Anfängerfrage zu Regular Expressions

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
Jurudoca
User
Beiträge: 23
Registriert: Dienstag 26. Juli 2011, 13:58

Hallo Leute,
bin ziemlich neu dabei und habe eine Frage zu folgendem Code, der die Links einer Seite (NICHT!) ausgeben soll:

Code: Alles auswählen

from httplib import *
import re
def getLinks(url):
    verb = HTTPConnection(url)
    verb.request('GET','/')
    antw = verb.getresponse()
    html = antw.read()

    p = re.compile('(?<=href=")(.*?)(?=")')
    link_matches = p.findall(html)
    for a in link_matches:
        if a != re.compile('(?<=href=")(.*?)(?=")'):
            print a
    #print link_matches

getLinks('www.spiegel.de')
Warum gibt python mir keine leere Liste zurück, wenn ich über das "for Konstrukt" das Suchmuster wieder negativ als Filter verwende (oder besser gesagt...verwenden will!). Was macht Python hier?

Mein Ziel ist es, alle Links auszugeben, bloss nicht die, die auf die Seite selbst zeigen. Um das aber zu verstehen, wollte ich erst mal dieses Verhalten untersuchen ;-P

Vielen Dank...
Jurudoca
Zuletzt geändert von Anonymous am Donnerstag 18. August 2011, 15:55, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Sinnvollerweise parst man HTML-Seiten mit einem entsprechenden Parser. lxml oder html5lib o.ä. Damit kannst Du Dir leicht alle Links rausfiltern und dann kommst Du ohne regExp an den Wert des href-Attributs. Bei diesem musst Du dann gucken, wie du die URL zerlegst.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Jurudoca hat geschrieben:

Code: Alles auswählen

    p = re.compile('(?<=href=")(.*?)(?=")')
    link_matches = p.findall(html)
    for a in link_matches:
        if a != re.compile('(?<=href=")(.*?)(?=")'):
            print a
Schau dir mal an, was du da eigentlich vergleichst. Du vergleichst ein kompiliertes Pattern mit einem String.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

In specifications, Murphy's Law supersedes Ohm's.
Jurudoca
User
Beiträge: 23
Registriert: Dienstag 26. Juli 2011, 13:58

Danke für die schnellen Anworten!
@/me : an welcher Stelle kompiliert er das Pattern? *aufSchlauchSteh*...Das soll er ja nur in bezug auf a..?
@ hyperion danke für den Hinweis, werde mir die Libraries gleich anschauen...

Grüße
Jurudoca
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Jurudoca hat geschrieben:an welcher Stelle kompiliert er das Pattern? *aufSchlauchSteh*...Das soll er ja nur in bezug auf a..?
Genau hier:

Code: Alles auswählen

if a != re.compile('(?<=href=")(.*?)(?=")'):
Jurudoca
User
Beiträge: 23
Registriert: Dienstag 26. Juli 2011, 13:58

Die Documentation von html5lib ist ja echst spartanisch und die Beispiele funktionieren bei mir nicht sonderlich gut:

Code: Alles auswählen

import html5lib
f = open("http://www.spiegel.de/index.html")
doc = html5lib.parse(f)
gibt bei mir die Fehlermeldung:
f = open("http://www.spiegel.de/index.html")
IOError: [Errno 22] invalid mode ('r') or filename: 'http://www.spiegel.de/index.html'

Was stimmt da nicht?

Liebe Grüße
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Das sagt die Doku:

Code: Alles auswählen

import html5lib
f = open("mydocument.html")
doc = html5lib.parse(f)
Nun vergleich das mal und schau dir die Fehlermeldung an.

Tipp: Du willst `urllib(2).urlopen` nutzen, nicht `open`.
Jurudoca
User
Beiträge: 23
Registriert: Dienstag 26. Juli 2011, 13:58

