PDF Datei nach string durchsuchen und Seiten ausgeben

Du hast eine Idee für ein Projekt?
Antworten
VoLLioMenTT
User
Beiträge: 19
Registriert: Montag 16. Oktober 2017, 16:00

Montag 16. Oktober 2017, 16:15

Hallo liebe Python-Forum Community,

Das ist mein erster Post falls ich irgendetwas falsch machen sollte tut es mir leid.^^

Ich würde gerne ein Programm schreiben das eine PDF Datei nach einem bestimmten String durchsucht und mir die Seitennummer von jeder Seite auf der sich dieser String befindet ausgibt.

Die PDF Datei kann ich davor selbstverständlich auch in Text umwandeln das sollte kein problem darstellen falls dies von nöten ist.

Wie auch immer, ich werde morgen anfangen zu recherchieren wie ich das angehe und anfangen zu arbeiten.

Falls jemand von euch den ein oder anderen Tipp hat würde mich dass sehr freuen :)

MfG
VoLLioMenTT
VoLLioMenTT
User
Beiträge: 19
Registriert: Montag 16. Oktober 2017, 16:00

Dienstag 17. Oktober 2017, 14:22

UPDATE:

Code: Alles auswählen

import PyPDF2

print("String eingeben:")
String = input()

print("Eingabe: ", String)

open("test.pdf", "rb")
File = PyPDF2.PdfFileReader("test.pdf")

Seitenanzahl = File.getNumPages()
print("Seitenanzahl: ", Seitenanzahl)

ausgabe = []

for i in range(1, Seitenanzahl):
    Seite = File.getPage(i)
    y = ""
    y += Seite.extractText()
    x = y.encode('utf-8').lower()
    prüfe = x.find(String)
    if prüfe == True:
        ausgabe += i
print(ausgabe)
Den Code habe ich bereits geschrieben doch ich bekomme diese Fehlermeldung dabei raus:
prüfe = x.find(String)
TypeError: a bytes-like object is required, not 'str'

Außerdem wenn ich print(x) ausgebe, bekomme ich keinen Text wie ich es gerne hätte sondern nur einen wirren Haufen von Zahlen, Buchstaben und Zeichen, es wird also nicht encodet.
Kann mir jemand weiterhelfen?

Ich habe auch in einem Forum gelesen, dass man das ganze mit pywin32 über DDE machen kann, da das ganze im Endeffekt auf Windows laufen soll und Adobe Acrobate 9 Pro installiert ist. Allerdings finde ich kaum Foren, Guides etc. dazu, falls es darüber womöglich einfacher wäre, wüsste jemand von euch wo ich mich am besten und das wenn dann kostenlos in die Thematik einlesen kann?

MfG
VoLLioMenTT
Sirius3
User
Beiträge: 8611
Registriert: Sonntag 21. Oktober 2012, 17:20

Dienstag 17. Oktober 2017, 14:40

@VoLLioMenTT: die Zeile mit "open..." ist überflüssig, weil Du mit dem geöffneten File-Objekt nichts machst. Einen leeren String zu erzeugen, um dann mit += etwas anzuhängen ist unsinnig, da kann man gleich "y = Seite..." schreiben, wobei i, y, x, prüfe, etc. schlechte Variablennamen sind. Variablennamen sollten aussagen, wofür diese Variable gut ist. "prüfe" ist eine Tätigkeit, Variablen speichern aber Zustände. "geprüft" wäre der Zustand dazu, aber Du hast ja nichts geprüft, sondern das Ergebnis einer Suche, also ist doch "gefunden", oder noch besser, "string_auf_seite_enthalten", wobei wir gleich beim nächsten Problem wären. "find" gibt die Position des gefundenen Strings zurück, Du willst aber nur auf enthalten/nicht enthalten prüfen, dafür gibt es den in-Operator: "string_auf_seite_enthalten = String in x". Explizit auf True zu prüfen ist unsinnig, weil jede Prüfung auf Wahrheit prüft. In der darauffolgenden Zeile versuchst Du eine Liste mit einer Zahl zu addieren, was nicht geht. Du suchst wahrscheinlich "ausgabe.append(i)".

Zur Fehlermeldung: extractText liefert Dir einen String zurück, den Du gleich mit einem anderen String vergleichen könntest, tust Du aber nicht, sondern Du wandelst den Text in Bytes um, was dann nicht mehr mit einem String vergleichbar ist. Bytes in Kleinbuchstaben umzuwandeln, führt auf auch nicht zum gewünschten Ergebnis.

Ist es Absicht, dass Du die erste Seite überspringst?

Code: Alles auswählen

import PyPDF2

print("String eingeben:")
search_string = input()

print("Eingabe: ", search_string)

pdf_file = PyPDF2.PdfFileReader("test.pdf")

page_count = pdf_file.getNumPages()
print("Seitenanzahl: ", page_count)

pages_found = []
for page_num in range(1, page_count): # ignore page 1
    page = pdf_file.getPage(page_num)
    page_text = page.extractText().lower()
	if search_string in page_text:
        pages_found.append(page_num)
print(pages_found)
VoLLioMenTT
User
Beiträge: 19
Registriert: Montag 16. Oktober 2017, 16:00

Dienstag 17. Oktober 2017, 15:29

@Sirius3
Vielen Vielen Dank für die Antwort, leider habe ich nun ein Problem das mich noch mehr Überfragt :K , wenn ich das Programm nun starte bekomme ich Anfangs mal den input für den String und die Seitenanzahl, doch danach gibt das Programm nichts mehr aus und ich muss es mit Strg + C stoppen.

