将 certifi 模块与 urllib2 一起使用?

Using certifi module with urllib2?

我有 ,这似乎是由于 urllib2 无法访问系统的证书存储。

要解决此问题,一种可能的解决方案是使用 certifi 模块使用 pycurl 下载 https 网页。以下是这样做的示例:

def download_web_page_with_curl(url_website):
    from pycurl import Curl, CAINFO, URL
    from certifi import where
    from cStringIO import StringIO

    response = StringIO()
    curl = Curl()
    curl.setopt(CAINFO, where())
    curl.setopt(URL, url_website)
    curl.setopt(curl.WRITEFUNCTION, response.write)
    curl.perform()
    curl.close()
    return response.getvalue()

有没有办法将 certifi 与 urllib2 一起使用(以类似于上面的 pycurl 示例的方式),这将允许我下载 https 站点?或者,是否有另一种可行的基于 urllib2 的解决方法,可以在不影响安全性的情况下解决权限问题?

扩展注释以使用 requests(基于 urllib3):

def download_web_page_with_requests(url_website):
    import requests

    r = requests.get(url_website)
    return r.text

这比其他任何事情都容易得多,并且可以独立于平台自己的证书列表正确处理 SSL 验证。如果找到 certifi,requests 将自动使用它。如果不是,它会默默地回退到一组更有限的、可能更旧的内置根证书。如果确保使用 certifi 对您很重要,您可以这样做:

r = requests.get(url_website, verify=certifi.where())

请注意,上面的代码没有执行您可能应该执行的错误检查。所以我要指出,requests.get() 可能会针对无效的 ULR、无法访问的站点、通信错误和失败的认证验证抛出许多异常,因此您应该准备好捕捉和处理这些异常。如果它确实成功地与服务器对话,但是服务器 returns 一个非 OK 状态代码(例如一个不存在的页面),那么就不会抛出异常,所以你也想检查 r.status_code==200。

建议根据我的其他回答使用请求。但是,要回答如何使用 urllib2 执行此操作的原始问题:

import urllib2
import certifi
def download_web_page_with_urllib2(url_website):
    t = urllib2.urlopen(url_website, cafile=certifi.where())
    return t.read()
text = download_web_page_with_urllib2('https://www.google.com/')

有关错误检查的相同建议也适用。