ใน 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 ที่เทียบเท่า (แสดงด้านล่าง) ทำงานได้ดี: import urllib2 req = urllib2.Request('yande.re') resp = urllib2.urlopen(req) resp.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 alert handshake failed (_ssl.c:748) - person MikeB; 12.08.2017

นี่เป็นเพราะ ข้อบกพร่องในการใช้งาน 1.x OpenSSL ในช่วงต้นของ การเข้ารหัสเส้นโค้งวงรี ลองดูส่วนที่เกี่ยวข้องของข้อยกเว้นให้ละเอียดยิ่งขึ้น:

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

นี่เป็นข้อผิดพลาดจากโค้ดไลบรารี OpenSSL พื้นฐานซึ่งเป็นผลมาจากการจัดการส่วนขยาย TLS รูปแบบ EC point ในทางที่ผิด วิธีแก้ปัญหาหนึ่งคือใช้วิธี 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