timeout per urllib2.urlopen () in fase di pre Python 2.6 versioni
Domanda
Il urllib2 documentazione dice che timeout parametro è stato aggiunto in Python 2.6. Purtroppo la mia base di codice è stato in esecuzione su Python 2.5 e 2.4 piattaforme.
C'è un modo alternativo per simulare il timeout? Tutto quello che voglio fare è consentire il codice per parlare il server remoto per un importo fisso di tempo.
Forse qualsiasi alternativa libreria incorporata? (Non vuoi installare 3a parte, come pycurl)
Soluzione
è possibile impostare un timeout globale per tutte le operazioni di socket (comprese le richieste HTTP) utilizzando:
in questo modo:
import urllib2
import socket
socket.setdefaulttimeout(30)
f = urllib2.urlopen('http://www.python.org/')
In questo caso, la richiesta sarebbe urllib2 timeout dopo 30 secondi e un'eccezione di socket. (Questo è stato aggiunto in Python 2.3)
Altri suggerimenti
Con notevole irritazione, è possibile sostituire la classe httplib.HTTPConnection che l'urllib2.HTTPHandler utilizza.
def urlopen_with_timeout(url, data=None, timeout=None):
# Create these two helper classes fresh each time, since
# timeout needs to be in the closure.
class TimeoutHTTPConnection(httplib.HTTPConnection):
def connect(self):
"""Connect to the host and port specified in __init__."""
msg = "getaddrinfo returns an empty list"
for res in socket.getaddrinfo(self.host, self.port, 0,
socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
try:
self.sock = socket.socket(af, socktype, proto)
if timeout is not None:
self.sock.settimeout(timeout)
if self.debuglevel > 0:
print "connect: (%s, %s)" % (self.host, self.port)
self.sock.connect(sa)
except socket.error, msg:
if self.debuglevel > 0:
print 'connect fail:', (self.host, self.port)
if self.sock:
self.sock.close()
self.sock = None
continue
break
if not self.sock:
raise socket.error, msg
class TimeoutHTTPHandler(urllib2.HTTPHandler):
http_request = urllib2.AbstractHTTPHandler.do_request_
def http_open(self, req):
return self.do_open(TimeoutHTTPConnection, req)
opener = urllib2.build_opener(TimeoutHTTPHandler)
opener.open(url, data)
Credo che la scelta migliore è quella di patch (o di distribuire una versione locale del) la tua urllib2 con il cambiamento dal ramo 2.6 di manutenzione
Il file dovrebbe essere in /usr/lib/python2.4/urllib2.py
(su Linux e 2.4)
Io uso httplib dalla libreria standard. Ha una semplice API morto, ma gestisce solo http come è facile intuire. IIUC urllib utilizza httplib per implementare la roba http.
È necessario impostare timeout in due punti.
import urllib2
import socket
socket.setdefaulttimeout(30)
f = urllib2.urlopen('http://www.python.org/', timeout=30)
Bene, il modo in cui timeout è gestita sia in 2.4 o 2.6 è lo stesso. Se si apre il file in urllib2.py 2.6 u sarebbe vedere che prende un argomento extra come timeout e lo gestisce con il metodo socket.defaulttimeout () come detto è la risposta 1.
Così davvero non è necessario aggiornare l'urllib2.py in questo caso.