@ me: dank Dir. ich glaube ich weiss was du meinst. Der Ausdruck steht für sich und macht rein gar nichts ;-P ? Wie kann ich erreichen, das er was macht? Mit re.search?
@cofi: uuuaah okay...das ist das lokale file! 'grrr'. Danke für den Hinweis! Kann man denn überhaupt mit html5lib eine Seite ähnlich wie mit urllib2.urlopen öffnen, oder ist html5lib gar nicht dafür gedacht, sondern quasi "nur" zur sinnvollen Weiterverarbeitung?

Danke Euch...das macht das Python erlernen echt angenehmer!
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Nein, html5lib ist "nur" ein Parser. Warum sollte es sich das auch aufbinden, wenn es eine schon eine funktionierende Infrastruktur in der Stdlib gibt?
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Jurudoca hat geschrieben:@ me: dank Dir. ich glaube ich weiss was du meinst. Der Ausdruck steht für sich und macht rein gar nichts ;-P ? Wie kann ich erreichen, das er was macht? Mit re.search?
Ich verstehe dein Problem gerade nicht. Du hast compile doch drei Zeilen darüber bereits korrekt verwendet.
Jurudoca
User
Beiträge: 23
Registriert: Dienstag 26. Juli 2011, 13:58

/me hat geschrieben: Ich verstehe dein Problem gerade nicht. Du hast compile doch drei Zeilen darüber bereits korrekt verwendet.
Dann kann ich das wohl nicht gut ausdrücken. Vielleicht hilft es, nochmal im Code zu sagen, was ich erreichen will:

Code: Alles auswählen

p = re.compile('(?<=href=")(.*?)(?=")')
    link_matches = p.findall(html)
    for a in link_matches:
        if a != re.compile('(?<=href=")(.*?)(?=")'): # HIER WILL ICH, DASS a GEPRÜFT WIRD, OB ES MIT DEM RE.PATTERN ÜBEREINSTIMMT UND WENN JA, DANN PRINTET... DA ABER DAS MUSTER AUF ALLE LINKS ZUTRIFFT, DÜRFTE ER NICHTS AUSGEBEN ODER?...UND DAS FUNKTIONIERT NICHT 
            print a
Danke für die Mühe ;-)
Jurudoca
User
Beiträge: 23
Registriert: Dienstag 26. Juli 2011, 13:58

cofi hat geschrieben:Nein, html5lib ist "nur" ein Parser. Warum sollte es sich das auch aufbinden, wenn es eine schon eine funktionierende Infrastruktur in der Stdlib gibt?
Habe dann das was Hyperion gesagt hat falsch verstanden:
hyperion hat geschrieben:Sinnvollerweise parst man HTML-Seiten mit einem entsprechenden Parser. lxml oder html5lib o.ä. Damit kannst Du Dir leicht alle Links rausfiltern und dann kommst Du ohne regExp an den Wert des href-Attributs. Bei diesem musst Du dann gucken, wie du die URL zerlegst.
Das gilt fürs parsen aber nicht fürs auslesen...Vestehe. Danke!
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Jurudoca hat geschrieben:

Code: Alles auswählen

p = re.compile('(?<=href=")(.*?)(?=")')
    link_matches = p.findall(html)
    for a in link_matches:
        if a != re.compile('(?<=href=")(.*?)(?=")'): # HIER WILL ICH, DASS a GEPRÜFT WIRD, OB ES MIT DEM RE.PATTERN ÜBEREINSTIMMT UND WENN JA, DANN PRINTET... DA ABER DAS MUSTER AUF ALLE LINKS ZUTRIFFT, DÜRFTE ER NICHTS AUSGEBEN ODER?...UND DAS FUNKTIONIERT NICHT
Dann kommen wir mal zu einer Verständnisfrage. Was glaubst du, was dir re.compile(...) als Ergebnis liefert?

Falls du meinst, dass es die gefundenen Muster sind, dann überlege dir, wofür du weiter oben findall(...) verwendet hast und denk noch mal darüber nach.
Jurudoca
User
Beiträge: 23
Registriert: Dienstag 26. Juli 2011, 13:58

