Wyodrębnianie tekstu z dokumentów programu Word jest często wykonywane w różnych scenariuszach. Na przykład, aby przeanalizować tekst, wyodrębnić określone sekcje dokumentu i połączyć je w jeden dokument i tak dalej. W tym artykule dowiesz się, jak programowo wyodrębnić tekst z dokumentów Worda w Python. Ponadto omówimy, jak dynamicznie wyodrębniać zawartość między określonymi elementami, takimi jak akapity, tabele itp.
- Biblioteka Python do wyodrębniania tekstu z dokumentów Worda
- Ekstrakcja tekstu w dokumentach Word
- Wyodrębnij tekst z dokumentu programu Word
Biblioteka Python do wyodrębniania tekstu z dokumentów Worda
Aspose.Words for Python to potężna biblioteka, która pozwala tworzyć od podstaw dokumenty MS Word. Ponadto pozwala manipulować istniejącymi dokumentami Word w celu szyfrowania, konwersji, ekstrakcji tekstu itp. Użyjemy tej biblioteki do wyodrębnienia tekstu z dokumentów Word DOCX lub DOC. Możesz zainstalować bibliotekę z PyPI za pomocą następującego polecenia pip.
pip install aspose-words
Ekstrakcja tekstu w dokumentach programu Word przy użyciu języka Python
Dokument MS Word składa się z różnych elementów, takich jak akapity, tabele, obrazy itp. Dlatego wymagania dotyczące ekstrakcji tekstu mogą się różnić w zależności od scenariusza. Na przykład może być konieczne wyodrębnienie tekstu między akapitami, zakładkami, komentarzami itp.
Każdy typ elementu w dokumencie programu Word jest reprezentowany jako węzeł. Dlatego, aby przetworzyć dokument, będziesz musiał bawić się węzłami. Zacznijmy więc i zobaczmy, jak wyodrębnić tekst z dokumentów programu Word w różnych scenariuszach.
Wyodrębnij tekst z dokumentu programu Word w Python
W tej sekcji zamierzamy zaimplementować ekstraktor tekstu w języku Python dla dokumentów programu Word, a przepływ pracy podczas wyodrębniania tekstu wyglądałby następująco:
- Najpierw zdefiniujemy węzły, które chcemy uwzględnić w procesie ekstrakcji tekstu.
- Następnie wyodrębnimy zawartość między określonymi węzłami (w tym lub z wyłączeniem węzłów początkowych i końcowych).
- Na koniec wykorzystamy klon wyodrębnionych węzłów np. do stworzenia nowego dokumentu Worda składającego się z wyodrębnionej treści.
Napiszmy teraz metodę o nazwie extractcontent, do której przekażemy węzły i kilka innych parametrów w celu przeprowadzenia ekstrakcji tekstu. Ta metoda przeanalizuje dokument i sklonuje węzły. Poniżej przedstawiono parametry, które przekażemy tej metodzie.
- StartNode i EndNode odpowiednio jako punkty początkowe i końcowe wyodrębniania zawartości. Mogą to być zarówno węzły na poziomie bloku (Akapit , Tabela), jak i na poziomie wiersza (np. Run, FieldStart, BookmarkStart itp.).
- Aby przekazać pole, należy przekazać odpowiedni obiekt FieldStart.
- Aby przekazać zakładki, należy przekazać węzły BookmarkStart i BookmarkEnd.
- W przypadku komentarzy należy używać węzłów CommentRangeStart i CommentRangeEnd.
- IsInclusive określa, czy znaczniki są uwzględniane w ekstrakcji, czy nie. Jeśli ta opcja jest ustawiona na false i zostanie przekazany ten sam węzeł lub kolejne węzły, zwrócona zostanie pusta lista.
Poniżej przedstawiono kompletną implementację metody extractcontent, która wyodrębnia zawartość między przekazywanymi węzłami.
def extract_content(startNode : aw.Node, endNode : aw.Node, isInclusive : bool):
# Najpierw sprawdź, czy węzły przekazane do tej metody są prawidłowe do użycia.
verify_parameter_nodes(startNode, endNode)
# Utwórz listę do przechowywania wyodrębnionych węzłów.
nodes = []
# Jeśli któryś ze znaczników jest częścią komentarza, w tym samego komentarza, musimy przesunąć wskaźnik
# do węzła Comment znajdującego się za węzłem 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
# Zachowaj zapis oryginalnych węzłów przekazanych do tej metody, aby w razie potrzeby podzielić węzły znaczników.
originalStartNode = startNode
originalEndNode = endNode
# Wyodrębnij zawartość na podstawie węzłów na poziomie bloku (akapity i tabele). Przechodź przez węzły nadrzędne, aby je znaleźć.
# Podzielimy zawartość pierwszego i ostatniego węzła, w zależności od tego, czy węzły znaczników są wbudowane.
startNode = get_ancestor_in_body(startNode)
endNode = get_ancestor_in_body(endNode)
isExtracting = True
isStartingNode = True
# Bieżący węzeł, który wyodrębniamy z dokumentu.
currNode = startNode
# Rozpocznij wyodrębnianie zawartości. Przetwarzaj wszystkie węzły na poziomie bloku i konkretnie podziel pierwszy
# i ostatnie węzły w razie potrzeby, dzięki czemu formatowanie akapitu zostaje zachowane.
# Metoda jest nieco bardziej skomplikowana niż zwykły ekstraktor, ponieważ musimy to uwzględnić
# w wyodrębnianiu za pomocą wbudowanych węzłów, pól, zakładek itp., aby było to przydatne.
while (isExtracting) :
# Sklonuj bieżący węzeł i jego elementy podrzędne, aby uzyskać kopię.
cloneNode = currNode.clone(True)
isEndingNode = currNode == endNode
if (isStartingNode or isEndingNode) :
# Musimy przetworzyć każdy znacznik osobno, więc zamiast tego przekaż go osobnej metodzie.
# Koniec powinien zostać przetworzony jako pierwszy, aby zachować indeksy węzłów.
if (isEndingNode) :
# !isStartingNode: nie dodawaj węzła dwa razy, jeśli znaczniki są tym samym węzłem.
process_marker(cloneNode, nodes, originalEndNode, currNode, isInclusive, False, not isStartingNode, False)
isExtracting = False
# Warunek musi być oddzielny, ponieważ znaczniki początku i końca na poziomie bloku, być może ten sam węzeł.
if (isStartingNode) :
process_marker(cloneNode, nodes, originalStartNode, currNode, isInclusive, True, True, False)
isStartingNode = False
else :
# Węzeł nie jest znacznikiem początkowym ani końcowym, po prostu dodaj kopię do listy.
nodes.append(cloneNode)
# Przejdź do następnego węzła i wyodrębnij go. Jeśli następnym węzłem jest Brak,
# reszta treści znajduje się w innej sekcji.
if (currNode.next_sibling == None and isExtracting) :
# Przejdź do następnej sekcji.
nextSection = currNode.get_ancestor(aw.NodeType.SECTION).next_sibling.as_section()
currNode = nextSection.body.first_child
else :
# Przejdź do następnego węzła w ciele.
currNode = currNode.next_sibling
# Aby zapewnić zgodność z trybem z wbudowanymi zakładkami, dodaj następny akapit (pusty).
if (isInclusive and originalEndNode == endNode and not originalEndNode.is_composite) :
include_next_paragraph(endNode, nodes)
# Zwróć węzły między znacznikami węzłów.
return nodes
Niektóre metody pomocnicze są również wymagane przez metodę extractcontent do wykonania operacji wyodrębniania tekstu, które podano poniżej.
def verify_parameter_nodes(start_node: aw.Node, end_node: aw.Node):
# Kolejność przeprowadzania tych kontroli jest ważna.
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")
# Sprawdź, czy węzeł końcowy znajduje się za węzłem początkowym w drzewie DOM.
# Najpierw sprawdź, czy są w różnych sekcjach, a jeśli nie,
# sprawdzić ich położenie w treści tej samej sekcji.
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):
# Sprawdź, czy węzeł jest potomkiem węzła akapitu lub tabeli i czy nie jest akapitem
# lub tabela akapit wewnątrz klasy komentarza, która jest przyzwoita w akapicie, jest możliwa.
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):
# Jeśli mamy do czynienia z węzłem na poziomie bloku, sprawdź, czy powinien zostać uwzględniony i dodaj go do listy.
if node == block_level_ancestor:
if can_add and is_inclusive:
nodes.append(clone_node)
return
# cloneNode jest klonem blockLevelNode. Jeśli węzeł != blockLevelNode, blockLevelAncestor
# jest przodkiem węzła, co oznacza, że jest to węzeł złożony.
assert clone_node.is_composite
# Jeśli znacznik jest węzłem FieldStart, sprawdź, czy ma być uwzględniony, czy nie.
# Dla uproszczenia zakładamy, że FieldStart i FieldEnd pojawiają się w tym samym akapicie.
if node.node_type == aw.NodeType.FIELD_START:
# Jeśli znacznik jest węzłem początkowym i nie jest uwzględniony, przejdź do końca pola.
# Jeśli znacznik jest węzłem końcowym i ma być uwzględniony, należy przejść do pola końcowego, aby pole nie zostało usunięte.
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
# Obsługuje przypadek, gdy węzeł znacznika znajduje się na trzecim lub niższym poziomie treści dokumentu.
node_branch = fill_self_and_parents(node, block_level_ancestor)
# Przetwórz odpowiedni węzeł w naszym sklonowanym węźle według indeksu.
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)
# Po przetworzeniu węzeł złożony może stać się pusty, jeśli go nie zawiera.
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:
# Przejdź do pierwszego elementu podrzędnego, aby uwzględnić akapity bez treści.
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()
# Usuń pierwszy akapit z pustego dokumentu.
dst_doc.first_section.body.remove_all_children()
# Zaimportuj każdy węzeł z listy do nowego dokumentu. Zachowaj oryginalne formatowanie węzła.
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
Teraz jesteśmy gotowi do wykorzystania tych metod i wyodrębnienia tekstu z dokumentu Word.
Wyodrębnij tekst między akapitami w dokumencie programu Word
Zobaczmy, jak wyodrębnić zawartość między dwoma akapitami w dokumencie Word DOCX. Poniżej przedstawiono kroki, aby wykonać tę operację w języku Python.
- Najpierw załaduj dokument programu Word przy użyciu klasy Document.
- Uzyskaj odwołanie do akapitu początkowego i końcowego do dwóch obiektów za pomocą metody Document.firstsection.body.getchild(NodeType.PARAGRAPH, int, boolean).asparagraph() .
- Wywołaj metodę extractcontent(startPara, endPara, True), aby wyodrębnić węzły do obiektu.
- Wywołaj metodę pomocnika generowaneocument(Document, extractedNodes), aby utworzyć dokument składający się z wyodrębnionej zawartości.
- Na koniec zapisz zwrócony dokument przy użyciu metody Document.save(string).
Poniższy przykładowy kod pokazuje, jak wyodrębnić tekst między 7. a 11. akapitem w dokumencie programu Word w języku Python.
# Załaduj dokument.
doc = aw.Document("Extract content.docx")
# Zdefiniuj początkowe i końcowe akapity.
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()
# Wyodrębnij zawartość między tymi akapitami w dokumencie. Uwzględnij te znaczniki w ekstrakcji.
extractedNodes = extract_content(startPara, endPara, True)
# Wygeneruj dokument zawierający wyodrębnioną treść.
dstDoc = generate_document(doc, extractedNodes)
# Zapisz dokument.
dstDoc.save("extract_content_between_paragraphs.docx")
Wyodrębnij tekst między różnymi typami węzłów w dokumencie programu Word
Możesz także wyodrębniać zawartość między różnymi typami węzłów. Dla demonstracji wyodrębnijmy zawartość między akapitem a tabelą i zapiszmy ją w nowym dokumencie programu Word. Poniżej przedstawiono kroki, aby wykonać tę operację.
- Załaduj dokument programu Word przy użyciu klasy Document.
- Uzyskaj odniesienie początkowego i końcowego węzła do dwóch obiektów za pomocą metody Document.firstsection.body.getchild(NodeType, int, boolean).
- Wywołaj metodę extractcontent(startPara, endPara, True), aby wyodrębnić węzły do obiektu.
- Wywołaj metodę pomocnika generowaneocument(Document, extractedNodes), aby utworzyć dokument składający się z wyodrębnionej zawartości.
- Zapisz zwrócony dokument przy użyciu metody Document.save(string).
Poniższy przykładowy kod pokazuje, jak wyodrębnić tekst między akapitem a tabelą w języku Python.
# Załaduj dokument
doc = aw.Document("Extract content.docx")
# Zdefiniuj węzły początkowe i końcowe.
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()
# Wyodrębnij zawartość między tymi węzłami w dokumencie. Uwzględnij te znaczniki w ekstrakcji.
extracted_nodes = extract_content(start_para, end_table, True)
# Wygeneruj dokument zawierający wyodrębnioną treść.
dstDoc = generate_document(doc, extractedNodes)
# Zapisz dokument.
dstDoc.save("extract_content_between_nodes.docx")
Wyodrębnij tekst między akapitami na podstawie stylów
Sprawdźmy teraz, jak wyodrębnić treść między akapitami na podstawie stylów. W celu demonstracji wyodrębnimy zawartość między pierwszym „Nagłówkiem 1” a pierwszym „Nagłówkiem 3” w dokumencie programu Word. Poniższe kroki pokazują, jak to osiągnąć w języku Python.
- Najpierw załaduj dokument programu Word przy użyciu klasy Document.
- Następnie wyodrębnij akapity do obiektu, używając metody pomocniczejparagrafybystylename(Document, “Heading 1”).
- Wyodrębnij akapity do innego obiektu, używając metody pomocniczejparagrafybystylename(Document, “Heading 3”).
- Wywołaj metodę extractcontent(startPara, endPara, True) i przekaż pierwsze elementy w obu tablicach akapitów jako pierwszy i drugi parametr.
- Wywołaj metodę pomocnika generowaneocument(Document, extractedNodes), aby utworzyć dokument składający się z wyodrębnionej zawartości.
- Na koniec zapisz zwrócony dokument przy użyciu metody Document.save(string).
Poniższy przykład kodu pokazuje, jak wyodrębnić zawartość między akapitami na podstawie stylów.
# Załaduj dokument
doc = aw.Document("Extract content.docx")
# Zbierz listę akapitów, używając odpowiednich stylów nagłówków.
parasStyleHeading1 = paragraphs_by_style_name(doc, "Heading 1")
parasStyleHeading3 = paragraphs_by_style_name(doc, "Heading 3")
# Użyj pierwszego wystąpienia akapitów z tymi stylami.
startPara1 = parasStyleHeading1[0]
endPara1 = parasStyleHeading3[0]
# Wyodrębnij zawartość między tymi węzłami w dokumencie. Nie uwzględniaj tych znaczników w ekstrakcji.
extractedNodes = extract_content(startPara1, endPara1, False)
# Wygeneruj dokument zawierający wyodrębnioną treść.
dstDoc = generate_document(doc, extractedNodes)
# Zapisz dokument.
dstDoc.save("extract_content_between_paragraphs_based_on-Styles.docx")
Czytaj więcej
Możesz zapoznać się z innymi scenariuszami wyodrębniania tekstu z dokumentów programu Word, korzystając z tego artykułu w dokumentacji.
Uzyskaj bezpłatną licencję API
Możesz uzyskać tymczasową licencję na używanie Aspose.Words for Python bez ograniczeń ewaluacyjnych.
Wniosek
W tym artykule nauczyłeś się, jak wyodrębniać tekst z dokumentów MS Word za pomocą Python. Ponadto widziałeś, jak programowo wyodrębniać zawartość między podobnymi lub różnymi typami węzłów w dokumencie programu Word. W ten sposób możesz zbudować własny ekstraktor tekstu MS Word w Python. Poza tym możesz poznać inne funkcje Aspose.Words for Python, korzystając z dokumentacji. Jeśli masz jakieś pytania, daj nam znać za pośrednictwem naszego forum.
Zobacz też
- Twórz dokumenty MS Word za pomocą Python
- Konwertuj dokument Word na HTML za pomocą Python
- Konwertuj dokumenty programu Word do formatu PNG, JPEG lub BMP w Python
- Dokumenty Worda do Markdown przy użyciu Python
- Porównaj dwa dokumenty Worda w Python
Info: Jeśli kiedykolwiek będziesz potrzebował pobrać dokument Word z prezentacji PowerPoint, możesz użyć konwertera Aspose Presentation to Word Document.