Ekstrak Konten dari dokumen Word DOCX dengan Python

Ekstraksi teks dari dokumen Word sering dilakukan dalam berbagai skenario. Misalnya untuk menganalisis teks, mengekstrak bagian tertentu dari suatu dokumen dan menggabungkannya menjadi satu dokumen, dan sebagainya. Pada artikel ini, Anda akan belajar cara mengekstrak teks dari dokumen Word secara terprogram dengan Python. Selain itu, kami akan membahas cara mengekstraksi konten di antara elemen tertentu seperti paragraf, tabel, dll. Secara dinamis.

Pustaka Python untuk Mengekstrak Teks dari Dokumen Word

Aspose.Words for Python adalah perpustakaan yang kuat yang memungkinkan Anda membuat dokumen MS Word dari awal. Selain itu, ini memungkinkan Anda memanipulasi dokumen Word yang ada untuk enkripsi, konversi, ekstraksi teks, dll. Kami akan menggunakan pustaka ini untuk mengekstrak teks dari dokumen Word DOCX atau DOC. Anda dapat menginstal pustaka dari PyPI menggunakan perintah pip berikut.

pip install aspose-words

Ekstraksi Teks dalam Dokumen Word menggunakan Python

Dokumen MS Word terdiri dari berbagai elemen yang meliputi paragraf, tabel, gambar, dll. Oleh karena itu, persyaratan ekstraksi teks dapat bervariasi dari satu skenario ke skenario lainnya. Misalnya, Anda mungkin perlu mengekstrak teks di antara paragraf, bookmark, komentar, dll.

Setiap jenis elemen dalam dokumen Word direpresentasikan sebagai node. Oleh karena itu, untuk memproses dokumen, Anda harus bermain dengan node. Jadi mari kita mulai dan lihat cara mengekstrak teks dari dokumen Word dalam berbagai skenario.

Ekstrak Teks dari Dokumen Word dengan Python

Pada bagian ini, kita akan mengimplementasikan ekstraktor teks Python untuk dokumen Word dan alur kerja ekstraksi teks adalah sebagai berikut:

  • Pertama, kita akan menentukan node yang ingin kita sertakan dalam proses ekstraksi teks.
  • Kemudian, kami akan mengekstrak konten di antara node yang ditentukan (termasuk atau tidak termasuk node awal dan akhir).
  • Terakhir, kita akan menggunakan tiruan dari node yang diekstraksi, misalnya untuk membuat dokumen Word baru yang terdiri dari konten yang diekstraksi.

Sekarang mari kita tulis metode bernama extractcontent yang akan kita berikan node dan beberapa parameter lain untuk melakukan ekstraksi teks. Metode ini akan mengurai dokumen dan mengkloning node. Berikut ini adalah parameter yang akan kita berikan pada metode ini.

  1. StartNode dan EndNode masing-masing sebagai titik awal dan akhir untuk ekstraksi konten. Ini bisa berupa node level blok (Paragraph , Table) atau level inline (misalnya Run, FieldStart, BookmarkStart, dll.).
    1. Untuk melewati bidang, Anda harus meneruskan objek FieldStart yang sesuai.
    2. Untuk melewati bookmark, simpul BookmarkStart dan BookmarkEnd harus dilewati.
    3. Untuk komentar, node CommentRangeStart dan CommentRangeEnd harus digunakan.
  2. IsInclusive menentukan apakah penanda disertakan dalam ekstraksi atau tidak. Jika opsi ini disetel ke false dan node yang sama atau node berurutan dilewatkan, maka daftar kosong akan dikembalikan.

Berikut ini adalah implementasi lengkap dari metode extractcontent yang mengekstraksi konten antar node yang dilewati.