/me hat geschrieben: Dann kommen wir mal zu einer Verständnisfrage. Was glaubst du, was dir re.compile(...) als Ergebnis liefert?
Okay sehe gerade ist ein Pattern Objekt <type '_sre.SRE_Pattern'> ;-P...
/me hat geschrieben: Falls du meinst, dass es die gefundenen Muster sind, dann überlege dir, wofür du weiter oben findall(...) verwendet hast und denk noch mal darüber nach.
Schwere Geburt...Danke für Deine Hilfe und das Fragen ;-):

Hier das Ergebnis, wie ich es mir vorgestellt habe:

Code: Alles auswählen

from httplib import *
import re
def getLinks(url):
    verb = HTTPConnection(url)
    verb.request('GET','/')
    antw = verb.getresponse()
    html = antw.read()

    p = re.compile('(?<=href=")(.*?)(?=")')
    link_matches = p.findall(html)
    for a in link_matches:
        i = p.findall(a)
        print i

getLinks('www.spiegel.de')
BlackJack

@Jurudoca: Was genau denkst Du was Du innerhalb der Schleife machst? Beziehungsweise was denkst du was `link_matches` enthält?

Und ich würde auch eher einen HTML-Parser verwenden, statt das mit regulären Ausdrücken zu lösen.
Jurudoca
User
Beiträge: 23
Registriert: Dienstag 26. Juli 2011, 13:58

Haha...tja die schleife ist irgendwie unsinnig *bg* Danke für den Hinweis
Die HTML Parser sind glaube ich noch ein bisschen zu hoch für mich...Habe schon mit urllib2 herumgespielt...aber da brauche ich noch Zeit...

geht auch so:

Code: Alles auswählen

from httplib import *
import re
def getLinks(url):
    verb = HTTPConnection(url)
    verb.request('GET','/')
    antw = verb.getresponse()
    html = antw.read()

    p = re.compile('(?<=href=")(.*?)(?=")')
    link_matches = p.findall(html)
    print link_matches
    absurd = p.findall(str(link_matches))
    print absurd
   
getLinks('www.spiegel.de')
jetzt muss ich es irgenwie hinbekommen, dass er die Links der eigenen Seite nicht mehr anzeigt, sondern nur noch die externen...das schaff ich hoffentlich bis heute Abend noch ;) Mein Ergebnis poste ich nochmal... Aber der Thread ist sowieso schon so lang...
BlackJack

@Jurudoca: Das „geht” nur bedingt. HTML kann man nicht zuverlässig mit so einfachen regulären Ausdrücken parsen. Der Ausdruck den Du verwendest, kann sowohl Links übersehen, als auch falsche Treffer liefern. Es wird zum Beispiel nicht beachtet ob das Muster innerhalb eines Tags steht. Vorzugsweise eines Tags was nicht zufällig auskommentiert ist. Auf der anderen Seite kann der Wert des Attributs auch in einfache statt doppelter Anführungszeichen eingefasst sein, oder auch in gar keine. Das ist dann zwar kein gültiges HTML, aber solche kaputten Sachen findet man im Netz zuhauf.
Jurudoca
User
Beiträge: 23
Registriert: Dienstag 26. Juli 2011, 13:58

@ Blackjack Ja das kann natürlich sein!
Wie würdest Du mit HTML Parsern vorgehen, um ein Programm zu schreiben was Links auf definierten Seiten zu externen Seiten ausgeben soll...
Welche Libs würdest du in welcher Reihenfolge dafür verwenden...?
Das Ding ist ja...ich will ja nicht html ausgeben sondern auslesen...

Grüße
Jurudoca
BlackJack

@Jurudoca: Ich würde `lxml.html` oder `BeautifulSoup` zum Parsen und extrahieren der Links verwenden. Dann `urllib2.urlparse()` um die URLs in ihre Bestandteile zu zerlegen. Für die Daten sollte man Quelltext schreiben können, der interne von externen Links unterscheidet.
Antworten