Seite 1 von 1

mehrere urlopen gleichzeitig ?

Verfasst: Dienstag 27. November 2007, 01:12
von debian75
salve,

ich möchte von ca. 20 verschiedenen seiten die lieferbarkeit von produkten abfragen, indem ich die html seiten parse.

ich habe das erst in php geschrieben, geht auch, ist aber sehr langsam....dauert gut 30 sekunden, weil das halt alles sequentiell gemacht wird.

ich habe gehört mit python kann man mehrere urls gleichzeitig öffnen und parsen, nennt sich wohl multithreading. leider finde ich nirgens ein beispiel.

hat jemand ein script an dem ich mich orientieren kann ? oder geht das auch ohne multithreading ?

thnx

d

Re: mehrere urlopen gleichzeitig ?

Verfasst: Dienstag 27. November 2007, 06:00
von gerold
debian75 hat geschrieben:ich habe gehört mit python kann man mehrere urls gleichzeitig öffnen und parsen, nennt sich wohl multithreading. leider finde ich nirgens ein beispiel.
Hallo debian75!

Willkommen im Python-Forum!

Ich sag's dir gleich vorab: Threading ist für den Anfang nicht einfach. Aber vielleicht kannst du trotzdem etwas damit anfangen.

Dieses Beispiel ist aber nicht ideal, da es genau so viele Threads öffnet, wie es URLs gibt. Und es versucht alle URLs gleichzeitig zu erreichen und die Daten zurück zu bekommen. Bei 30 URLs die gleichzeitig abgefragt werden, kann das evt. Probleme bereiten. Probier es einfach mal aus.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import urllib2
import threading
import time


lock = threading.Lock()


def download(url, retvals):
    
    try:
        html = urllib2.urlopen(url).read()
    except urllib2.URLError, exception:
        html = "ERROR: %s" % str(exception)
    lock.acquire()
    retvals.append((url, html))
    lock.release()


def main():
    urls = (
        "http://gerold.bcom.at/",
        "http://halvar.at/",
        "http://lugt.at/",
        "http://microsoft.de/",
        "http://www.python-forum.de/",
        "http://python.org/",
        "http://wallerforum.com/",
        #"http://log-in.fachdid.fu-berlin.de/Archiv/2001/2/Thema/", # braucht zu lange
    )
    retvals = []
    threads = []
    for url in urls:
        threads.append(
            threading.Thread(
                target = download, kwargs = dict(url = url, retvals = retvals)
            )
        )
        threads[-1].start()
        time.sleep(0.2)
    
    # Warten bis alle fertig sind
    for thread in threads:
        thread.join()
        
    for url, html in retvals:
        print url
        if html.startswith("ERROR"):
            print "Achtung Fehler!"
        print html[:100]
        print


if __name__ == "__main__":
    main()
Und lies dir die Hilfe zu den Modulen "thread" und "threading" genau durch. Und hier im Forum findest du auch einige Beispiele zum Threma "Threading". Z.B. hier: http://www.python-forum.de/topic-3869.html

mfg
Gerold
:-)

Verfasst: Dienstag 27. November 2007, 09:37
von debian75
hey, vielen dank. muss ich gleich mal ausprobieren wenn ich von der arbeit komme.

Verfasst: Dienstag 27. November 2007, 14:03
von debian75
hallo


ich nochmal. ich habe jetzt dieses script in die datei "m.py" kopiert. leider bekomme ich einen fehler wenn ich m.py über den browser aufrufen will.

"The server encountered an internal error or misconfiguration and was unable to complete your request."

----

Code: Alles auswählen

#!/usr/bin/env python 
# -*- coding: iso-8859-15 -*- 

import os
import urllib
import urllib2
import threading
import time
print 'Content-Type: text/html\n\n'

lock = threading.Lock() 


def download(url, retvals): 
    
    try: 
        html = urllib2.urlopen(url).read() 
    except urllib2.URLError, exception: 
        html = "ERROR: %s" % str(exception) 
    lock.acquire() 
    retvals.append((url, html)) 
    lock.release() 


def main(): 
    urls = ( 
        "http://www.google.com/", 
        "http://www.gmail.com/", 
        #"http://log-in.fachdid.fu-berlin.de/Archiv/2001/2/Thema/", # braucht zu lange 
    ) 
    retvals = [] 
    threads = [] 
    for url in urls: 
        threads.append( 
            threading.Thread( 
                target = download, kwargs = dict(url = url, retvals = retvals) 
            ) 
        ) 
        threads[-1].start() 
        time.sleep(0.2) 
    
    # Warten bis alle fertig sind 
    for thread in threads: 
        thread.join() 
        
    for url, html in retvals: 
        print url 
        if html.startswith("ERROR"): 
            print "Achtung Fehler!" 
        print html[:100] 
        print 