def extract_content(startNode : aw.Node, endNode : aw.Node, isInclusive : bool):
    
    # Pertama, periksa apakah node yang diteruskan ke metode ini valid untuk digunakan.
    verify_parameter_nodes(startNode, endNode)

    # Buat daftar untuk menyimpan node yang diekstrak.
    nodes = []

    # Jika salah satu penanda adalah bagian dari komentar, termasuk komentar itu sendiri, kita perlu memindahkan pointer
    # meneruskan ke Node Komentar yang ditemukan setelah node 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

    # Catat node asli yang diteruskan ke metode ini untuk membagi node penanda jika diperlukan.
    originalStartNode = startNode
    originalEndNode = endNode

    # Ekstrak konten berdasarkan node tingkat blok (paragraf dan tabel). Lintasi node induk untuk menemukannya.
    # Kami akan membagi konten node pertama dan terakhir, tergantung apakah node penanda inline.
    startNode = get_ancestor_in_body(startNode)
    endNode = get_ancestor_in_body(endNode)

    isExtracting = True
    isStartingNode = True
    # Node saat ini yang kami ekstrak dari dokumen.
    currNode = startNode

    # Mulailah mengekstraksi konten. Proses semua node tingkat blok dan secara khusus pisahkan yang pertama
    # dan simpul terakhir bila diperlukan, sehingga pemformatan paragraf dipertahankan.
    # Metodenya sedikit lebih rumit daripada ekstraktor biasa karena kita perlu memfaktorkan
    # dalam mengekstraksi menggunakan inline node, field, bookmark, dll agar bermanfaat.
    while (isExtracting) :
        
        # Klon node saat ini dan turunannya untuk mendapatkan salinannya.
        cloneNode = currNode.clone(True)
        isEndingNode = currNode == endNode

        if (isStartingNode or isEndingNode) :
            
            # Kita perlu memproses setiap penanda secara terpisah, jadi alihkan ke metode terpisah.
            # End harus diproses terlebih dahulu untuk menjaga indeks node.
            if (isEndingNode) :
                # !isStartingNode: jangan menambahkan simpul dua kali jika penandanya adalah simpul yang sama.
                process_marker(cloneNode, nodes, originalEndNode, currNode, isInclusive, False, not isStartingNode, False)
                isExtracting = False

            # Bersyarat harus dipisahkan sebagai penanda awal dan akhir level blok, mungkin node yang sama.
            if (isStartingNode) :
                process_marker(cloneNode, nodes, originalStartNode, currNode, isInclusive, True, True, False)
                isStartingNode = False
            
        else :
            # Node bukan penanda awal atau akhir, cukup tambahkan salinan ke daftar.
            nodes.append(cloneNode)

        # Pindah ke node berikutnya dan ekstrak. Jika simpul berikutnya adalah Tidak ada,
        # sisa konten ditemukan di bagian yang berbeda.
        if (currNode.next_sibling == None and isExtracting) :
            # Pindah ke bagian berikutnya.
            nextSection = currNode.get_ancestor(aw.NodeType.SECTION).next_sibling.as_section()
            currNode = nextSection.body.first_child
            
        else :
            # Pindah ke node berikutnya dalam tubuh.
            currNode = currNode.next_sibling
            
    # Untuk kompatibilitas dengan mode dengan bookmark sebaris, tambahkan paragraf berikutnya (kosong).
    if (isInclusive and originalEndNode == endNode and not originalEndNode.is_composite) :
        include_next_paragraph(endNode, nodes)

    # Kembalikan node di antara penanda node.
    return nodes

