Auslesen von Metadaten aus pdf-Dateien

Code-Stücke können hier veröffentlicht werden.
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Aktuell programmiere ich ein kleines Programm, welches verschiedene Ordner durchsucht und die Pfade zu Pdf-Dateien in eine Datei schreibt. Neben dem Pfad möchte ich auch die Seitenzahl der jeweiligen PDF-Dateien in die Datei schreiben. Leider konnte ich bisher keinen wirklich lauffähigen Code hierfür finden. Soweit ich das verstanden habe kann man die PDF-Metadaten mittels pyPDF2 auslesen.

Kann hier jemand helfenß
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@TuXX: Die PdfFileReader Klasse von PyPDF2 verfügt über eine getNumPages() Methode. Vielleicht ist es das, was Du suchst. Lässt sich mit Google übrigens sehr schnell finden.
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Danke für den Hinweis. Mittlerweile habe ich das Paket pyPDF2 installiert und den folgenden Code gefunden:

import pyPDF2
pdf_file = open('C:\Users\test\Downloads\test.pdf')
read_pdf = PyPDF2.PdfFileReader(pdf_file)
number_of_pages = read_pdf.getNumPages()
print(number_of_pages)

Beim Ausführen des Codes erhalte ich die folgende Fehlermeldung:

SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape

Was mache ich hier falsch? Der Pfad ist auf jeden Fall korrekt.

Im Voraus Danke für eure Hilfe!
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Zu Testzwecken habe ich mittlerweile den Pfad zur Datei entfernt.

pdf_file = open('Problembeschreibung.pdf')

Dann wird folgende Fehlermeldung angezeigt:

PdfReadWarning: PdfFileReader stream/file object is not in binary mode. It may not be read correctly. [pdf.py:1079]
Traceback (most recent call last):
File "C:/Users/test/PycharmProjects/untitled/Schreibtest.py", line 28, in <module>
read_pdf = PyPDF2.PdfFileReader(pdf_file)
File "C:\Users\test\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1084, in __init__
self.read(stream)
File "C:\Users\test\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1689, in read
stream.seek(-1, 2)
io.UnsupportedOperation: can't do nonzero end-relative seeks

Process finished with exit code 1

Hat jemand eine Ahnung wie man diese beiden Probleme mit und ohne Pfadangabe lösen kann?
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

TuXX hat geschrieben:pdf_file = open('C:\Users\test\Downloads\test.pdf')
(...)
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape
Das Problem ist, dass der Backslash aus der Pfadangabe in diesem Zusammenhang eine andere Bedeutung hat. Um das zu vermeiden, schreibt man Windows-Pfade meistens nach diesem Schema:

Code: Alles auswählen

path = r'C:\pfad\zur\datei.txt'
Durch das vorangestellte r wird es ein sogannter Raw-String und der Backslash wird so verstanden wie du es erwartest.
TuXX hat geschrieben:pdf_file = open('Problembeschreibung.pdf')
(...)
PdfReadWarning: PdfFileReader stream/file object is not in binary mode. It may not be read correctly. [pdf.py:1079]
(...)
io.UnsupportedOperation: can't do nonzero end-relative seeks
Öffne die Datei einfach im Binärmodus:

Code: Alles auswählen

pdf_file = open(r'C:\dein\pfad\Problembeschreibung.pdf', 'rb')
Eine ausführliche Erklärung auf deutsch zur Benutzung von open() findest du übrigens hier.
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Vielen Dank für die Problemlösung. Die Seitenzahl wird nun ausgegeben. Allerdings habe ich schon die nächste Warnmeldung.

PdfReadWarning: Superfluous whitespace found in object header b'1' b'0' [pdf.py:1666]

Ist das lediglich eine Information, welche man guten Gewissens ignorieren kann? Gibt es einen Weg diese Info zu vermeiden?
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wenn du beim Erzeugen des PdfFileReader()-Objekts die Option strict=False mitgibst, dann sollte die Warnung verschwinden. An der Ursache dafür kannst du nur etwas machen, wenn du die PDF-Datei selbst erzeugt hast. Sofern sie aus einer Fremdquelle kommt, würde ich das wahrscheinlich einfach so belassen und da keine große Nachbearbeitung machen.

EDIT:
Und mit Blick auf die Uhrzeiten deiner Beiträge möchte ich etwas Schlaf zwischendurch empfehlen... ;)
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Mittlerweile bin ich einen kleinen Schritt vorangekommen. Wenn ich einen festen Pfad eingebe kann ich die Anzahl der Seiten auslesen:

pdf_file = open(r'C:\Users\rogbet\Desktop\Problembeschreibung.pdf', 'rb')

read_pdf = PyPDF2.PdfFileReader(pdf_file)
number_of_pages = read_pdf.getNumPages()
print(number_of_pages)

Was nachwievor nicht funktioniert ist das Zählen von Seiten für mittels Skript ermittelte Pfade. Der bisherige Code sieht wie folgt aus:

gespfad = os.path.join(folderName,filename)
pdf_file = open(gespfad, 'rb')
read_pdf = PyPDF2.PdfFileReader(pdf_file)
number_of_pages = read_pdf.getNumPages()
print(number_of_pages)

Bei der Kompilierung werden Fehler angezeigt. Weiss jemand was hier schief läuft?
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@TuXX: jetzt wäre es noch hilfreich, wenn Du den Fehler auch noch postest, inklusive Traceback.
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Hier noch die gewünschte Fehlerausgabe:

C:\Users\User\AppData\Local\Programs\Python\Python36\python.exe C:/Users/User/PycharmProjects/untitled/Schreibtest.py
2
PdfReadWarning: Superfluous whitespace found in object header b'1' b'0' [pdf.py:1666]
PdfReadWarning: Superfluous whitespace found in object header b'2' b'0' [pdf.py:1666]
PdfReadWarning: Superfluous whitespace found in object header b'3' b'0' [pdf.py:1666]
PdfReadWarning: Superfluous whitespace found in object header b'32' b'0' [pdf.py:1666]
Traceback (most recent call last):
File "C:\Users\User\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1147, in getNumPages
self.decrypt('')
File "C:\Users\User\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1987, in decrypt
return self._decrypt(password)
File "C:\Users\User\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1996, in _decrypt
raise NotImplementedError("only algorithm code 1 and 2 are supported")
NotImplementedError: only algorithm code 1 and 2 are supported

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:/Users/User/PycharmProjects/untitled/Schreibtest.py", line 36, in <module>
number_of_pages = read_pdf.getNumPages()
File "C:\Users\User\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1150, in getNumPages
raise utils.PdfReadError("File has not been decrypted")
PyPDF2.utils.PdfReadError: File has not been decrypted

Process finished with exit code 1

Im Voraus vielen Dank für eure Hinweise!
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@TuXX: Du scheinst ein verschlüsseltest PDF zu haben: »read_pdf.decrypt(password)«
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Ich habe das getestet. Scheinbar sind die von mir genutzen PDF wirklich verschlüsselt. Gibt es hier eine alternative Möglichkeit die PDF-Metadaten zu extrahieren (Seitenzahl, ...), ohne Passwort.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

TuXX hat geschrieben:Gibt es hier eine alternative Möglichkeit die PDF-Metadaten zu extrahieren (Seitenzahl, ...), ohne Passwort.
Jetzt komme ich nicht ganz mit: Was bringt dir das, wenn du ohne Passwort gar nicht auf die Daten zugreifen kannst?
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@TuXX: an die Seitenzahl kommt man auch bei einem verschlüsselten PDF ran. Nur das Paket scheint in den neueren Versionen dies zu verhindern.

Code: Alles auswählen

import PyPDF2
read_pdf = PyPDF2.PdfFileReader("test.pdf")
read_pdf._override_encryption = True
num_pages = read_pdf.trailer["/Root"]["/Pages"]["/Count"]
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Vielen Dank für den Code-Schnipsel. Solange ich wie im Beispiel keine Pfadangabe angebe funktioniert das nun einwandfrei, auch mit fremden Pdfs.

read_pdf = PyPDF2.PdfFileReader("alfa-laval-base-10_en.pdf")
read_pdf._override_encryption = True
num_pages = read_pdf.trailer["/Root"]["/Pages"]["/Count"]
print(num_pages)

Nun habe ich versucht diesen Schnipsel so anzupassen, dass dieser mit den von mir generierten Pfaden funktioniert, aber leider ohne Erfolg.

gespfad = os.path.join(folderName,filename)
pdf_file = open(gespfad, 'rb')
read_pdf = PyPDF2.PdfFileReader(pdf_file)
number_of_pages = read_pdf.getNumPages()
print(number_of_pages)

Was läuft hier falsch mit der Pfadangabe. Vielen Dank für eure Hilfe!
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@TuXX: was ist `gespfad` und existiert die Datei auch? Was und wo ist die Fehlermeldung?
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Hier noch die Fehlermeldung:

Traceback (most recent call last):
File "C:/Users/User/PycharmProjects/untitled/Schreibtest.py", line 41, in <module>
read_pdf = PyPDF2.PdfFileReader(pdf_file)
File "C:\Users\User\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1084, in __init__
self.read(stream)
File "C:\Users\User\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1697, in read
line = self.readNextEndLine(stream)
File "C:\Users\User\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1937, in readNextEndLine
raise utils.PdfReadError("Could not read malformed PDF file")
PyPDF2.utils.PdfReadError: Could not read malformed PDF file

Process finished with exit code 1

Was läuft hier falsch?
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Fehlermeldung sagt doch ganz eindeutig, dass das Format der PDF-Datei von pypdf nicht gelesen werden kann, entweder weil die Datei kaputt ist, oder in einem Format vorliegt, das PyPDF nicht versteht.
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Gibt es eine Alternative zu PyPDF2 für das Auslesen von Metadaten? Ich habe ein Paket namens PDFX gesehen.
TuXX
User
Beiträge: 24
Registriert: Sonntag 25. Juni 2017, 17:52

Mittlerweile habe ich die Verzeichnisse noch einmal aufgeräumt (nur noch pdfs). Wenn ich nun das Programm kompiliere, bekomme ich die folgende Fehlermeldung:

Traceback (most recent call last):
File "C:/Users/User/PycharmProjects/untitled/Schreibtest.py", line 60, in <module>
num_pages = read_pdf.trailer["/Root"]["/Pages"]["/Count"]
File "C:\Users\User\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\generic.py", line 516, in __getitem__
return dict.__getitem__(self, key).getObject()
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\generic.py", line 178, in getObject
return self.pdf.getObject(self).getObject()
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1593, in getObject
retval = self._getObjectFromStream(indirectReference)
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\pdf.py", line 1543, in _getObjectFromStream
streamData = BytesIO(b_(objStm.getData()))
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\generic.py", line 841, in getData
decoded._data = filters.decodeStreamData(self)
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\filters.py", line 346, in decodeStreamData
data = FlateDecode.decode(data, stream.get("/DecodeParms"))
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\filters.py", line 111, in decode
data = decompress(data)
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\PyPDF2\filters.py", line 49, in decompress
return zlib.decompress(data)
zlib.error: Error -3 while decompressing data: incorrect header check

Process finished with exit code 1

Muss ich noch ein Paket zlib integrieren? Wer hat eine Idee was hier falsch ist? Gibt es eine Alternative zu PyPDF2 zum Auslesen von PDF Metadaten wie Seitenzahl etc.?
Antworten