استخراج المحتوى من مستندات Word DOCX في Python

غالبًا ما يتم إجراء استخراج النص من مستندات Word في سيناريوهات مختلفة. على سبيل المثال ، لتحليل النص ، لاستخراج أقسام معينة من المستند ودمجها في مستند واحد ، وهكذا. في هذه المقالة ، ستتعلم كيفية استخراج نص من مستندات Word برمجيًا في Python. علاوة على ذلك ، سوف نتناول كيفية استخراج المحتوى بين عناصر محددة مثل الفقرات والجداول وما إلى ذلك بشكل ديناميكي.

مكتبة Python لاستخراج نص من مستندات Word

Aspose.Words for Python هي مكتبة قوية تسمح لك بإنشاء مستندات MS Word من البداية. علاوة على ذلك ، فإنه يتيح لك معالجة مستندات Word الحالية للتشفير والتحويل واستخراج النص وما إلى ذلك. سنستخدم هذه المكتبة لاستخراج النص من مستندات Word DOCX أو DOC. يمكنك تثبيت المكتبة من PyPI باستخدام أمر pip التالي.

pip install aspose-words

استخراج النص في مستندات Word باستخدام Python

يتكون مستند MS Word من عناصر مختلفة تشمل فقرات وجداول وصور وما إلى ذلك. لذلك ، يمكن أن تختلف متطلبات استخراج النص من سيناريو إلى آخر. على سبيل المثال ، قد تحتاج إلى استخراج نص بين الفقرات والإشارات المرجعية والتعليقات وما إلى ذلك.

يتم تمثيل كل نوع من العناصر في مستند Word كعقدة. لذلك ، لمعالجة مستند ، سيتعين عليك اللعب بالعقد. لذلك دعونا نبدأ ونرى كيفية استخراج النص من مستندات Word في سيناريوهات مختلفة.

استخراج نص من مستند Word في Python

في هذا القسم ، سنقوم بتنفيذ مستخرج نص Python لمستندات Word وسيكون سير العمل لاستخراج النص كما يلي:

  • أولاً ، سنحدد العقد التي نريد تضمينها في عملية استخراج النص.
  • بعد ذلك ، سنقوم باستخراج المحتوى بين العقد المحددة (بما في ذلك أو استبعاد عقد البداية والنهاية).
  • أخيرًا ، سنستخدم استنساخ العقد المستخرجة ، على سبيل المثال لإنشاء مستند Word جديد يتكون من محتوى مستخرج.

لنكتب الآن طريقة باسم extractcontent سنمرر إليها العقد وبعض المعلمات الأخرى لإجراء استخراج النص. ستعمل هذه الطريقة على تحليل المستند واستنساخ العقد. فيما يلي المعلمات التي سنمررها إلى هذه الطريقة.

  1. StartNode و EndNode كنقطتي بداية ونهاية لاستخراج المحتوى ، على التوالي. يمكن أن تكون هذه العقد على مستوى الكتلة (فقرة ، جدول) أو مستوى مضمن (على سبيل المثال ، Run ، FieldStart ، BookmarkStart وما إلى ذلك).
    1. لتمرير حقل ، يجب عليك تمرير كائن FieldStart المقابل.
    2. لتمرير الإشارات المرجعية ، يجب تمرير عقد BookmarkStart و BookmarkEnd.
    3. للتعليقات ، يجب استخدام عقدتي CommentRangeStart و CommentRangeEnd.
  2. يحدد IsInclusive ما إذا كانت العلامات مضمنة في الاستخراج أم لا. إذا تم تعيين هذا الخيار على false وتم تمرير نفس العقدة أو العقد المتتالية ، فسيتم إرجاع قائمة فارغة.

فيما يلي التنفيذ الكامل لطريقة extractcontent التي تستخرج المحتوى بين العقد التي تم تمريرها.

