如何在Python 3.x中禁用SSL检查?

21

我正在使用urllib.request.urlretrieve将文件下载到本地。

urllib.request.urlretrieve(url_string,file_name)

出现错误:

ssl.CertificateError未被用户代码处理 消息:主机名'foo.net'与'a248.e.akamai.net','.akamaihd.net','.akamaihd-staging.net','.akamaized.net','.akamaized-staging.net'中的任何一个都不匹配

如果您将URL复制到Chrome中,它会向您显示通知,并且您需要说一些类似于“继续访问该URL”的话。


@JoranBeasley,urllib.request.urlretrieve不接受verify关键字参数。也许您与requests混淆了。 - falsetru
2个回答

49

使用自定义的SSL上下文urllib.request.urlopen

import ssl
import urllib.request

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

with urllib.request.urlopen(url_string, context=ctx) as u, \
        open(file_name, 'wb') as f:
    f.write(u.read())

如果您使用 requests,也可以更简便地实现:

import requests

with open(file_name, 'wb') as f:
    resp = requests.get(url_string, verify=False)
    f.write(resp.content)

1
我猜第一个解决方案中有一些打字错误,这个可以正常工作 :D 使用urllib.request.urlopen(url_string, context=ctx)打开链接后,我们可以将内容写入文件中。 不过我不确定Python3中是否有requests库。 - Bing Gan
@BingGan,我修正了拼写错误。感谢您的反馈。requests支持Python 3.x。运行 pip install requests 安装它并获益吧. :) - falsetru
即使将 check_hostname=False 设置为假,我仍然收到“启用 check_hostname 时无法将 verify_mode 设置为 CERT_NONE。”的错误消息。有什么想法吗? - viveksinghggits
好的,所以我们必须在verify_mode之前设置check_hostname - viveksinghggits
1
可以使用shutil.copyfileobj(u, f)代替f.write(u.read()),以避免将整个内容加载到内存中。 - jfs

6

urllib.request.urlretrieve函数不接受任何SSL选项,但urllib.request.urlopen函数可以。

然而,你可以使用ssl.SSLContext()创建一个不安全的上下文,而不是使用ssl.create_default_context()创建一个安全的SSL上下文并使其不安全:

代码如下:

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

等同于:

ctx = ssl.SSLContext()
< p >< em >(对于Python版本小于3.5.3,请使用 ssl.SSLContext(ssl.PROTOCOL_TLSv1))

这使得代码变成了一个漂亮的一行:

import ssl
import urllib.request

with urllib.request.urlopen("https://wrong.host.badssl.com/", context=ssl.SSLContext()) as url:
    print(url.read())

ctx(第一个版本)提供了不支持的协议。 - James Hirschorn
@JamesHirschorn,你是什么意思?你是怎么得到那个错误的? - mx0
我使用您的代码遇到了错误,使用ctx的第一个定义和不同的url。所以:with urllib.request.urlopen(my_url, context=ctx) as url: print(url.read())我猜这个网站可能不支持最近的协议,即使证书验证关闭了? - James Hirschorn
是的,这个技巧是禁用证书的特定检查。但协议和密码仍然必须匹配。 - mx0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接