Endlosschleife aber warum?

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
Sync32
User
Beiträge: 141
Registriert: Mittwoch 27. Januar 2010, 12:42

Dienstag 6. Juli 2010, 15:34

Hallo.
Bekomme komischerweise immer eine Dauerschleife:

Code: Alles auswählen

....
for line in url:  
    pos = line.find("href")

    while (pos != -1):
        pos2 = line[pos+6:].find("\"")
        print line[pos+6:pos+6+pos2]
        #file.write(line[pos+6:pos+6+pos2])
        #file.write("\n")
        pos = line[pos+6:].find("href")
....	

Aber ich weiß nicht wieso?
Wenn die Methode find() nichts findet, gibt sie den Wert "-1" zurück.
Der Code ist - denke ich mal - selbsterklärend:
- Ein Quelltext wird Zeile für Zeile durchgefiltert und nach html-Links durchsucht
- Wenn in einer Zeile ein href gefunden wurde, wird der abschließende " gesucht
- Somit habe ich die Anfangsposition (pos) und die Endposition (pos2) des Linkes und kann ihn denn per ...[pos:pos2] ausgeben

Nun kommen wir zum eigentlichen Grund der Schleife: Wenn er ein Link gefunden hat, soll er ja nicht aufhören sondern in der Zeile weitersuchen, denn rechts vom Link könnten ja noch mehr Links stehen. Deshalb soll er die ganze suche nochmal machen bloß nicht wieder von anfangan sondern von der Position an, wo der letzte Link geendet hat also pos2. So soll er die Links von links nach rechts abfrühstücken bis die Suche irgendwann "-1" returnt (wenn kein Link mehr in der Zeile ist) und dann die Schleife verlassen.
Doch leider funktioniert ddas so nciht und ich weiß nciht warum.
Er gibt mir irgendwie die ein und selbe quelltext-codestelle (noch nciht mal erklärlich warum die) aus und wiederholt diese endlos.
lunar

Dienstag 6. Juli 2010, 15:58

Verwende doch einfach einen fertigen HTML-Parser zum Auslesen der Links. lxml.html ist empfehlenswert, das bietet komfortable Methoden, um über alle Links im Dokument zu iterieren.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Dienstag 6. Juli 2010, 16:22

lunar hat geschrieben:Verwende doch einfach einen fertigen HTML-Parser zum Auslesen der Links.
Mit dem aus der Standard-Lib geht's ungefähr so.
Das Beispiel sammelt auch gleich allen Text aus den links (d.h. <a href=""...></a>-tags), andere Tags darin werden ignoriert.

hth, Jörg

edit: kurze Erklärung eingefügt.
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
Sync32
User
Beiträge: 141
Registriert: Mittwoch 27. Januar 2010, 12:42

Mittwoch 7. Juli 2010, 09:00

Danke für die Antworten aber mich würde schon interessieren, warum meine simple Lösung nicht funktioniert. :(
Kann das nicht nachvollziehen.
Trichter
User
Beiträge: 45
Registriert: Montag 20. April 2009, 10:21

Mittwoch 7. Juli 2010, 09:35

Hast du dir schonmal die Werte ausgeben lassen, die beim Durchlaufen der while-Schleife in pos gespeichert werden?
Vielleicht hilft es den Startindex beim Suchen nach "href" in der while-Schleife um 1 zu erhöhen. Dadurch beginnt die Suche an einer Stelle, an der du nicht Gefahr läufst dein letztes gefundenes "href" nochmal zu finden.

Also

Code: Alles auswählen

pos = line[pos+7:].find("href")
statt

Code: Alles auswählen

pos = line[pos+6:].find("href")
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Mittwoch 7. Juli 2010, 09:36

@OP:
Wenn ich deine Lösung auf die Testdaten aus meinem Beispiel loslasse (genauer: auf "TESTDATA.splitlines()") funktioniert dein Code.
Hast du in deinen Daten irgendwelche 'ungewöhnlichen' Zeilenumbrüche (innerhalb von Tags)?
Hast du deine Daten mit "datei.read()" eingelesen statt einfach über die Datei zu iterieren? (Was ist dein 'url'?)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7477
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Mittwoch 7. Juli 2010, 09:42

Sync32 hat geschrieben:Danke für die Antworten aber mich würde schon interessieren, warum meine simple Lösung nicht funktioniert. :(
Kann das nicht nachvollziehen.
Prinzipiell schon eine gute Einstellung, den Fehler analysieren zu wollen. Allerdings habe ich so den Eindruck, dass Du dann die sinnvollere Lösung nicht umsetzen wolen würdest, frei nach dem Motto: Was läuft, das läuft.

Wir haben doch Deine ganzen Dateien nicht; also wird der Hund in einem Spezialfall begraben liegen. So aufwendig scheint der Code ja nicht gerade. Gib Dir doch mal die Werte von pos aus - denn augenscheinlich wird das eben niemals "-1". Das Debuggen kann Dir hier keiner abnehmen... zumal es wohl recht einfach ist ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Mittwoch 7. Juli 2010, 09:54

Code: Alles auswählen

def test(data=TESTDATA.splitlines()):
    OFFSET = len("href=\"")
    for line in data:
        head = line.find("href")
        while True:
            tail = line[head + OFFSET:].find("\"")
            print "link:", line[head + OFFSET: head + OFFSET + tail]
            tmp = line[head + OFFSET:].find("href")
            if tmp == -1: break
            head += tmp + OFFSET
Kann man hier erkennen, was das Problem war?

Edit: Das funktioniert so auch mit "test( [TESTDATA.replace("\n", "")])" - d.h. mehreren Links in einer Zeile

hth, Jörg
Sync32
User
Beiträge: 141
Registriert: Mittwoch 27. Januar 2010, 12:42

Mittwoch 7. Juli 2010, 10:05

Also ich lese einfach den Quelltext einer Website ein und will dort die Links rausfiltern:
Hier nochmal der komplette Quelltext:

Code: Alles auswählen

import urllib
url = urllib.urlopen("http://www.google.de")
file = open("C:/quelltext.txt", "a")
for line in url:   
    pos = line.find("href")

    while (pos != -1):
        pos2 = line[pos+6:].find("\"")
        print line[pos+6:pos+6+pos2]
        #file.write(line[pos+6:pos+6+pos2])
        #file.write("\n")
        pos = line[pos+6:].find("href")      

        
url.close()
file.close()
print "Fertig!"
Hast du dir schonmal die Werte ausgeben lassen, die beim Durchlaufen der while-Schleife in pos gespeichert werden?
Ja und da zeigt er mir auch an: -1 (kein weitere gefunden) oder z.B. 168
Von daher weiß ich nicht, warum es da irgendwie Probleme gibt.
Verwende doch einfach einen fertigen HTML-Parser zum Auslesen der Links. lxml.html ist empfehlenswert,
Danke das ist nett gemeint. :) Wollte mir - um auch praktische Erfahrung zu bekommen - selber nen kleinen Crawler basteln. :)

