В Python 3.2 я могу открыть и прочитать веб-страницу HTTPS с помощью http.client, но urllib.request не может открыть ту же страницу

Я хочу открыть и прочитать https://yande.re/ с помощью urllib.request, но получаю сообщение об ошибке SSL. Я могу открыть и прочитать страницу, используя http.client с этим кодом:

import http.client

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

Однако следующий код с использованием urllib.request не работает:

import urllib.request

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

Выдает следующую ошибку: ssl.SSLError: [Errno 1] _ssl.c:392: error:1411809D:SSL routines:SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list. Почему я могу открыть страницу с помощью HTTPSConnection, но не opener.open?

Изменить: вот моя версия OpenSSL и трассировка попытки открыть 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>
>>> 

person user1406902    schedule 21.05.2012    source источник
comment
Можете ли вы вставить вывод import ssl; ssl.OPENSSL_VERSION и результат urllib.request.urlopen('https://yande.re/')   -  person Burhan Khalid    schedule 21.05.2012
comment
FWIW, вероятно, точка данных для отладки. Эквивалентный код Python 2.7.x (показан ниже) работает нормально: a>) соотв = urllib2.urlopen(req) соотв.read()   -  person sateesh    schedule 21.05.2012
comment
код для http.client неверен. Возможно, вы имели в виду: conn.request('GET', '/')   -  person jfs    schedule 05.09.2012


Ответы (4)


Какое совпадение! У меня та же проблема, что и у вас, с дополнительным осложнением: я за прокси. Я нашел этот отчет об ошибке, касающийся https-not-working-with-urllib. К счастью, они опубликовали обходной путь.

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)

Кстати, спасибо, что показали, как использовать http.client. Я не знал, что есть еще одна библиотека, которую можно использовать для подключения к Интернету. ;)

person Annie Lagang    schedule 04.12.2012
comment
Большое спасибо, это действительно помогло мне с немного другой проблемой urllib. - person Corvin; 27.09.2013
comment
Этот фрагмент кода у меня не работает; В итоге я получаю ошибку рукопожатия: ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ошибка рукопожатия предупреждения sslv3 (_ssl.c:748) - person MikeB; 12.08.2017

Это связано с ошибкой в ​​ранней реализации OpenSSL 1.x криптография на эллиптических кривых. Присмотритесь к соответствующей части исключения:

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

Это ошибка базового кода библиотеки OpenSSL, которая является результатом неправильного обращения с расширением TLS формата точек EC. Одним из обходных путей является использование метода SSLv3 вместо метода SSLv23, другим обходным путем является использование спецификации набора шифров, которая отключает все наборы шифров ECC (у меня были хорошие результаты с ALL:-ECDH, используйте openssl ciphers для тестирования). Исправление заключается в обновлении OpenSSL.

person Daniel Roethlisberger    schedule 20.12.2012
comment
не могли бы вы указать, как можно использовать спецификацию комплекта шифров в примере пользователя? - person mic.sca; 10.12.2014

Проблема связана с именами хостов, которые вы указали в двух примерах:

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

и...

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

Обратите внимание, что в первом примере вы просите клиента установить соединение с хостом: www.yande.re, а во втором примере urllib сначала проанализирует URL-адрес «https://yande.re», а затем попытается запрос на хост yande.re

Хотя www.yande.re и yande.re могут разрешаться в один и тот же IP-адрес, с точки зрения веб-сервера это разные виртуальные хосты. Я предполагаю, что у вас возникла проблема с конфигурацией SNI на стороне вашего веб-сервера. Учитывая, что исходный вопрос был опубликован 21 мая, а текущий сертификат на yande.re начинается 28 мая, я думаю, что вы уже исправили эту проблему?

person parselmouth    schedule 30.05.2012

Попробуй это:

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)
person Python    schedule 22.08.2012