Liste aus Klartext auslesen

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
moinmoin
User
Beiträge: 14
Registriert: Samstag 14. Februar 2009, 00:30

Hallo Allerseits,

Ich nutze Python 2.6.5

Ich habe ein html Klartextfile, in dem es folgene Zeilen gibt:

Code: Alles auswählen

...
zeichenfolge : ["","/link/zu/pdf/file.pdf","/link/zu/pdf/file2.pdf","/link/zu/pdf/file3.pdf"]
...
Die Punkte bezeichnen beliebiges html-generiertes markup.

Kurz zum Ziel: Ich will die pdfs aus dieser Liste downloaden und verarbeiten. Der download und die Verarbeitung funktionieren bereits.

In einer früheren Version meines Skripts, habe ich jeden Link einzeln mittels regular expressions gematcht (re modul) und in eine Liste gepackt. Jetzt stehen die links so schön in einer Liste. Das will ich nutzen.

Konkrete Frage: Wenn ich die Zeile "zeichenfolge" RE matche, wie kann ich die Liste im Klartext auslesen und direkt in eine python liste packen? Hinzu kommt, dass die Liste über mehrere Zeilen gehen kann.

Bin über Hinweise / Tips sehr dankbar. Wenn noch Infos fehlen, bitte um Hinweis.

Vielen Dank im Voraus!
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ich glaube, ich verstehe dein Problem nicht. Suchst du so etwas?

Code: Alles auswählen

import re
s = '... zeichenfolge : ["","/link/zu/pdf/file.pdf","/link/zu/pdf/file2.pdf","/link/zu/pdf/file3.pdf"] ...'
print([eval(l) for l in re.findall(r'zeichenfolge : (\[.*?\])', s)])
Es gelten natürlich die üblichen Bemerkungen zu den Einschränkungen regulärer Sprachen, etwa das in den Strings kein ] vorkommen darf.

Stefan
moinmoin
User
Beiträge: 14
Registriert: Samstag 14. Februar 2009, 00:30

Danke für Deine Antwort Stefan.

Meine Imports:

Code: Alles auswählen

import os
import sys
from subprocess import Popen, call, PIPE
from re import compile as Pattern
from pyPdf import PdfFileWriter, PdfFileReader
import wx
Also zunächst habe ich die html Quelldatei mit

Code: Alles auswählen

source = open('bla.html', 'r')
geöffnet.

Dann will ich per

Code: Alles auswählen

pattern = Pattern(r'.+(/content/.+/fulltext.pdf).*')
part_link_list = []
for line in source:
    part_link_list.extend(pattern.findall(line))
Eine Liste (part_link_list) mit den Download-links erhalten.

Obiges pattern war zugeschneidert auf den Fall, wo die Links irgendwo im html-file standen...

Jetzt gibt es wie gesagt die Liste bereits in der html-Klartext-Datei. Also will ich die Startzeile der Liste per "zeichenfolge" (die ist in allen html-files die gleiche) herausfinden (re match) und dann die nachstehende Liste auslesen. Also Klartext-Liste -> Datenstruktur-Liste.

Jetzt klarer? Danke für Deine Hilfe!
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Genau das macht das Beispiel von sma doch - mit dem kleinen Unterschied, dass es nicht von einem Vorkommen der Liste ausgeht, sondern gleich nach mehreren Listen sucht - was ja m.E. kein Problem darstellt.

Statt eval kann man hier übrigens sehr schön ast.literal_eval() nutzen.

Schöne Grüße,

brb
moinmoin
User
Beiträge: 14
Registriert: Samstag 14. Februar 2009, 00:30

Danke für Deinen Kommentar Barabbas.

Muss jetzt weg, werde mir das nochmal in Ruhe ansehen, vielleicht pack ich es von hier aus alleine...
moinmoin
User
Beiträge: 14
Registriert: Samstag 14. Februar 2009, 00:30

So. Nach ein paar Tagen habe ich mich vorhin wieder an die Lösung gemacht.

Dank sma's code funktioniert das ganze nun! Danke nocheinmal!

Mein Problem war, dass ich durch das Öffnen per

Code: Alles auswählen

source = open('tmp_source', 'r')
das file als ein Objekt bekommen habe, auf das ich dann in einer for-Schleife zeilenweise das matching laufen ließ.

Ich hab ein wenig im Netz gestöbert und herausgefunden, dass die Methode read() das file als string einliest, den ich dann wie in sma's Beispiel nutzen kann.

Code: Alles auswählen

source = open('tmp_source', 'r').read()
Eine Frage noch: Der Tip von sma gibt mir eine Liste in einer Liste zurück. Gibt es einen eleganteren Weg als den folgenden um nur die eigentliche Liste aus dem Klartext zu erhalten?

Code: Alles auswählen

part_link_list = [eval(l) for l in re.findall(r'documentPdfDownloadUrls : (\[.*?\])', source)][0]
Grüße,
MM
BlackJack

@moinmoin: Dateien sollte man explizit wieder schliessen. Am besten mit der ``with``-Anweisung arbeiten.

Natürlich geht das eleganter: *Du* erstellst eine Liste mit einer Liste als einzigem Element. Lass das doch einfach, dann musst Du die Liste aus der Liste auch nicht heraus holen. Mach Dir mal klar was die einzelnen Teile des Ausdrucks jeweils als Ergebnis haben.
moinmoin
User
Beiträge: 14
Registriert: Samstag 14. Februar 2009, 00:30

Danke BlackJack für Deinen Kommentar!

Der part

Code: Alles auswählen

re.findall(r'documentPdfDownloadUrls : (\[.*?\])', source)
gibt mir eine Liste zurück, in der die gewünschte(n) Liste(n) als string(s) enthalten ist (sind).

Falls mehrere Listen durch findall gefunden werden, dann sind also mehrere strings in dieser Liste.

Code: Alles auswählen

[eval(l) for l in re.findall(r'documentPdfDownloadUrls : (\[.*?\])', source)]
evaluiert diese strings, in einer list comprehension, zu den eigentlichen Listen und packt diese durch [] wieder in eine Liste.

Soweit mein Verständnis der Abläufe.

Ich weiss ziemlich sicher, dass ich für diese Anwendung nur eine dieser Listen finden werde.

Ich habe nun:

Code: Alles auswählen

with open('tmp_source', 'r').read() as source:
    part_link_list = eval(re.findall(r'documentPdfDownloadUrls : (\[.*?\])', source)[0])
Ist das nun eleganter?
BlackJack

@moinmoin: Wenn Du nur eine Liste erwartest bzw. finden willst, warum dann `findall()`? Ich würde dann ja tatsächlich nur die erste Liste suchen. Und statt `eval()` wirklich besser `ast.literal_eval()`
moinmoin
User
Beiträge: 14
Registriert: Samstag 14. Februar 2009, 00:30

@BlackJack: Nach ein wenig Stöbern in der re Dokumentation bin ich auf folgendes gekommen:

Code: Alles auswählen

ast.literal_eval(re.search(r'documentPdfDownloadUrls : (\[.*?\])', source).group(1))
jetzt besser?
BlackJack

@moinmoin: Jup, das sieht gut aus. :-)
moinmoin
User
Beiträge: 14
Registriert: Samstag 14. Februar 2009, 00:30

Nice! "Fühlt" sich auch irgendwie richtiger an, ausserdem lesbarer.

Macht halt doch viel mehr Spass sich das alles hobbymäßig reinzuziehen - da ist der Lerneffekt viel größer...

Danke nochmal BlackJack, so gibt man richtig Nachhilfe!
Antworten