Felder in einer PDF-Datei anhand Ihrer Position ermitteln

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

Hallo zusammen,

ich lese mit PyPDF2 über die Methode get_fields die Daten von Textfeldern und Checkboxes aus. Das funktioniert soweit alles sehr gut.

Code: Alles auswählen

pdf_reader = PdfReader(open(self._current_pdf_file_path, "rb"))
obj_dict = pdf_reader.get_fields()
Bild

Allerdings hat sich heraus gestellt, dass die Textfelder bzw. Checkboxes bei vom Aufbau identischen Dateien unterschiedliche Namen haben. Da die Dateien von einer Firmensoftware generiert werden, kann ich daran auch nicht ändern.

Nun meine Frage : Wie kann ich die Position dieser Felder ermitteln und über diese Position dann auf die Daten der Felder zugreifen.

Vielen Dank für Eure Hinweise !
Benutzeravatar
noisefloor
User
Beiträge: 3876
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

mit Position meinst du die absolute Position im PDF, also so was wie "Abstand X = 10 und Abstand Y=15" von der linken unteren Ecke des PDFs", richtig?

Dann lautet die Antwort: AFAIK nur, wenn du dich selber durch die Seitenbeschreibung des PDF durchparst und Daten extrahierst. Also ziemlich aufwendig.

Was du vorhast hört sich eher nach einer Anwendung für eine Bildanalyse mittels (einfacher) KI an. Die erkennt dann, wo was steht, nachdem sie mit den entsprechenden Dokumenten trainiert wurde. So funktioniert ja z.B. i.d.R. die automatische Rechnungsverarbeitung in Unternehmen, wenn die Rechnungen von extern als PDF bekommen.

Gruß, noisefloor
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

Hallo noisfloor,

Du hast recht, es geht um die absolute Position auf der PDF-Seite. Dabei handelt es sich um Objekte (mal als Widgets und mal als xForms-Elemente bezeichnet. Ich habe eventuell eine Lösung gefunden.

https://stackoverflow.com/questions/228 ... a-pdf-file

Nach Bildanalyse klingt das eher nicht, schon eher nach dem Durchlaufen sämtlicher auf der Page enthaltenen Objekte.

Vielen Dank für die Antwort. Ich werde über meine Erfolge (oder Misserfolge) berichten.

Viele Grüße
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

Hallo zusammen,

falls sich jemand für die Lösung des Problems interessiert : PyMuPDF

PyMuPDF installieren und fitz importieren

Hier ein kurzes Code-Beispiel :

Code: Alles auswählen

import fitz

def get_widgets_with_pymupdf(file_path: str) -> None:
    pdf = fitz.open(file_path)
    page: fitz.Page = pdf.load_page(0)
    widgets = page.widgets()
    for widget in widgets:
        x1_position: int = int(widget.rect[0])
        y1_position: int = int(widget.rect[1])
        x2_position: int = int(widget.rect[2])
        y2_position: int = int(widget.rect[3])
        print('X1 = ' + str(x1_position) + ' Y1 = ' + str(y1_position) + ' X2 = ' + str(x2_position) + ' Y2 = ' + str(y2_position) + ' Wert = ' + str(widget.field_value))
 
Zu beachten ist, dass bei mir nach der ersten Installation (Windows / PyCharm) das Modul nicht gefunden wurde und damit fitz nicht importiert werden konnte. Habe alles noch einmal deinstalliert und nen Tag später den Versuch wiederholt.

Siehe auch : https://stackoverflow.com/questions/731 ... eld-widget

Viele Grüße
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Schoen, dass es klappt. Was du dir angewoehnen solltest: string-formatting. Dieses rum-geplusse ist wirklich grauselig.

Code: Alles auswählen

# print kann mehrere argumente
print('X1 = ', x1_position,' Y1 = ', y1_position, ' X2 = ', x2_position, 'Y2 = ', y2_position, 'Wert = ', widget.field_value)
#format strings machen das Leben einfacher
print(f'X1 = {x1_position}  Y1 = {y1_position}  X2 = {x2_position}  Y2 = {y2_position}  Wert = {widget.field_value))
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

... war doch nur zum schnell "Rumprobieren" !!!
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

War garantiert nicht schneller zu schreiben, als einer der beiden meiner Vorschlaege. Aber schon verstanden, keine Hinweise, wie man sich das leben einfacher machen kann.
Karsten Böhme
User
Beiträge: 86
Registriert: Sonntag 23. Dezember 2012, 07:54

Du hast ja Recht und ich gelobe Besserung !

... und nicht gleich beleidigt sein :)

VG
Karsten
Benutzeravatar
__blackjack__
User
Beiträge: 13202
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wo man auch Zeit sparen kann ist beim Tippen von extrem unsinnigen Typannotationen. Jeder menschliche Leser weiss auch ohne Annotation das `int()` etwas vom Typ `int` zurück gibt. Genau so weiss das die Software, die diese Annotationen prüft.

Code: Alles auswählen

def get_widgets_with_pymupdf(file_path):
    for widget in fitz.open(file_path).load_page(0).widgets():
        x_1, y_1, x_2, y_2 = map(int, widget.rect)
        print(
            "X1 =",
            x_1,
            "Y1 =",
            y_1,
            "X2 =",
            x_2,
            "Y2 =",
            y_2,
            "Wert =",
            widget.field_value,
        )
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Sirius3
User
Beiträge: 17797
Registriert: Sonntag 21. Oktober 2012, 17:20

Eine Funktion, die get_... heißt sollte etwas zurückliefern, wenn das nicht der Fall ist, dann ist das sehr verwirrend.
Dass x1_position ein int ist, ist für alle Computer klar, und auch für die meisten Menschen, diese Typannotation ist also total überflüssig. Dass load_page ein Page-Objekt zurückliefert, sollte auch klar sein. Warum Du dann bei widgets und widget die Typannotation wegläßt, bleibt wohl ein Geheimnis.
Wenn man was mit open öffnet, sollte man das auch wieder schließen.

Code: Alles auswählen

def print_widgets(file_path):
    with fitz.open(file_path) as pdf:
        for widget in pdf[0].widgets():
            x1, y1, x2, y2 = widget.rect
            value = widget.field_value
            print(f"X1 = {x1} Y1 = {y1} X2 = {x2} Y2 = {y2} Wert = {value}")
Benutzeravatar
__blackjack__
User
Beiträge: 13202
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sirius3: Die Koordinaten können auch Gleitkommazahlen sein. Also ist das `int()` hier vielleicht tatsächlich gewollt.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Antworten