米扑代理官方博客,在编写代理使用示例的过程中,发现访问未经验证的https网站时,会抛出异常:

Traceback (most recent call last):
  File "/Users/homer/Documents/workspace/MimvpProxyDemo/Python2/mimvp-proxy-python2.py", line 89, in <module>
    test_http(proxy_https, mimvp_url2)    
  File "/Users/homer/Documents/workspace/MimvpProxyDemo/Python2/mimvp-proxy-python2.py", line 42, in test_http
    f = opener.open(mimvp_url, timeout=30)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 431, in open
    response = self._open(req, data)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 449, in _open
    '_open', req)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 409, in _call_chain
    result = func(*args)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1240, in https_open
    context=self._context)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1197, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)>

 

上面异常信息的核心提示为:

urllib2.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)>

 

操作系统: Mac OS X 

Python 版本:

$ python 
Python 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 12:39:47) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin

 

问题的原因是 “SSL: CERTIFICATE_VERIFY_FAILED”

Python 升级到 2.7.9 之后引入了一个新特性,当使用urllib.urlopen打开一个 https 链接时,会验证一次 SSL 证书

Python 2.7.9 之前的版本,不支持 ssl._create_unverified_context,需要另外找办法,请见本米扑博客的下文

而当目标网站使用的是自签名的证书时就会抛出一个 urllib2.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)> 的错误消息,详细信息可以在这里查看(https://www.python.org/dev/peps/pep-0476/

 

解决方案包括下列两种方式:

方式1. 使用ssl创建未经验证的上下文,在urlopen中传入上下文参数

import ssl
import urllib2

context = ssl._create_unverified_context()
print urllib2.urlopen("https://proxy.mimvp.com", context=context).read()

 

方式2. 全局取消证书验证

import ssl

ssl._create_default_https_context = ssl._create_unverified_context
# ssl._create_default_https_context = ssl._create_unverified_context()

 

Python 2.7.9 之前的版本,不支持 ssl._create_unverified_context,会抛出异常:

AttributeError: 'module' object has no attribute '_create_unverified_context'

Python 2.7.9 之前的版本,解决办法如下:

import ssl

## Python 2.7.9 以前的版本用法
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode=ssl.CERT_NONE

 

至此,问题圆满解决!