2012-05-21 734 views
7

Quiero abrir y leer https://yande.re/ con,, pero aparece un error de SSL . Puedo abrir y leer la página bien utilizando http.client con este código:En Python 3.2, puedo abrir y leer una página web HTTPS con http.client, pero urllib.request no abre la misma página

import http.client 

conn = http.client.HTTPSConnection('www.yande.re') 
conn.request('GET', 'https://yande.re/') 
resp = conn.getresponse() 
data = resp.read() 

Sin embargo, el siguiente código utilizando urllib.request falla:

import urllib.request 

opener = urllib.request.build_opener() 
resp = opener.open('https://yande.re/') 
data = resp.read() 

Me da el siguiente error: ssl.SSLError: [Errno 1] _ssl.c:392: error:1411809D:SSL routines:SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list. ¿Por qué puedo abrir la página con HTTPSConnection pero no con abridor.open?

Editar: aquí está mi versión de OpenSSL y el rastreo de su intención de https://yande.re/

>>> import ssl; ssl.OPENSSL_VERSION 
'OpenSSL 1.0.0a 1 Jun 2010' 
>>> import urllib.request 
>>> urllib.request.urlopen('https://yande.re/') 
Traceback (most recent call last): 
    File "<pyshell#3>", line 1, in <module> 
    urllib.request.urlopen('https://yande.re/') 
    File "C:\Python32\lib\urllib\request.py", line 138, in urlopen 
    return opener.open(url, data, timeout) 
    File "C:\Python32\lib\urllib\request.py", line 369, in open 
    response = self._open(req, data) 
    File "C:\Python32\lib\urllib\request.py", line 387, in _open 
    '_open', req) 
    File "C:\Python32\lib\urllib\request.py", line 347, in _call_chain 
    result = func(*args) 
    File "C:\Python32\lib\urllib\request.py", line 1171, in https_open 
    context=self._context, check_hostname=self._check_hostname) 
    File "C:\Python32\lib\urllib\request.py", line 1138, in do_open 
    raise URLError(err) 
urllib.error.URLError: <urlopen error [Errno 1] _ssl.c:392: error:1411809D:SSL routines:SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list> 
>>> 
+0

Puede pegar la salida de 'import ssl; ssl.OPENSSL_VERSION', y el resultado de 'urllib.request.urlopen ('https://yande.re/')' –

+0

FWIW, probablemente un punto de datos para la depuración. El equivalente de Python 2.7.x código (que se muestra a continuación) funciona bien: importa urllib2 req = urllib2.Request ('https://yande.re') resp = urllib2.urlopen (req) resp.read() – sateesh

+0

código para http.client es incorrecto . Usted podría querer decir: 'conn.request ('GET', '/')' – jfs

Respuesta

1

El problema se debe a los nombres de host que sea tu limosna en los dos ejemplos:

import http.client 
conn = http.client.HTTPSConnection('www.yande.re') 
conn.request('GET', 'https://yande.re/') 

y ...

import urllib.request 
urllib.request.urlopen('https://yande.re/') 

Tenga en cuenta que en el primer ejemplo, le está pidiendo al cliente que se conecte con el host: www.yande.re y en el segundo ejemplo, urllib primero analizará la url 'https://yande.re' y luego intente una solicitud en el host yande.re

Aunque www.yande.re y yande.re pueden resolverse en la misma dirección IP, desde la perspectiva del servidor web, estos son hosts virtuales diferentes. Supongo que tuvo un problema de configuración SNI en el lado de su servidor web. Al ver que la pregunta original fue publicada el 21 de mayo, y el certificado actual en yande.re comienza el 28 de mayo, ¿estoy pensando que ya corrigió este problema?

+1

'conn.request ('GET', '/')' – jfs

-1

Prueba esto:

import connection #imports connection 
import url 

url = 'http://www.google.com/'  
webpage = url.open(url) 

try: 
    connection.receive(webpage) 
except: 
    webpage = url.text('This webpage is not available!') 
    connection.receive(webpage) 
2

Qué casualidad! Estoy teniendo el mismo problema que tú, con una complicación adicional: estoy detrás de un proxy. Encontré esto bug report con respecto a https-not-working-with-urllib. Afortunadamente, publicaron una solución alternativa.

import urllib.request 
import ssl 

##uncomment this code if you're behind a proxy 
##https port is 443 but it doesn't work for me, used port 80 instead 

##proxy_auth = '{0}://{1}:{2}@{3}'.format('https', 'username', 'password', 
##    'proxy:80') 
##proxies = { 'https' : proxy_auth } 
##proxy = urllib.request.ProxyHandler(proxies) 
##proxy_auth_handler = urllib.request.HTTPBasicAuthHandler() 
##opener = urllib.request.build_opener(proxy, proxy_auth_handler, 
##          https_sslv3_handler) 

https_sslv3_handler = 
     urllib.request.HTTPSHandler(context=ssl.SSLContext(ssl.PROTOCOL_SSLv3)) 
opener = urllib.request.build_opener(https_sslv3_handler) 
urllib.request.install_opener(opener) 
resp = opener.open('https://yande.re/') 
data = resp.read().decode('utf-8') 
print(data) 

Por cierto, gracias por mostrar cómo utilizar el http.client. No sabía que hay otra biblioteca que se puede usar para conectarse a Internet. ;)

+0

Muchas gracias, esto en realidad me ha ayudado con un problema de urllib ligeramente diferente – Corvin

+0

Este fragmento de código no funciona para mí; Termino con una falla de handshake: "ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] error de handshake de alerta sslv3 (_ssl.c: 748)" – MikeB

2

Esto se debe a un bug in the early 1.x OpenSSL implementation of elliptic curve cryptography. Echar un vistazo más de cerca a la parte pertinente de la excepción:

_ssl.c:392: error:1411809D:SSL routines:SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list 

Este es un error del código de la biblioteca OpenSSL subyacente que es el resultado de un mal manejo de la extensión de formato de coma CE TLS. Una solución consiste en utilizar el método SSLv3 en lugar de SSLv23, la otra solución consiste en utilizar una especificación de conjunto de cifrado que deshabilita todas las suites de cifrado ECC (obtuve buenos resultados con ALL:-ECDH, utilice openssl ciphers para realizar pruebas). La solución es actualizar OpenSSL.

+0

¿podría especificar cómo es posible usar una especificación de serie de cifrado en el ejemplo del usuario? –

Cuestiones relacionadas