Edit:
Darf ich mal fragen, was das genau bewirkt/macht:
test(data=TESTDATA.splitlines())
Ist mir als Pythonanfänger noch nicht ganz klar.

Achja @besserwisser:

Code: Alles auswählen

#....
        head = line.find("href")
        while True:
#....
Warauf bezieht sich das true? Weiß Python das line.find() true sein muss?


Edit2:
Besserwisser, hab meinen Quelltext entsprechend nach deinem mal angepasst, Funktioniert zwar auch nicht ganz aber besser:
- keine Endlosschleife mehr
- erkennt alle alle Links (auch wenn er sie nicht komplett ausgibt und paar Zeichen abschneidet
- und er gibt noch paar andere Quelltextstellen (die keine Links sind) aus.
Zuletzt geändert von Sync32 am Mittwoch 7. Juli 2010, 10:24, insgesamt 1-mal geändert.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Mittwoch 7. Juli 2010, 10:24

Da steht nicht "test(data=TESTDATA.splitlines())", da steht "def test(data=TESTDATA.splitlines()):" - wird im Tutorial bei "Funktionen" erklärt.
Sync32 hat geschrieben:Warauf bezieht sich das true? Weiß Python das line.find() true sein muss?
Da steht "while True:" - das wäre eine Endlosschleife (ohne das "if...: break" weiter unten) "Wiederhole solange True Wahr ist"
Sync32 hat geschrieben:Wollte mir [...]selber nen kleinen Crawler basteln
Mach das nach dem Tutorial...
Trichter
User
Beiträge: 45
Registriert: Montag 20. April 2009, 10:21

Mittwoch 7. Juli 2010, 10:32

Habs mir mal angeschaut.
Du darfst an die Funktion find nicht den geslicten string übergeben, damit die indices stimmen.
Stattdessen musst du die Position an der die Suche im String fortgesetzt werden soll als weiteren Parameter an find übergeben.
So müsste es funktionieren:

Code: Alles auswählen

import urllib
url = urllib.urlopen("http://www.google.de")
for line in url:
    pos = line.find("a href=")
    #print line

    while (pos != -1):
        pos2 = line.find("\"",pos+8)
        print line[pos+8:pos2]
        #file.write(line[pos+6:pos+6+pos2])
        #file.write("\n")
        pos = line.find("a href=",pos+1)


url.close()
print "Fertig!"
Außerdem habe ich jetzt speziell nach "a href=" gesucht, da google scheinbar auch noch ein paar andere stylesheets oder was auch immer verwendet in denen die Zeichenkette "href" vorkommt.
Sync32
User
Beiträge: 141
Registriert: Mittwoch 27. Januar 2010, 12:42

Mittwoch 7. Juli 2010, 10:42

b.esser-wisser hat geschrieben:

Code: Alles auswählen

def test(data=TESTDATA.splitlines()):
    OFFSET = len("href=\"")
    for line in data:
        head = line.find("href")
        while True:
            tail = line[head + OFFSET:].find("\"")
            print "link:", line[head + OFFSET: head + OFFSET + tail]
            tmp = line[head + OFFSET:].find("href")
            if tmp == -1: break
            head += tmp + OFFSET
Kann man hier erkennen, was das Problem war?

Edit: Das funktioniert so auch mit "test( [TESTDATA.replace("\n", "")])" - d.h. mehreren Links in einer Zeile

hth, Jörg
Hey dein Quelltext war fast richtig.
Ich musste nur in der Schleife als erstes noch ein:
if head == -1: break (falls in der ersten Zeile nichts gefunden wurde)
einbinden.

Trichter (und allen anderen auch, auch dir vielen Dank. Nun weiß ich auch wo mein eigentlicher Fehler war.

Mfg und drückt Deutschland heute die Daumen ;)
Antworten