1. 程式人生 > >Mac OS X 使用python urllib 模組 通過ssl訪問報錯 urllib.error.URLError

Mac OS X 使用python urllib 模組 通過ssl訪問報錯 urllib.error.URLError

今天是我第一次使用python的urllib.request.openurl 功能獲取網頁資訊,程式碼如下

# 獲取網路檔案
from urllib.request import urlopen
with urlopen(url='https://book.douban.com/subject/1005022/') as f:
for line in f.readlines():
print(line, end='')

一個4行的程式碼,完成了java中幾十行的功能,但是。。。。
別人執行一點問題都沒有,為什麼我的執行起來報錯了?
錯誤程式碼基本如下(解決以後才寫的,所以錯誤程式碼也不是我的,錯誤程式碼執行的機器是):

Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1318, in do_open
encode_chunked=req.has_header('Transfer-encoding'))
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1239, in request
self._send_request(method, url, body, headers, encode_chunked)

File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1285, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1234, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)

File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1026, in _send_output
self.send(msg)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 964, in send
self.connect()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 1400, in connect
server_hostname=server_hostname)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 407, in wrap_socket
_context=self, _session=session)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 814, in __init__
self.do_handshake()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 1068, in do_handshake
self._sslobj.do_handshake()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 689, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/a-nguyen/Downloads/EzSorses/APAsauce.py", line 3, in <module>
u1 = urllib.request.urlopen(url)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 223, in urlopen
return opener.open(url, data, timeout)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 526, in open
response = self._open(req, data)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 544, in _open
'_open', req)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 504, in _call_chain
result = func(*args)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1361, in https_open
context=self._context, check_hostname=self._check_hostname)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1320, in do_open
raise URLError(err)
urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777)>
解決方案是:通過控制檯執行/Application/Python 3.x(版本號)/install certificates.command
指令為: /Applications/Python\ 3.7/Install\ Certificates.command
 
在/Application/python 3.7/ReadMe.rtf 中提到了這個問題,原文為:

Certificate verification and OpenSSL 

This variant of Python 3.7 includes its own private copy of OpenSSL 1.1.0.  The deprecated Apple-supplied OpenSSL libraries are no longer used.  This means that the trust certificates in system and user keychains managed by the Keychain Access application and the security command line utility are no longer used as defaults by the Python ssl module.  A sample command script is included in /Applications/Python 3.7 to install a curated bundle of default root certificates from the third-party certifi package (https://pypi.org/project/certifi/).  If you choose to use certifi, you should consider subscribing to the project's email update service to be notified when the certificate bundle is updated.

python 3.7 的該版本包括了他自己私有的OpenSSL 1.1.0 副本。被棄用的蘋果支援的 OpenSSL 庫已經不再使用。這意味著系統認證和使用者通過金鑰訪問應用或控制檯進行金鑰管理已經不再用於預設的python ssl 模版。一個簡單的命令列檔案已經包括在/Applications/python3.7下,用於為預設的root認證從第三部分的certifi包中安裝輔助包,如果你選擇適用certifi,你應該思考訂閱專案的email升級服務,關注捆綁包的升級。

官方網站對此問題的描述和解決:https://bugs.python.org/issue28150