Beberapa metode pembantu juga diperlukan oleh metode extractcontent untuk menyelesaikan operasi ekstraksi teks, yang diberikan di bawah ini.

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

    # Urutan pemeriksaan ini dilakukan adalah penting.
    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")

    # Periksa simpul akhir setelah simpul awal di pohon DOM.
    # Pertama, periksa apakah mereka berada di bagian yang berbeda, lalu jika tidak,
    # periksa posisinya di badan bagian yang sama.
    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):

    # Menguji apakah simpul tersebut adalah turunan dari simpul Paragraf atau Tabel dan bukan merupakan paragraf
    # atau tabel paragraf di dalam kelas komentar yang layak untuk sebuah paragraf dimungkinkan.
    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):

    # Jika kita berurusan dengan node level blok, lihat apakah itu harus disertakan dan tambahkan ke daftar.
    if node == block_level_ancestor:
        if can_add and is_inclusive:
            nodes.append(clone_node)
        return

    # cloneNode adalah tiruan dari blockLevelNode. Jika node != blockLevelNode, blockLevelAncestor
    # adalah nenek moyang node yang berarti itu adalah node komposit.
    assert clone_node.is_composite

    # Jika marker adalah node FieldStart, periksa apakah akan disertakan atau tidak.
    # Kami berasumsi untuk penyederhanaan bahwa FieldStart dan FieldEnd muncul di paragraf yang sama.
    if node.node_type == aw.NodeType.FIELD_START:
        # Jika penanda adalah simpul awal dan tidak disertakan, lewati ke ujung bidang.
        # Jika penanda adalah simpul akhir dan akan disertakan, maka pindahkan ke bidang akhir sehingga bidang tidak akan dihapus.
        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

    # Dukung kasus jika simpul penanda berada di tingkat ketiga badan dokumen atau lebih rendah.
    node_branch = fill_self_and_parents(node, block_level_ancestor)

    # Proses node yang sesuai di node kloning kami berdasarkan indeks.
    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)

    # Setelah diproses, node komposit mungkin menjadi kosong jika tidak menyertakannya.
    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:

        # Pindah ke anak pertama untuk menyertakan paragraf tanpa konten.
        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()
    # Hapus paragraf pertama dari dokumen kosong.
    dst_doc.first_section.body.remove_all_children()

    # Impor setiap node dari daftar ke dalam dokumen baru. Pertahankan pemformatan asli dari node.
    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

Sekarang kami siap menggunakan metode ini dan mengekstrak teks dari dokumen Word.

Ekstrak Teks antar Paragraf dalam Dokumen Word

Mari kita lihat cara mengekstrak konten di antara dua paragraf dalam dokumen Word DOCX. Berikut ini adalah langkah-langkah untuk melakukan operasi ini dengan Python.

  • Pertama, muat dokumen Word menggunakan kelas Document.
  • Dapatkan referensi paragraf awal dan akhir menjadi dua objek menggunakan metode Document.firstsection.body.getchild(NodeType.PARAGRAPH, int, boolean).asparagraph() .
  • Panggil metode extractcontent(startPara, endPara, True) untuk mengekstrak node menjadi objek.
  • Panggil metode pembantu generatedocument(Document, extractNodes) untuk membuat dokumen yang terdiri dari konten yang diekstraksi.
  • Terakhir, simpan dokumen yang dikembalikan menggunakan metode Document.save(string).

Contoh kode berikut menunjukkan cara mengekstrak teks antara paragraf ke-7 dan ke-11 dalam dokumen Word dengan Python.

# Muat dokumen.
doc = aw.Document("Extract content.docx")

# Tentukan awal dan akhir paragraf.
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()

# Ekstrak konten di antara paragraf ini dalam dokumen. Sertakan penanda ini dalam ekstraksi.
extractedNodes = extract_content(startPara, endPara, True)

# Hasilkan dokumen yang berisi konten yang diekstraksi.
dstDoc = generate_document(doc, extractedNodes)

# Simpan dokumen.
dstDoc.save("extract_content_between_paragraphs.docx")

Ekstrak Teks antara Berbagai Jenis Node dalam Dokumen Word

Anda juga dapat mengekstraksi konten di antara berbagai jenis node. Untuk demonstrasi, mari ekstrak konten antara paragraf dan tabel dan simpan ke dalam dokumen Word baru. Berikut ini adalah langkah-langkah untuk melakukan operasi ini.

  • Muat dokumen Word menggunakan kelas Document.
  • Dapatkan referensi node awal dan akhir menjadi dua objek menggunakan metode Document.firstsection.body.getchild(NodeType, int, boolean).
  • Panggil metode extractcontent(startPara, endPara, True) untuk mengekstrak node menjadi objek.
  • Panggil metode pembantu generatedocument(Document, extractNodes) untuk membuat dokumen yang terdiri dari konten yang diekstraksi.
  • Simpan dokumen yang dikembalikan menggunakan metode Document.save(string).