def extract_content(startNode : aw.Node, endNode : aw.Node, isInclusive : bool):
    
    # أولاً ، تحقق من أن العقد التي تم تمريرها إلى هذه الطريقة صالحة للاستخدام.
    verify_parameter_nodes(startNode, endNode)

    # قم بإنشاء قائمة لتخزين العقد المستخرجة.
    nodes = []

    # إذا كانت أي من العلامات جزءًا من تعليق ، بما في ذلك التعليق نفسه ، فنحن بحاجة إلى تحريك المؤشر
    # أعد توجيهها إلى عقدة التعليق التي تم العثور عليها بعد عقدة CommentRangeEnd.
    if (endNode.node_type == aw.NodeType.COMMENT_RANGE_END and isInclusive) :
        
        node = find_next_node(aw.NodeType.COMMENT, endNode.next_sibling)
        if (node != None) :
            endNode = node

    # احتفظ بسجل للعقد الأصلية التي تم تمريرها إلى هذه الطريقة لتقسيم عقد التحديد إذا لزم الأمر.
    originalStartNode = startNode
    originalEndNode = endNode

    # استخراج المحتوى على أساس العقد على مستوى الكتلة (الفقرات والجداول).اجتياز العقد الأصلية للعثور عليها.
    # سنقسم محتوى العقد الأولى والأخيرة ، اعتمادًا على ما إذا كانت عُقد التحديد مضمّنة.
    startNode = get_ancestor_in_body(startNode)
    endNode = get_ancestor_in_body(endNode)

    isExtracting = True
    isStartingNode = True
    # العقدة الحالية التي نستخرجها من المستند.
    currNode = startNode

    # ابدأ في استخراج المحتوى. قم بمعالجة جميع العقد على مستوى الكتلة وقسم الأولى على وجه التحديد
    # والعقد الأخيرة عند الحاجة ، لذلك يتم الاحتفاظ بتنسيق الفقرة.
    # الطريقة أكثر تعقيدًا من المستخرج العادي حيث نحتاج إلى التحليل
    # في الاستخراج باستخدام العقد المضمنة والحقول والإشارات المرجعية وما إلى ذلك لجعلها مفيدة.
    while (isExtracting) :
        
        # استنساخ العقدة الحالية وتوابعها للحصول على نسخة.
        cloneNode = currNode.clone(True)
        isEndingNode = currNode == endNode

        if (isStartingNode or isEndingNode) :
            
            # نحتاج إلى معالجة كل علامة على حدة ، لذا قم بتمريرها إلى طريقة منفصلة بدلاً من ذلك.
            # يجب معالجة النهاية في البداية للاحتفاظ بفهارس العقدة.
            if (isEndingNode) :
                # ! isStartingNode: لا تقم بإضافة العقدة مرتين إذا كانت العلامات هي نفس العقدة.
                process_marker(cloneNode, nodes, originalEndNode, currNode, isInclusive, False, not isStartingNode, False)
                isExtracting = False

            # يجب أن يكون الشرطي منفصلاً مثل علامات بداية ونهاية مستوى الكتلة ، وربما نفس العقدة.
            if (isStartingNode) :
                process_marker(cloneNode, nodes, originalStartNode, currNode, isInclusive, True, True, False)
                isStartingNode = False
            
        else :
            # العقدة ليست علامة بداية أو نهاية ، ما عليك سوى إضافة النسخة إلى القائمة.
            nodes.append(cloneNode)

        # انتقل إلى العقدة التالية واستخرجها. إذا كانت العقدة التالية لا شيء ،
        # تم العثور على بقية المحتوى في قسم مختلف.
        if (currNode.next_sibling == None and isExtracting) :
            # انتقل إلى القسم التالي.
            nextSection = currNode.get_ancestor(aw.NodeType.SECTION).next_sibling.as_section()
            currNode = nextSection.body.first_child
            
        else :
            # انتقل إلى العقدة التالية في الجسم.
            currNode = currNode.next_sibling
            
    # للتوافق مع الوضع مع الإشارات المرجعية المضمنة ، أضف الفقرة التالية (فارغة).
    if (isInclusive and originalEndNode == endNode and not originalEndNode.is_composite) :
        include_next_paragraph(endNode, nodes)

    # أعد العقد بين علامات العقدة.
    return nodes

بعض الطرق المساعدة مطلوبة أيضًا من خلال طريقة extractcontent لإنجاز عملية استخراج النص ، والتي ترد أدناه.

def verify_parameter_nodes(start_node: aw.Node, end_node: aw.Node):

    # الترتيب الذي تتم به هذه الفحوصات مهم.
    if start_node is None:
        raise ValueError("Start node cannot be None")
    if end_node is None:
        raise ValueError("End node cannot be None")

    if start_node.document != end_node.document:
        raise ValueError("Start node and end node must belong to the same document")

    if start_node.get_ancestor(aw.NodeType.BODY) is None or end_node.get_ancestor(aw.NodeType.BODY) is None:
        raise ValueError("Start node and end node must be a child or descendant of a body")

    # تحقق من أن عقدة النهاية بعد عقدة البداية في شجرة DOM.
    # أولاً ، تحقق مما إذا كانوا في أقسام مختلفة ، ثم إذا لم يكونوا كذلك ،
    # تحقق من موقعهم في الجسم من نفس القسم.
    start_section = start_node.get_ancestor(aw.NodeType.SECTION).as_section()
    end_section = end_node.get_ancestor(aw.NodeType.SECTION).as_section()

    start_index = start_section.parent_node.index_of(start_section)
    end_index = end_section.parent_node.index_of(end_section)

    if start_index == end_index:

        if (start_section.body.index_of(get_ancestor_in_body(start_node)) >
            end_section.body.index_of(get_ancestor_in_body(end_node))):
            raise ValueError("The end node must be after the start node in the body")

    elif start_index > end_index:
        raise ValueError("The section of end node must be after the section start node")

 