Hat jemand eine Idee woran das liegen könnte?
VoLLioMenTT
User
Beiträge: 19
Registriert: Montag 16. Oktober 2017, 16:00

Mittwoch 18. Oktober 2017, 06:25

UPDATE:
Ich habe probiert in die pages_found = [] list zahlen einzutragen um herauszufinden ob er dann wenigstens diese Zahlen ausgibt, aber das tut er nicht.
Sirius3
User
Beiträge: 8611
Registriert: Sonntag 21. Oktober 2012, 17:20

Mittwoch 18. Oktober 2017, 07:07

@VoLLioMenTT: der erste Schritt wäre, auszugeben, auf welcher Seite sich das Programm gerade befindet. Dann weiß man, ob es schon beim Öffnen der Datei oder bei einer bestimmten Seite hängen bleibt.
VoLLioMenTT
User
Beiträge: 19
Registriert: Montag 16. Oktober 2017, 16:00

Mittwoch 18. Oktober 2017, 07:43

Ok das nichts weiter passiert ist war kein Fehler sondern nur mein Denkfehler, da es ja einige Zeit dauert bis er alle Seiten durchsucht hat.

Das Script Funktiert also und wenn ich page_num in der for schleife ausgebe, gibt er mir auch alle Seiten aus und am ende die leere pages_found list.

Mit dem String den ich suche kann er nichts anfangen, denn wenn ich page_text ausgebe sieht man das er keine für mich nützlichen Daten aus der PDF zieht, sondern lediglich einen wirren haufen von Zahlen Buchstaben und Zeichen.

Muss ich die Ausgabe womöglich doch encoden? und wenn ja mit was?
Sirius3
User
Beiträge: 8611
Registriert: Sonntag 21. Oktober 2012, 17:20

Mittwoch 18. Oktober 2017, 08:15

@VoLLioMenTT: in PDF-Dateien werden die Schriften mit eingebunden, aber nur die Zeichen, die auch tatsächlich gebraucht werden. Die Zeichennummern werden dabei umsortiert. Zudem werden nur Text-Positionen gespeichert, den eigentlichen Textfluß muß man durch geschicktes Raten ermitteln. pdfminer hört sich dafür ganz vielversprechend an, ab es aber nicht getestet.
VoLLioMenTT
User
Beiträge: 19
Registriert: Montag 16. Oktober 2017, 16:00

Donnerstag 19. Oktober 2017, 10:28

@Sirius3

UPDATE:
Ich habe mir das pdfminer module installiert, mir einen Code rausgesucht und dieses umgeschrieben.

Code: Alles auswählen

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter#process_pdf 
from pdfminer.pdfpage import PDFPage 
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from io import StringIO
 
 
def pdf_to_text(pdfname): 

    rsrcmgr = PDFResourceManager() 
    sio = StringIO() 
    codec = 'utf-8' 
    laparams = LAParams() 
    device = TextConverter(rsrcmgr, sio, codec=codec, laparams=laparams) 
    interpreter = PDFPageInterpreter(rsrcmgr, device) 

    search_string = "CB6"
    Pages_Found = []
    Page_Num = 1

    fp = open(pdfname, 'rb')
    for page in PDFPage.get_pages(fp):
        print(Page_Num)
        Page_Num += 1
        interpreter.process_page(page)
        page_text = sio.getvalue()
        if search_string in page_text:
            Pages_Found.append(Page_Num)
    fp.close() 
 
 
    text = sio.getvalue() 

  
    device.close()
    sio.close() 
 
    return Pages_Found

x = pdf_to_text("test.pdf")
print(x)
Nun Funktioniert das ganze ohne Fehlermeldungen, allerdings gibt er mir ab der 2ten Seite jede aus, obwohl man den search_string nicht auf jeder Seite findet.

Eine Idee was ich versuchen könnte?

MfG
VoLLioMenTT
Zuletzt geändert von VoLLioMenTT am Donnerstag 19. Oktober 2017, 10:48, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 8611
Registriert: Sonntag 21. Oktober 2012, 17:20

Donnerstag 19. Oktober 2017, 10:48

Du benutzt ja auch EINEN TextConverter für das ganze PDF. Wenn Du seitenweise suchen willst, mußt Du auch die Seiten einzeln konvertieren.

Code: Alles auswählen

def get_page_content(page): 
    rsrcmgr = PDFResourceManager() 
    output = StringIO() 
    device = TextConverter(rsrcmgr, output, laparams=LAParams()) 
    interpreter = PDFPageInterpreter(rsrcmgr, device) 
    interpreter.process_page(page)
    return output.getvalue()
 
def search_pdf(pdfname, search_string):
    pages_found = []
    with open(pdfname, 'rb') as fp:
        for page_num, page in enumerate(PDFPage.get_pages(fp), 1):
            print(page_num)
            page_text = get_page_content(page)
            if search_string in page_text:
                pages_found.append(page_num)
    return pages_found
PS: Namenskonvention ist, alle Variablennamen klein zu schreiben.
VoLLioMenTT
User
Beiträge: 19
Registriert: Montag 16. Oktober 2017, 16:00

Donnerstag 19. Oktober 2017, 11:49

@Sirius3
Es funktioniert :D , vielen vielen Dank für deine Hilfe und deine Geduld mit mir.

Wir haben zwar erst Donnerstag, aber ich wünsche dir auf jeden fall schon mal ein schönes Wochenende.
Antworten