2008-12-27 10 views
7

Tengo un script que me gustaría seguir usando, pero parece que tengo que encontrar alguna solución para un error en Python 3, o rebajar de nuevo a 2.6, y tener que degradar otros scripts también ..¿Cómo descargar un archivo a través de http con autorización en python 3.0, trabajando alrededor de los errores?

Esperemos que alguien aquí ya haya logrado encontrar una solución alternativa.

El problema es que debido a los nuevos cambios en Python 3.0 con respecto a los bytes y las cadenas, no todo el código de la biblioteca es aparentemente probado.

Tengo un script que descarga una página de un servidor web. Esta secuencia de comandos pasó un nombre de usuario y una contraseña como parte de la url en Python 2.6, pero en Python 3.0, esto ya no funciona.

Por ejemplo, esto:

import urllib.request; 
url = "http://username:[email protected]/file"; 
urllib.request.urlretrieve(url, "temp.dat"); 

falla con esta excepción:

Traceback (most recent call last): 
    File "C:\Temp\test.py", line 5, in <module> 
    urllib.request.urlretrieve(url, "test.html"); 
    File "C:\Python30\lib\urllib\request.py", line 134, in urlretrieve 
    return _urlopener.retrieve(url, filename, reporthook, data) 
    File "C:\Python30\lib\urllib\request.py", line 1476, in retrieve 
    fp = self.open(url, data) 
    File "C:\Python30\lib\urllib\request.py", line 1444, in open 
    return getattr(self, name)(url) 
    File "C:\Python30\lib\urllib\request.py", line 1618, in open_http 
    return self._open_generic_http(http.client.HTTPConnection, url, data) 
    File "C:\Python30\lib\urllib\request.py", line 1576, in _open_generic_http 
    auth = base64.b64encode(user_passwd).strip() 
    File "C:\Python30\lib\base64.py", line 56, in b64encode 
    raise TypeError("expected bytes, not %s" % s.__class__.__name__) 
TypeError: expected bytes, not str 

Aparentemente, base64-codificación necesita ahora bytes en y emite una cadena, y por lo tanto urlretrieve (o algo de código en él) que construye una cadena de nombre de usuario: contraseña e intenta codificar64 a base de esto para una autorización simple, falla.

Si en lugar de tratar de usar urlopen, así:

import urllib.request; 
url = "http://username:[email protected]/file"; 
f = urllib.request.urlopen(url); 
contents = f.read(); 

Entonces se produce un error con esta excepción:

Traceback (most recent call last): 
    File "C:\Temp\test.py", line 5, in <module> 
    f = urllib.request.urlopen(url); 
    File "C:\Python30\lib\urllib\request.py", line 122, in urlopen 
    return _opener.open(url, data, timeout) 
    File "C:\Python30\lib\urllib\request.py", line 359, in open 
    response = self._open(req, data) 
    File "C:\Python30\lib\urllib\request.py", line 377, in _open 
    '_open', req) 
    File "C:\Python30\lib\urllib\request.py", line 337, in _call_chain 
    result = func(*args) 
    File "C:\Python30\lib\urllib\request.py", line 1082, in http_open 
    return self.do_open(http.client.HTTPConnection, req) 
    File "C:\Python30\lib\urllib\request.py", line 1051, in do_open 
    h = http_class(host, timeout=req.timeout) # will parse host:port 
    File "C:\Python30\lib\http\client.py", line 620, in __init__ 
    self._set_hostport(host, port) 
    File "C:\Python30\lib\http\client.py", line 632, in _set_hostport 
    raise InvalidURL("nonnumeric port: '%s'" % host[i+1:]) 
http.client.InvalidURL: nonnumeric port: '[email protected]' 

Al parecer, el análisis de URL en esta "biblioteca siguiente de recuperación url gen" doesn No sé qué hacer con el nombre de usuario y las contraseñas en la url.

¿Qué otras opciones tengo?

Respuesta

20

directa de los documentos Py3k: http://docs.python.org/dev/py3k/library/urllib.request.html#examples

import urllib.request 
# Create an OpenerDirector with support for Basic HTTP Authentication... 
auth_handler = urllib.request.HTTPBasicAuthHandler() 
auth_handler.add_password(realm='PDQ Application', 
          uri='https://mahler:8092/site-updates.py', 
          user='klem', 
          passwd='kadidd!ehopper') 
opener = urllib.request.build_opener(auth_handler) 
# ...and install it globally so it can be used with urlopen. 
urllib.request.install_opener(opener) 
urllib.request.urlopen('http://www.example.com/login.html') 
+0

¿Quiso publicar esa contraseña? De lo contrario, sugiero eliminar la respuesta y publicar una nueva con datos ficticios allí. Gracias por la respuesta, parece prometedor. –

+3

Directo desde los documentos de Python: P –

+4

Klem probablemente está bastante molesto si esa es su verdadera contraseña :) –

0

Mi consejo sería mantener su 2. * rama como su rama de producción hasta que pueda conseguir las cosas 3.0 ordenados.

Voy a esperar un tiempo antes de pasar a Python 3.0. Parece que hay mucha gente apurada, pero solo quiero que todo esté resuelto y una buena selección de bibliotecas de terceros. Esto puede tomar un año, puede llevar 18 meses, pero la presión para "actualizar" es realmente baja para mí.

Cuestiones relacionadas