main()
----

was mach ich falsch ?

Edit by Gerold: Code-Tags gesetzt. Beim nächsten mal bitte selber machen.

Verfasst: Dienstag 27. November 2007, 14:37
von Dakre
hört sich so an als könnte es an der Konfiguration des Web Servers liegen? nutzt du Apache mit mod_python? oder hast du den python Interpreter einfach so installiert?

stimmt der Pfad #!/usr/bin/env python?

Verfasst: Dienstag 27. November 2007, 14:46
von debian75
ne, der pfad stimmt nicht, hab das aber in meinem script richtig:

#!/usr/bin/python


ja, der hoster den ich hab benutzt mod_python mit apache

Verfasst: Dienstag 27. November 2007, 14:46
von gerold
Hallo!

Du willst das also als CGI ausführen. Da kann vieles schief laufen. Zu niedere Python-Version. Falscher Pfad zu Python im Kopf. Falsches Encoding (aber nicht in diesem Fall). ...

- [wiki]CGI[/wiki]
- [wiki]Web-Skripte zum Laufen bringen[/wiki]

Vielleicht bekommst du eine bessere Fehlermeldung mit:

Code: Alles auswählen

import cgi
import cgitb; cgitb.enable()
im Kopf deines Programms.

Und dann noch dieser Hinweis: http://www.python-forum.de/faq.php#21

mfg
Gerold
:-)

Verfasst: Dienstag 27. November 2007, 14:58
von debian75
danke, ich les mich da mal durch. anbei mal meine ausgangslage, nicht lachen, ist erst mein zweiter tag mit python :)

das hier funktioniert so, ich will halt jetzt nur noch mehrere urls gleichzeitig losrennen lassen:

das script soll die lieferzeit von büchern verschiedener online shops prüfen:

Code: Alles auswählen

#!/usr/bin/python
#print 'Content-Type: text/html\n\n'
import os
import urllib
import urllib2
import threading
import time

print 'Content-Type: text/html\n\n'

#EAN ist sowas wie die ISBN nummer von einem buch
def geturltest(ean):
	url = 'http://www.foobar.ch/search.aspx?some=params'
	page = urllib.urlopen(url)
	pagedata = page.read()
	return pagedata

def strpos(string,search):
	pos = string.find(search)
	return pos

def test(string,pos):
	return string[pos+5:pos+12]


page = geturltest('9783280071465')
position = strpos(page,"Lieferzeit")
print test(page,position)

Verfasst: Dienstag 27. November 2007, 15:17
von gerold
Jetzt wirds ärgelich: http://www.python-forum.de/faq.php#21
Du kannst mit dem "Edit"-Button deinen Beitrag editieren.

Verfasst: Dienstag 27. November 2007, 15:45
von debian75
gerold hat geschrieben:Jetzt wirds ärgelich: http://www.python-forum.de/faq.php#21
Du kannst mit dem "Edit"-Button deinen Beitrag editieren.
sorry, hatte ich ned gesehen

Verfasst: Dienstag 27. November 2007, 15:55
von gerold
gerold hat geschrieben:Vielleicht bekommst du eine bessere Fehlermeldung mit:

Code: Alles auswählen

import cgi
import cgitb; cgitb.enable()
im Kopf deines Programms.
mfg
Gerold
:-)

Verfasst: Dienstag 27. November 2007, 15:57
von Leonidas
Oftmals hilft es auch in den `error.log` des Webservers reinzuschauen denn dort werden Fehlermeldungen von CGI-Skripten deponiert.

Verfasst: Donnerstag 13. Dezember 2007, 12:20
von debian75
uhm....neues problem.

ich benutze den code so ziemlich wie vorgeschlagen. nur, wenn ein server nicht erreichbar ist, dann blockiert er die weitere verarbeitung.

gibt es eine möglichkeite einem thread zu sagen, er solle es nur 5 sekunden versuchen und wenn er dann nicht fertig ist aufhören ?

weil sonst hängt mein programm wegen diesem einen thead.

Verfasst: Donnerstag 13. Dezember 2007, 16:22
von debian75
aha....scheint weniger trivial zu sein :)

keiner ne idee ?

Verfasst: Donnerstag 13. Dezember 2007, 16:28
von gerold
Hallo!

Das eingebaute Timeout ist, glaube ich, bei 30 Sekunden angesetzt. Mehr weiß ich jetzt auch nicht. Vielleicht hilft ein Blick in den Quellcode von urllib2.

mfg
Gerold
:-)

Verfasst: Freitag 14. Dezember 2007, 00:56
von Leonidas
Man muss über `settimeout()` auf das Socket-Objekt das Timeout verstellen.