pyPdf für IndirectObject Extraktions
Frage
In diesem Beispiel folgend, kann ich alle Elemente in eine pdf-Datei auflisten
import pyPdf
pdf = pyPdf.PdfFileReader(open("pdffile.pdf"))
list(pdf.pages) # Process all the objects.
print pdf.resolvedObjects
Jetzt muß ich aus der PDF-Datei ein Nicht-Standard-Objekt extrahieren.
Meine Aufgabe ist die eines mit dem Namen myObject und es ist eine Zeichenfolge.
Das Stück vom Python Skript gedruckt, das mir Concernés ist:
{'/MYOBJECT': IndirectObject(584, 0)}
Die PDF-Datei ist dies:
558 0 obj
<</Contents 583 0 R/CropBox[0 0 595.22 842]/MediaBox[0 0 595.22 842]/Parent 29 0 R/Resources
<</ColorSpace <</CS0 563 0 R>>
/ExtGState <</GS0 568 0 R>>
/Font<</TT0 559 0 R/TT1 560 0 R/TT2 561 0 R/TT3 562 0 R>>
/ProcSet[/PDF/Text/ImageC]
/Properties<</MC0<</MYOBJECT 584 0 R>>/MC1<</SubKey 582 0 R>> >>
/XObject<</Im0 578 0 R>>>>
/Rotate 0/StructParents 0/Type/Page>>
endobj
...
...
...
584 0 obj
<</Length 8>>stream
1_22_4_1 --->>>> this is the string I need to extract from the object
endstream
endobj
Wie kann ich den Wert 584
folgen, um meinen String (unter pyPdf natürlich) ??
Lösung
jedes Element in pdf.pages
ein Wörterbuch ist, so auf Seite ist es unter der Annahme, 1 sollte pdf.pages[0]['/MYOBJECT']
das Element sein, das Sie wollen.
Sie können versuchen, die einzeln zu drucken oder steckt es mit help
und dir
in einem Python-Prompt für mehr darüber, wie die Zeichenfolge, die Sie wollen
Edit:
nach Erhalt einer Kopie des PDF-Empfang, fand ich das Objekt an pdf.resolvedObjects[0][558]['/Resources']['/Properties']['/MC0']['/MYOBJECT']
und der Wert kann über getData ()
Die folgende Funktion gibt eine allgemeinere Art und Weise dies durch rekursiv für den Schlüssel in Frage suchen zu lösen
import types
import pyPdf
pdf = pyPdf.PdfFileReader(open('file.pdf'))
pages = list(pdf.pages)
def findInDict(needle,haystack):
for key in haystack.keys():
try:
value = haystack[key]
except:
continue
if key == needle:
return value
if type(value) == types.DictType or isinstance(value,pyPdf.generic.DictionaryObject):
x = findInDict(needle,value)
if x is not None:
return x
answer = findInDict('/MYOBJECT',pdf.resolvedObjects).getData()
Andere Tipps
Ein IndirectObject bezieht sich auf ein tatsächliches Objekt (es ist wie ein Link oder Alias, so dass die Gesamtgröße des PDF kann reduziert werden, wenn der gleiche Inhalt an mehreren Stellen angezeigt wird). Die getObject Methode werden Sie das aktuelle Objekt.
Wenn das Objekt ein Textobjekt ist, dann nur ein str tun () oder Unicode () auf dem Objekt sollten Sie die Daten innerhalb davon.
Alternativ pyPdf speichert die Objekte in den resolvedObjects zuschreiben. Zum Beispiel, dass ein PDF enthält dieses Objekt:
13 0 obj
<< /Type /Catalog /Pages 3 0 R >>
endobj
Kann mit diesem gelesen werden:
>>> import pyPdf
>>> pdf = pyPdf.PdfFileReader(open("pdffile.pdf"))
>>> pages = list(pdf.pages)
>>> pdf.resolvedObjects
{0: {2: {'/Parent': IndirectObject(3, 0), '/Contents': IndirectObject(4, 0), '/Type': '/Page', '/Resources': IndirectObject(6, 0), '/MediaBox': [0, 0, 595.2756, 841.8898]}, 3: {'/Kids': [IndirectObject(2, 0)], '/Count': 1, '/Type': '/Pages', '/MediaBox': [0, 0, 595.2756, 841.8898]}, 4: {'/Filter': '/FlateDecode'}, 5: 147, 6: {'/ColorSpace': {'/Cs1': IndirectObject(7, 0)}, '/ExtGState': {'/Gs2': IndirectObject(9, 0), '/Gs1': IndirectObject(10, 0)}, '/ProcSet': ['/PDF', '/Text'], '/Font': {'/F1.0': IndirectObject(8, 0)}}, 13: {'/Type': '/Catalog', '/Pages': IndirectObject(3, 0)}}}
>>> pdf.resolvedObjects[0][13]
{'/Type': '/Catalog', '/Pages': IndirectObject(3, 0)}
Jehija Methode ist gut, wenn überall für das Objekt suchen. Meine Vermutung (im PDF-Suche) ist, dass es immer an der gleichen Stelle ist (der ersten Seite in der Unterkunft ‚MC0‘), und so ein viel einfacheres Verfahren zur Herstellung der Zeichenfolge zu finden wäre:
import pyPdf
pdf = pyPdf.PdfFileReader(open("file.pdf"))
pdf.getPage(0)['/Resources']['/Properties']['/MC0']['/MYOBJECT'].getData()