def find_next_node(node_type: aw.NodeType, from_node: aw.Node):

    if from_node is None or from_node.node_type == node_type:
        return from_node

    if from_node.is_composite:

        node = find_next_node(node_type, from_node.as_composite_node().first_child)
        if node is not None:
            return node

    return find_next_node(node_type, from_node.next_sibling)

 
def is_inline(node: aw.Node):

    # اختبر ما إذا كانت العقدة تابعة لفقرة أو عقدة جدول وليست فقرة
    # أو جدول فقرة داخل فئة تعليق مناسبة للفقرة ممكن.
    return ((node.get_ancestor(aw.NodeType.PARAGRAPH) is not None or node.get_ancestor(aw.NodeType.TABLE) is not None) and
            not (node.node_type == aw.NodeType.PARAGRAPH or node.node_type == aw.NodeType.TABLE))

 
def process_marker(clone_node: aw.Node, nodes, node: aw.Node, block_level_ancestor: aw.Node,
    is_inclusive: bool, is_start_marker: bool, can_add: bool, force_add: bool):

    # إذا كنا نتعامل مع عقدة على مستوى الكتلة ، فراجع ما إذا كان يجب تضمينها وإضافتها إلى القائمة.
    if node == block_level_ancestor:
        if can_add and is_inclusive:
            nodes.append(clone_node)
        return

    # cloneNode هو استنساخ blockLevelNode. إذا كانت العقدة! = blockLevelNode ، blockLevelAncestor
    # هي سلف العقدة مما يعني أنها عقدة مركبة.
    assert clone_node.is_composite

    # إذا كانت العلامة عبارة عن عقدة FieldStart ، تحقق مما إذا كان سيتم تضمينها أم لا.
    # نفترض من أجل البساطة أن يظهر FieldStart و FieldEnd في نفس الفقرة.
    if node.node_type == aw.NodeType.FIELD_START:
        # إذا كانت العلامة عبارة عن عقدة بداية ولم يتم تضمينها ، فانتقل إلى نهاية الحقل.
        # إذا كانت العلامة عبارة عن عقدة نهاية ويجب تضمينها ، فانتقل إلى حقل النهاية حتى لا تتم إزالة الحقل.
        if is_start_marker and not is_inclusive or not is_start_marker and is_inclusive:
            while node.next_sibling is not None and node.node_type != aw.NodeType.FIELD_END:
                node = node.next_sibling

    # دعم حالة إذا كانت عقدة العلامة على المستوى الثالث من نص المستند أو أقل.
    node_branch = fill_self_and_parents(node, block_level_ancestor)

    # قم بمعالجة العقدة المقابلة في العقدة المستنسخة بواسطة الفهرس.
    current_clone_node = clone_node
   for i in range(len(node_branch) - 1, -1):

        current_node = node_branch[i]
        node_index = current_node.parent_node.index_of(current_node)
        current_clone_node = current_clone_node.as_composite_node.child_nodes[node_index]

        remove_nodes_outside_of_range(current_clone_node, is_inclusive or (i > 0), is_start_marker)

    # بعد المعالجة ، قد تصبح العقدة المركبة فارغة إذا لم تتضمنها.
    if can_add and (force_add or clone_node.as_composite_node().has_child_nodes):
        nodes.append(clone_node)

 
def remove_nodes_outside_of_range(marker_node: aw.Node, is_inclusive: bool, is_start_marker: bool):

    is_processing = True
    is_removing = is_start_marker
    next_node = marker_node.parent_node.first_child

    while is_processing and next_node is not None:

        current_node = next_node
        is_skip = False

        if current_node == marker_node:
            if is_start_marker:
                is_processing = False
                if is_inclusive:
                    is_removing = False
            else:
                is_removing = True
                if is_inclusive:
                    is_skip = True

        next_node = next_node.next_sibling
        if is_removing and not is_skip:
            current_node.remove()

 
