RE Frage

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
to.ni
User
Beiträge: 24
Registriert: Dienstag 6. Januar 2004, 15:52

Hallo zusammen,

habe heute mit Python "in der Praxis" angefangen und ne Frage zu den REs.
Ich will aus ner HTML-Datei alle Links extrahieren. Theoretisch ganz einfach, da ich das selbe Beispiel auch in nem Buch gefunden habe, aber im Buch wird davon ausgegangen, dass die Links das Format href="..." haben. Links könnten aber auch das Format href = ... haben (also mit leerzeichen, etc.

Ich bin inzwischen soweit:

Code: Alles auswählen

regex = re.compile(r"<a.*?href\s*=\s*[\"|']?.*?[\"|']?.*?>")
result = regex.findall(code)
Das liefert mir den gesamten A-Tag also z.B. <a href="link"> oder <a href = 'link' class = 'test'> oder <a href=link> oder was auch immer.

Aber ich brauche ja nur den HREF-Inhalt. Im Buch wurde das mit runden Klammer gelöst (*.?) - in meinem Beispiel würde das so aussehen:

Code: Alles auswählen

regex = re.compile(r"<a.*?href\s*=\s*[\"|']?(.*?)[\"|']?.*?>")
#                                           ^^^^^
result = regex.findall(code)
Das liefert mir aber eine Liste mit '', '','', etc.
also nicht den gewünschten HREF-Inhalt

Habt ihr ne Idee wie es ausbessern kann?

mfg to.ni
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Hallo!

Vorab: Das | hat in Zeichenmengen keine Sonderbedeutung, also kannst Du es weglassen. [\"'] bedeutet ja schon " oder '.

Am Beispiel von <a href=foobar> mal erläutert, was Dein RE macht.

Code: Alles auswählen

<a.*?href\s*=  erkennt    <a href=
\s*            erkennt    leeren String
[\"']?         erkennt    leeren String, logisch
(.*?)          erkennt    leeren String, das reicht dem Teil-RE schließlich
[\"']?         erkennt    leeren String, logisch
.*?            erkennt    foobar
                 Dem Teil-RE würde der leere String zwar auch reichen, 
                 aber die Folgebedingung hat da was gegen.
>              erkennt    >
Du hast nach dem Gleichheitszeichen fünf "0 bis"-Bedingungen, und das muss schief gehen, denn jede "0 bis"-Bedingung erkennt vorrangig den leeren String. Und das .*? am Ende ist so wenig spezifisch, dass es alles bekommt.

Mein Vorschlag: regex = re.compile(r"<a.*?href\s*=\s*([^\s>]+).*?>")
Ich kenne die html-Syntax nicht im Einzelnen. Mein RE funktioniert, wenn der Link kein Leerzeichen enthält (sollte ja wohl so sein) und wenn auf den Link (mit oder ohne Anführungszeichen) ein Leerzeichen oder > folgt. Wenn der Link in Anführungszeichen steht, musst Du die aber anschließend noch entfernen.

Jan
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hallo,

hier mal die Regex, die mit und ohne Anführungszeichen funktioniert und die Anführungszeichen nicht mitnimmt:

Code: Alles auswählen

regex = re.compile(r'<a.*?href\s*=\s*"?([^\s">]+).*?>')

Gruß

Dookie
to.ni
User
Beiträge: 24
Registriert: Dienstag 6. Januar 2004, 15:52

Danke für eure Hilfe,

alles Funktioniert, aber kapiert hab ichs dann doch nur zu (ca.) 80%...
Also ich hab das letzte Beispiel nochmal "Aufgebohrt", damit es auch mit eifnachen ' Funktioniert...
Aber nochmal schauen, was das Teil so macht (für den Lerneffekt):

Code: Alles auswählen

regex = re.compile(r"<a.*?href\s*=\s*[\"']?([^\s\"'>]+).*?>")

Code: Alles auswählen

<a           sucht nach <a
.*?          es können beliebig viele Zeichen folgen, ein oder null mal
href         sucht nach href
\s*          es könen beliebige Leerzeichen vorkommen, beliebig oft
=            sucht nach =
\s*          wieder beliebig viele Leerzeichen
[\"']?       " oder ' können einmal oder keinmal vorkommen
(            was zwischen den Klammern steht bekomme ich zurück? (unklar)
[^\s\"'>]    keine Ahnung... ^ ist mir ein Rätsel... 
             sonst... es kann vorkommen: ein beliebiges leerzeichen oder " oder ' oder > (falls der TAG               aus ist)
+            Das alles muss einmal oder mehrmal vorkommen
)            keine Ahnung ;-) siehe oben...
.*?          beliebige Zeichen (ein oder 0 mal...)
>            findet >
Tja, theoretisch funktioniert alles, aber ganz kapiert hab ichs noch nicht... ( oder ) oder ^

nochmal danke für eure hilfe ;-)

mfg
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Das was in den Klammern (...) kommt, wird bei findall zurückgegeben.
das ^ bedeutet not, also in dem Beispiel [^\s\"'>] bedeutet: nimm alles was kein Whitespace (Leerzeichen, Tab, Zeilenumbruch, ...), Anführungszeichen (doppelt oder einfach) oder das Grösserzeichen ist.
Das letzte ? kannst auch weglassen.


Gruß

Dookie
Antworten