En Python 3.2, puedo abrir y leer una página web HTTPS con http.client, pero urllib.request no puede abrir la misma página

Quiero abrir y leer https://yande.re/ con urllib.request , pero urllib.request un error de SSL. Puedo abrir y leer la página simplemente usando http.client con este código:

 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 que usa 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 opener.open?

Edición: Aquí está mi versión de OpenSSL y el rastreo de intentar abrir 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 "", line 1, in  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:  >>> 

¡Qué casualidad! Tengo el mismo problema que usted, con una complicación adicional: estoy detrás de un proxy. Encontré este informe de error relacionado con https-not-working-with-urllib. Afortunadamente, publicaron una solución.

 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 usar http.client . No sabía que hay otra biblioteca que se puede usar para conectarse a Internet. 😉

Esto se debe a un error en la implementación 1.x OpenSSL de la criptografía de curva elíptica . Eche un vistazo más de cerca a la parte relevante de la excepción:

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

Esto es un error del código de la biblioteca OpenSSL subyacente que es el resultado de un manejo inadecuado de la extensión TLS del formato de punto EC Una solución es usar el método SSLv3 en lugar del método SSLv23, la otra solución es usar una especificación de conjunto de cifrado que deshabilita todos los conjuntos de cifrado ECC (tuve buenos resultados con ALL:-ECDH , use openssl ciphers para realizar pruebas). La solución es actualizar OpenSSL.

El problema se debe a los nombres de host que da 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 haga una conexión con el host: http://www.yande.re y en el segundo ejemplo, urllib primero analizará la url ‘https://yande.re’ y luego intentará una solicitud en el host yande.re

Aunque http://www.yande.re y yande.re pueden resolverse con la misma dirección IP, desde la perspectiva del servidor web, estos son hosts virtuales diferentes. Supongo que tuvo un problema de configuración de SNI en el lado de su servidor web. Al ver que la pregunta original se publicó el 21 de mayo y el certificado actual en yande.re comienza el 28 de mayo, ¿creo que ya solucionó este problema?

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)