def fill_self_and_parents(node: aw.Node, till_node: aw.Node):

    nodes = []
    current_node = node

    while current_node != till_node:
        nodes.append(current_node)
        current_node = current_node.parent_node

    return nodes

 
def include_next_paragraph(node: aw.Node, nodes):

    paragraph = find_next_node(aw.NodeType.PARAGRAPH, node.next_sibling).as_paragraph()
    if paragraph is not None:

        # انتقل إلى الطفل الأول لتضمين فقرات بدون محتوى.
        marker_node = paragraph.first_child if paragraph.has_child_nodes else paragraph
        root_node = get_ancestor_in_body(paragraph)

        process_marker(root_node.clone(True), nodes, marker_node, root_node,
            marker_node == paragraph, False, True, True)

 
def get_ancestor_in_body(start_node: aw.Node):

    while start_node.parent_node.node_type != aw.NodeType.BODY:
        start_node = start_node.parent_node
    return start_node
def generate_document(src_doc: aw.Document, nodes):

    dst_doc = aw.Document()
    # أزل الفقرة الأولى من المستند الفارغ.
    dst_doc.first_section.body.remove_all_children()

    # قم باستيراد كل عقدة من القائمة إلى المستند الجديد. احتفظ بالتنسيق الأصلي للعقدة.
    importer = aw.NodeImporter(src_doc, dst_doc, aw.ImportFormatMode.KEEP_SOURCE_FORMATTING)

   for node in nodes:
        import_node = importer.import_node(node, True)
        dst_doc.first_section.body.append_child(import_node)

    return dst_doc

 
def paragraphs_by_style_name(doc: aw.Document, style_name: str):

    paragraphs_with_style = []
    paragraphs = doc.get_child_nodes(aw.NodeType.PARAGRAPH, True)

   for paragraph in paragraphs:
        paragraph = paragraph.as_paragraph()
        if paragraph.paragraph_format.style.name == style_name:
            paragraphs_with_style.append(paragraph)

    return paragraphs_with_style

نحن الآن جاهزون لاستخدام هذه الأساليب واستخراج النص من مستند Word.

استخراج نص بين الفقرات في مستند Word

دعونا نرى كيفية استخراج المحتوى بين فقرتين في مستند Word DOCX. فيما يلي خطوات إجراء هذه العملية في Python.

  • أولاً ، قم بتحميل مستند Word باستخدام فئة المستند.
  • احصل على مرجع لفقرات البداية والنهاية في كائنين باستخدام طريقة Document.firstsection.body.getchild (NodeType.PARAGRAPH، int، boolean) .asparagraph().
  • استدعاء طريقة extractcontent (startPara ، endPara ، True) لاستخراج العقد في كائن.
  • الاستدعاء الذي تم إنشاؤه للمستند (Document ، extractedNodes) هو الأسلوب المساعد لإنشاء مستند يتكون من المحتوى المستخرج.
  • أخيرًا ، احفظ المستند المرتجع باستخدام طريقة Document.save(string).

يوضح نموذج التعليمات البرمجية التالي كيفية استخراج النص بين الفقرتين السابعة والحادية عشرة في مستند Word في Python.

# تحميل المستند.
doc = aw.Document("Extract content.docx")

# تحديد بداية ونهاية فقرات.
startPara = doc.first_section.body.get_child(aw.NodeType.PARAGRAPH, 6, True).as_paragraph()
endPara = doc.first_section.body.get_child(aw.NodeType.PARAGRAPH, 10, True).as_paragraph()

# استخرج المحتوى بين هذه الفقرات في الوثيقة. قم بتضمين هذه العلامات في الاستخراج.
extractedNodes = extract_content(startPara, endPara, True)

# إنشاء مستند يحتوي على محتوى مستخرج.
dstDoc = generate_document(doc, extractedNodes)

# احفظ المستند.
dstDoc.save("extract_content_between_paragraphs.docx")

استخراج النص بين أنواع العقد المختلفة في مستند Word

يمكنك أيضًا استخراج المحتوى بين أنواع العقد المختلفة. للتوضيح ، دعنا نستخرج المحتوى بين فقرة وجدول ونحفظه في مستند Word جديد. فيما يلي خطوات إجراء هذه العملية.

  • قم بتحميل مستند Word باستخدام فئة المستند.
  • احصل على مرجع لعقدتي البداية والنهاية في كائنين باستخدام طريقة Document.firstsection.body.getchild (NodeType، int، boolean).
  • استدعاء طريقة extractcontent (startPara ، endPara ، True) لاستخراج العقد في كائن.
  • الاستدعاء الذي تم إنشاؤه للمستند (Document ، extractedNodes) هو الأسلوب المساعد لإنشاء مستند يتكون من المحتوى المستخرج.
  • احفظ المستند الذي تم إرجاعه باستخدام طريقة Document.save(string).

