Das Analysieren von PDFs mit Text ist mit Python einfach ...
Wenn Zeicheninformationen enthalten sind, können Sie einfach einen Webdienst erstellen, indem Sie Zeichen- und Tabelleninformationen aus der PDF-Datei extrahieren und diese Daten verwenden. Das Ergebnis eines einfachen Gedankens lautet wie folgt. Ich werde.
** Ich habe versucht, PDF-Daten der medizinischen Online-Versorgung zu verwenden, die auf der Ausbreitung einer neuen Coronavirus-Infektion basieren ** https://qiita.com/mima_ita/items/c0f28323f330c5f59ed8
Das wichtigste Ergebnis, das ich hier erhalten habe, ist ** "Lesen Sie keine PDF-Daten auf einem Computer, es ist etwas, das Menschen lesen" ** </ font> und einige Umgang mit PDF mit Python.
Dieses Mal werde ich erklären, wie man mit PDF mit diesem kleinen Python umgeht. Die experimentelle Umgebung ist Window10 Python 3.7.5 64bit.
Alle PDF-Zeichen und Grafiken bestehen aus Operatoren und Operatoren, deren Spezifikationen unten aufgeführt sind. https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf
Es gibt verschiedene Bibliotheken, die zum Lesen von PDF in Python nützlich sind, aber hier werde ich PyPDF2 verwenden, um das PDF zu lesen. Das Merkmal dieser Bibliothek ist, dass sie vollständig in Python geschrieben ist, sodass Sie überprüfen können, wie das PDF auf Operator- und Operatorebene aussieht.
Lassen Sie uns überprüfen, aus welcher Art von Operatoren und Operatoren das folgende einfache PDF tatsächlich besteht. http://needtec.sakura.ne.jp/doc/hello.pdf
Der folgende Code listet Operatoren und Operatoren auf.
import PyPDF2
from PyPDF2.pdf import ContentStream
with open("hello.pdf", "rb") as fp:
pdf = PyPDF2.PdfFileReader(fp)
for page_no in range(pdf.numPages):
page = pdf.getPage(page_no)
content = page['/Contents'].getObject()
if not isinstance(content, ContentStream):
content = ContentStream(content, pdf)
for operands, operator in content.operations:
print(operands, operator)
Das Ergebnis davon mit dem einfachen PDF oben ist wie folgt.
[1, 0, 0, 1, 0, 0] b'cm'
[] b'BT'
['/F1', 12] b'Tf'
[14.4] b'TL'
[] b'ET'
[] b'n'
[10, 10, 200, 200] b're'
[] b'S'
[] b'BT'
[1, 0, 0, 1, 100, 50] b'Tm'
['Hello'] b'Tj'
[] b'T*'
[] b'ET'
Technische Daten Folgendes kann beim Lesen der Anhang A-Bedienerübersicht analysiert werden. Ich verstehe.
Operands | Operator | Description | Seitenzahl |
---|---|---|---|
x y width height | re | Untere linke Ecke(x,y)Fügen Sie einen quadratischen Pfad von hinzu | 133p |
- | S | Zeichnen Sie eine Linie entlang des aktuellen Pfads | 135p |
a b c d e f | Tm | Gibt die Matrix an, die die Position des Textes bestimmt. |
249 |
string | Tj | Zeichen anzeigen | 250 |
Mit anderen Worten wird die Zeichnung wie folgt sein. (1) Zeichnen Sie ein Quadrat mit einer Breite von 200 und einer Höhe von 200 aus (10,10) mit dem unteren linken Rand als Ursprung. (2) Schreiben Sie das Zeichen "Hallo" aus (100, 50)
Diesmal war es ein einfaches Beispiel, damit ich es lesen konnte, aber das Zeichnen des Textes ist sehr mühsam. Wenn ich das Verhalten von Textpositionierungsoperatoren und Textanzeigeoperatoren nicht verstehe, werde ich Zeichen aus PDF und deren Positionen extrahieren Und die Größe kann nicht bekannt sein.
Das folgende PDF ist beispielsweise verfügbar. http://needtec.sakura.ne.jp/doc/hello2.pdf
Zum Zwecke der Betrachtung gibt es nur noch wenige japanische und Tabellenmatrizen, aber es ist schwierig, dies auf die gleiche Weise zu interpretieren.
Darüber hinaus verfügt PyPDF2 über eine Funktion zum Extrahieren von Seiten mit dem Namen page.extractText (). Für nichtamerikanische Benutzer ist dies jedoch sehr schwierig. https://github.com/mstamy2/PyPDF2/issues
PDFMiner erleichtert das Extrahieren der Zeichen im PDF.
Im Folgenden finden Sie ein Beispiel zum Extrahieren der Zeichen in der PDF-Datei.
from pdfminer.high_level import extract_text
print(extract_text('hello2.pdf'))
Darüber hinaus besteht der wahre Wert von PDFMiner nicht nur darin, Zeichen zu extrahieren, sondern auch die Koordinaten und die Größe der zu zeichnenden Zeichen zu ermitteln. Unten finden Sie ein Beispielprogramm, das bestimmte PDF-Zeichen und deren Koordinateninformationen extrahiert.
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfpage import PDFTextExtractionNotAllowed
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import (
LAParams,
LTContainer,
LTTextLine,
)
def get_objs(layout, results):
if not isinstance(layout, LTContainer):
return
for obj in layout:
if isinstance(obj, LTTextLine):
results.append({'bbox': obj.bbox, 'text' : obj.get_text(), 'type' : type(obj)})
get_objs(obj, results)
def main(path):
with open(path, "rb") as f:
parser = PDFParser(f)
document = PDFDocument(parser)
if not document.is_extractable:
raise PDFTextExtractionNotAllowed
# https://pdfminersix.readthedocs.io/en/latest/api/composable.html#
laparams = LAParams(
all_texts=True,
)
rsrcmgr = PDFResourceManager()
device = PDFPageAggregator(rsrcmgr, laparams=laparams)
interpreter = PDFPageInterpreter(rsrcmgr, device)
for page in PDFPage.create_pages(document):
interpreter.process_page(page)
layout = device.get_result()
results = []
print('objs-------------------------')
get_objs(layout, results)
for r in results:
print(r)
main('hello2.pdf')
Das Ergebnis der Ausführung dieses Programms mit PDF mit gemischtem Japanisch ist wie folgt.
objs-------------------------
{'bbox': (90.744, 728.1928, 142.2056, 738.7528), 'text': 'Hallo Welt\n', 'type': <class 'pdfminer.layout.LTTextLineHorizontal'>}
{'bbox': (168.5, 728.1928, 223.8356, 738.7528), 'text': 'Die Katze klingelte\n', 'type': <class 'pdfminer.layout.LTTextLineHorizontal'>}
{'bbox': (168.5, 709.7128, 202.8356, 720.2728), 'text': 'ich bin Gott\n', 'type': <class 'pdfminer.layout.LTTextLineHorizontal'>}
{'bbox': (90.744, 691.1128, 146.0456, 701.6728), 'text': 'Gott ist gestorben\n', 'type': <class 'pdfminer.layout.LTTextLineHorizontal'>}
{'bbox': (168.5, 691.1128, 171.2456, 701.6728), 'text': ' \n', 'type': <class 'pdfminer.layout.LTTextLineHorizontal'>}
{'bbox': (168.5, 672.6328, 255.2756, 683.1928), 'text': 'Aw neo l sf\n', 'type': <class 'pdfminer.layout.LTTextLineHorizontal'>}
{'bbox': (90.744, 709.7128, 93.4896, 720.2728), 'text': ' \n', 'type': <class 'pdfminer.layout.LTTextLineHorizontal'>}
{'bbox': (90.744, 672.6328, 93.4896, 683.1928), 'text': ' \n', 'type': <class 'pdfminer.layout.LTTextLineHorizontal'>}
{'bbox': (85.104, 654.1528, 87.8496, 664.7128), 'text': ' \n', 'type': <class 'pdfminer.layout.LTTextLineHorizontal'>}
Sie können sehen, dass Sie die Koordinaten sowie den Inhalt der Zeichen in der PDF erhalten.
Es gibt keine Operatoren und Operatoren, die Tabellen in PDF darstellen. Ich vertrete die Tabelle nur mit der bisher beschriebenen quadratischen Zeichnung und Textzeichnung. Daher ist es nicht möglich, PDF-Tabellen so einfach zu analysieren wie HTML-Tabellen und Excel.
Einige Python-Bibliotheken versuchen, die PDF-Tabelle zu analysieren. Dieses Mal verwenden wir camelot, das vollständig in Python implementiert ist.
Unten finden Sie einen Vergleich von camelot mit anderen Bibliotheken. https://github.com/atlanhq/camelot/wiki/Comparison-with-other-PDF-Table-Extraction-libraries-and-tools
Das Ergebnis meines Vergleichs mit tabula-py ist wie folgt. ** [PDF des Ministeriums für Gesundheit, Arbeit und Soziales in CSV oder JSON konvertieren](https://needtec.sakura.ne.jp/wod07672/2020/04/29/%e5%8e%9a%e7%94%9f%e5 % 8a% b4% e5% 83% 8d% e7% 9c% 81% e3% 81% aepdf% e3% 82% 92csv% e3% 82% 84json% e3% 81% ab% e5% a4% 89% e6% 8f % 9b% e3% 81% 99% e3% 82% 8b /) **
Extrahieren wir die Tabelle von früher verwendetes PDF mit camelot.
import camelot
tables = camelot.read_pdf('hello2.pdf')
for ix in tables[0].df.index:
print(ix, tables[0].df.loc[ix][0], '|', tables[0].df.loc[ix][1])
Ergebnis
0 Hallo Welt|Die Katze klingelte
1 |ich bin Gott
2 Gott starb|
3 |Aw neo l sf
Darüber hinaus können Sie die URL direkt angeben, um die PDF-Datei zu öffnen oder in CSV oder JSON zu exportieren. Einige PDFs können jetzt die Tabelle extrahieren.
In den meisten Fällen funktionieren die Standardeinstellungen, aber wenn Sie die PDF-Datei tatsächlich analysieren, verhält sie sich möglicherweise unerwartet. In diesem Fall empfehlen wir Ihnen, das folgende Dokument einmal zu lesen.
Advanced Usage https://camelot-py.readthedocs.io/en/master/user/advanced.html
Passen Sie die an read_pdf übergebenen Parameter an, während Sie überprüfen, was cameralot in Visual Debbug erkennt. ) Könnte funktionieren.
Obwohl es in Tweak Layout Generation erwähnt wird, ist Camelot intern PDFMiner. mit. Wenn die Tabelle mit der oben beschriebenen Methode nicht aus PDF extrahiert werden kann, kann sie möglicherweise durch Anpassen der an PDFMiner übergebenen Parameter gelöst werden.
Wenn Sie beispielsweise das folgende PDF auf dieselbe Weise wie den vorherigen Code analysieren, kann die zweite Zeile nicht gut extrahiert werden. http://needtec.sakura.ne.jp/doc/hello4.pdf
** Ausgabeergebnis **
0 1 |ah ah
1 |2 gut
2 3 |Uuu
Dies ist das Ergebnis der Erkenntnis, dass der Abstand zwischen "2" und "gut" zu eng ist und es sich um dieselbe Zeichenfolge handelt. So passen Sie dies an:
tables = camelot.read_pdf(
'hello4.pdf',
layout_kwargs = {
'char_margin': 0.25
}
)
layout_kwargs ist ein Objekt von Parametern, die an pdfminer.layout von PDFMiner übergeben werden sollen. char_margin betrachtet zwei Textblöcke, die näher als dieser Wert liegen, als zusammenhängend. Der Standardwert ist 0,5, was kürzer ist und weniger wahrscheinlich als der gleiche Text betrachtet wird.
Das Ergebnis der Ausführung mit diesem Parameter ist wie folgt.
0 1 |ah ah
1 |2 gut
2 3 |Uuu
--------------------------
0 1 |ah ah
1 2 |Gut
2 3 |Uuu
Bei der Verarbeitung einer Tabelle mit einer gepunkteten Linie mit Camelot wird die gepunktete Linie nicht erkannt.
Detect dotted line #370 https://github.com/atlanhq/camelot/issues/370
Das folgende PDF ist beispielsweise eines davon. ➀ Vertikale gepunktete Linie https://github.com/atlanhq/camelot/files/3565115/Test.pdf
② Horizontale gepunktete Linie https://github.com/mima3/yakusyopdf/blob/master/20200502/%E5%85%B5%E5%BA%AB%E7%9C%8C.pdf
Diese Lösung kann mit der im folgenden Artikel beschriebenen Methode behandelt werden.
・ ** [Gepunktete Linie als durchgezogene Linie mit Camelot verarbeiten](https://needtec.sakura.ne.jp/wod07672/2020/05/03/camelot%e3%81%a7%e7%82%b9%e7% b7% 9a% e3% 82% 92% e5% ae% 9f% e7% b7% 9a% e3% 81% a8% e3% 81% 97% e3% 81% a6% e5% 87% a6% e7% 90% 86% e3% 81% 99% e3% 82% 8b /) **
Einfach ausgedrückt werden die von Camelot verarbeiteten Bilddaten zwangsweise verarbeitet und die gepunktete Linie durch eine durchgezogene Linie ersetzt, um die Verarbeitung fortzusetzen.
Es gibt Fälle, in denen nichts unternommen werden kann, um ein PDF zu erstellen. Beispiel: [Für Daten mit langen Zeichen, die über die Zelle hinausgehen](https://qiita.com/mima_ita/items/c0f28323f330c5f59ed8#pdf%E3%81%8B%E3%82%89%E3%83%86%E3% 83% BC% E3% 83% 96% E3% 83% AB% E3% 82% 92% E6% 8A% BD% E5% 87% BA% E3% 81% 99% E3% 82% 8B% E9% 9A% 9B% E3% 81% AE% E5% 95% 8F% E9% A1% 8C% E7% 82% B9) und so weiter.
Wenn Sie zunächst vergessen, eine Linie zu zeichnen, funktioniert dies nicht ordnungsgemäß.
Die Methode zum Lesen der PDF-Datei wurde bis zum vorherigen Abschnitt erläutert. Lassen Sie uns als nächstes kurz über das Aktualisieren des PDF nachdenken.
Mit reportlab können Sie den Inhalt von Zeichentext und Abbildungen als PDF ausgeben.
from io import BytesIO
from reportlab.pdfgen import canvas
with open('hello.pdf', 'wb') as output_stream:
buffer = BytesIO()
c = canvas.Canvas(buffer, pagesize=(300, 300))
c.rect(10, 10, 200, 200, fill=0)
c.drawString(100, 50, 'Hello')
c.showPage()
c.save()
buffer.seek(0)
output_stream.write(buffer.getvalue())
Diese Ausgabe ist das zuvor verwendete PDF. http://needtec.sakura.ne.jp/doc/hello.pdf
Ich habe verschiedene Möglichkeiten untersucht, um ein vorhandenes PDF zu lesen und die grafischen Informationen und den Text auf der Seite neu zu schreiben, aber ehrlich gesagt schien es schwierig zu sein. Die hier vorgestellte Methode ist eine Methode zum Hinzufügen neuer Abbildungen und Texte zur PDF-Seite.
・ ** [Ersetzen Sie die gepunktete PDF-Linie durch eine durchgezogene Linie (PyPDF2 + reportlab)](https://needtec.sakura.ne.jp/wod07672/2020/05/04/pdf%e3%81%ae%e7%82% b9% e7% b7% 9a% e3% 82% 92% e5% ae% 9f% e7% b7% 9a% e3% 81% ab% e3% 81% 8a% e3% 81% 8d% e3% 81% 8b% e3% 81% 88% e3% 82% 8b /) ** ・ ** [Ersetzen Sie die gepunktete PDF-Linie durch eine durchgezogene Linie (PyMuPDF)](https://needtec.sakura.ne.jp/wod07672/2020/05/04/pdf%e3%81%ae%e7%82%b9% e7% b7% 9a% e3% 82% 92% e5% ae% 9f% e7% b7% 9a% e3% 81% ab% e3% 81% 8a% e3% 81% 8d% e3% 81% 8b% e3% 81% 88% e3% 82% 8bpymupdf /) **
Beachten Sie, dass PyPDF2 keine Komprimierungsfunktion hat. Verwenden Sie daher eine andere Methode, um die Datei zu aktualisieren. In meiner Umgebung sind aus 3 MB PDF 440 MB geworden.
Einige von Ihnen finden es möglicherweise einfach, die PDF-Daten in der bisherigen Erklärung zu verwenden. Wenn Sie nicht berechtigt sind, das eingegebene PDF zu ändern, stellen Sie es sich im Grunde als ** Thorn Road ** </ font> vor. In Excel können Sie beispielsweise Zellen unterscheiden, auch wenn Sie vergessen haben, einen Rahmen zu zeichnen, in PDF jedoch nicht.
Ich möchte diesen Artikel abschließen, indem ich die wichtigsten Dinge wiederhole, die ich am Anfang erwähnt habe.
** "Lesen Sie keine PDF-Daten auf einem Computer, es ist etwas, das Menschen lesen" ** </ font>
Recommended Posts