Contoh kode berikut menunjukkan cara mengekstrak teks antara paragraf dan tabel dengan Python.

# Muat dokumen
doc = aw.Document("Extract content.docx")

# Tentukan node awal dan akhir.
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()

# Ekstrak konten di antara simpul-simpul ini dalam dokumen. Sertakan penanda ini dalam ekstraksi.
extracted_nodes = extract_content(start_para, end_table, True)

# Hasilkan dokumen yang berisi konten yang diekstrak.
dstDoc = generate_document(doc, extractedNodes)

# Simpan dokumen.
dstDoc.save("extract_content_between_nodes.docx")

Ekstrak Teks antar Paragraf berdasarkan Gaya

Sekarang mari kita lihat cara mengekstrak konten antar paragraf berdasarkan gaya. Untuk demonstrasi, kita akan mengekstrak konten antara “Heading 1” pertama dan “Heading 3” pertama dalam dokumen Word. Langkah-langkah berikut menunjukkan cara mencapainya dengan Python.

  • Pertama, muat dokumen Word menggunakan kelas Document.
  • Kemudian, ekstrak paragraf menjadi objek menggunakan metode pembantuparagraphsbystylename(Document, “Heading 1”).
  • Ekstrak paragraf ke objek lain menggunakan metode pembantuparagraphsbystylename(Document, “Heading 3”).
  • Panggil metode extractcontent(startPara, endPara, True) dan teruskan elemen pertama di kedua larik paragraf sebagai parameter pertama dan kedua.
  • Panggil metode pembantu generatedocument(Document, extractNodes) untuk membuat dokumen yang terdiri dari konten yang diekstraksi.
  • Terakhir, simpan dokumen yang dikembalikan menggunakan metode Document.save(string).

Contoh kode berikut menunjukkan cara mengekstrak konten antar paragraf berdasarkan gaya.

# Muat dokumen
doc = aw.Document("Extract content.docx")

# Kumpulkan daftar paragraf menggunakan gaya tajuk masing-masing.
parasStyleHeading1 = paragraphs_by_style_name(doc, "Heading 1")
parasStyleHeading3 = paragraphs_by_style_name(doc, "Heading 3")

# Gunakan contoh paragraf pertama dengan gaya tersebut.
startPara1 = parasStyleHeading1[0]
endPara1 = parasStyleHeading3[0]

# Ekstrak konten di antara simpul-simpul ini dalam dokumen. Jangan sertakan penanda ini dalam ekstraksi.
extractedNodes = extract_content(startPara1, endPara1, False)

# Hasilkan dokumen yang berisi konten yang diekstrak.
dstDoc = generate_document(doc, extractedNodes)

# Simpan dokumen.
dstDoc.save("extract_content_between_paragraphs_based_on-Styles.docx")

Baca selengkapnya

Anda dapat menjelajahi skenario lain untuk mengekstraksi teks dari dokumen Word menggunakan artikel dokumentasi ini.

Dapatkan Lisensi API Gratis

Anda bisa mendapatkan lisensi sementara untuk menggunakan Aspose.Words for Python tanpa batasan evaluasi.

Kesimpulan

Pada artikel ini, Anda telah mempelajari cara mengekstrak teks dari dokumen MS Word menggunakan Python. Selain itu, Anda telah melihat cara mengekstraksi konten antara jenis node yang serupa atau berbeda dalam dokumen Word secara terprogram. Dengan demikian, Anda dapat membuat ekstraktor teks MS Word Anda sendiri dengan Python. Selain itu, Anda dapat menjelajahi fitur lain dari Aspose.Words for Python menggunakan dokumentasi. Jika Anda memiliki pertanyaan, jangan ragu untuk memberi tahu kami melalui forum kami.

Lihat juga

Info: Jika Anda perlu mendapatkan dokumen Word dari presentasi PowerPoint, Anda dapat menggunakan pengonversi Aspose Presentation to Word Document.