يوضح نموذج التعليمات البرمجية التالي كيفية استخراج نص بين فقرة وجدول في Python.

# تحميل المستند
doc = aw.Document("Extract content.docx")

# تحديد عقد البداية والنهاية.
start_para = doc.last_section.get_child(aw.NodeType.PARAGRAPH, 2, True).as_paragraph()
end_table = doc.last_section.get_child(aw.NodeType.TABLE, 0, True).as_table()

# استخرج المحتوى بين هذه العقد في المستند. قم بتضمين هذه العلامات في الاستخراج.
extracted_nodes = extract_content(start_para, end_table, True)

# إنشاء مستند يحتوي على محتوى مستخرج.
dstDoc = generate_document(doc, extractedNodes)

# احفظ المستند.
dstDoc.save("extract_content_between_nodes.docx")

استخراج النص بين الفقرات بناءً على الأنماط

دعنا الآن نتحقق من كيفية استخراج المحتوى بين الفقرات بناءً على الأنماط. للتوضيح ، سنقوم باستخراج المحتوى بين “العنوان 1” الأول و “العنوان 3” الأول في مستند Word. توضح الخطوات التالية كيفية تحقيق ذلك في بايثون.

  • أولاً ، قم بتحميل مستند Word باستخدام فئة المستند.
  • بعد ذلك ، استخرج فقرات في كائن باستخدام أسلوب مساعد paragraphbystylename (المستند ، “العنوان 1”).
  • استخراج فقرات إلى كائن آخر باستخدام أسلوب المساعد paragraphbystylename (المستند ، “العنوان 3”).
  • استدعاء طريقة extractcontent (startPara ، endPara ، True) وتمرير العناصر الأولى في كل من مصفوفات الفقرة كمعامل أول وثاني.
  • الاستدعاء الذي تم إنشاؤه للمستند (Document ، extractedNodes) هو الأسلوب المساعد لإنشاء مستند يتكون من المحتوى المستخرج.
  • أخيرًا ، احفظ المستند المرتجع باستخدام طريقة Document.save(string).

يوضح نموذج التعليمات البرمجية التالي كيفية استخراج المحتوى بين الفقرات بناءً على الأنماط.

# تحميل المستند
doc = aw.Document("Extract content.docx")

# قم بتجميع قائمة بالفقرات باستخدام أنماط العناوين الخاصة بها.
parasStyleHeading1 = paragraphs_by_style_name(doc, "Heading 1")
parasStyleHeading3 = paragraphs_by_style_name(doc, "Heading 3")

# استخدم المثيل الأول للفقرات بهذه الأنماط.
startPara1 = parasStyleHeading1[0]
endPara1 = parasStyleHeading3[0]

# استخرج المحتوى بين هذه العقد في المستند. لا تقم بتضمين هذه العلامات في الاستخراج.
extractedNodes = extract_content(startPara1, endPara1, False)

# إنشاء مستند يحتوي على محتوى مستخرج.
dstDoc = generate_document(doc, extractedNodes)

# احفظ المستند.
dstDoc.save("extract_content_between_paragraphs_based_on-Styles.docx")

اقرأ أكثر

يمكنك استكشاف سيناريوهات أخرى لاستخراج النص من مستندات Word باستخدام مقالة التوثيق هذه.

احصل على ترخيص API مجاني

يمكنك الحصول على ترخيص مؤقت لاستخدام Aspose.Words مع Python بدون قيود تقييم.

استنتاج

في هذه المقالة ، تعلمت كيفية استخراج نص من مستندات MS Word باستخدام Python. علاوة على ذلك ، لقد رأيت كيفية استخراج المحتوى بين أنواع متشابهة أو مختلفة من العقد في مستند Word برمجيًا. وبالتالي ، يمكنك إنشاء مستخرج نصوص MS Word خاص بك في Python. بالإضافة إلى ذلك ، يمكنك استكشاف ميزات أخرى لـ Aspose.Words لبايثون باستخدام التوثيق. في حال كان لديك أي أسئلة ، لا تتردد في إخبارنا عبر المنتدى.

أنظر أيضا

معلومات: إذا احتجت في أي وقت إلى الحصول على مستند Word من عرض تقديمي لـ PowerPoint ، فيمكنك استخدام محول Aspose Presentation to Word Document.