Cartopy 无法下载 shapefile,因为证书不受信任

Cartopy can't download shapefiles because a certificate is not trusted

我需要用cartopy来画图。

运行 来自他们网站的例子

import cartopy.crs as ccrs
import matplotlib.pyplot as plt

ax = plt.axes(projection=ccrs.PlateCarree())
ax.coastlines()

plt.show()

当 cartopy 尝试下载形状文件时,我收到一个与无法验证的证书相关的非常长的错误。 (请参阅下面的错误并忽略文件路径。我删除了特定于我的硬盘驱动器的内容。它在虚拟环境中)。

如果我转到 URL 它正在尝试下载 (https://naciscdn.org/naturalearth/110m/physical/ne_110m_coastline.zip),我可以下载 zip 文件。检查证书表明它是由 Let's Encrypt 分发的,有效期还有几个月。收到错误后,我什至去下载了证书,将其添加到我的系统密钥链并将信任级别设置为始终信任。

我在 macOS Catalina 10.15.4 上使用 Python 3.7.3。

有人知道我该如何解决这个问题吗?

/env/lib/python3.7/site-packages/cartopy/io/__init__.py:260: DownloadWarning: Downloading: https://naciscdn.org/naturalearth/110m/physical/ne_110m_coastline.zip
  warnings.warn('Downloading: {}'.format(url), DownloadWarning)
Traceback (most recent call last):
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1317, in do_open
    encode_chunked=req.has_header('Transfer-encoding'))
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/http/client.py", line 1229, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/http/client.py", line 1275, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/http/client.py", line 1224, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/http/client.py", line 1016, in _send_output
    self.send(msg)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/http/client.py", line 956, in send
    self.connect()
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/http/client.py", line 1392, in connect
    server_hostname=server_hostname)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/ssl.py", line 412, in wrap_socket
    session=session
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/ssl.py", line 853, in _create
    self.do_handshake()
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/ssl.py", line 1117, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/env/lib/python3.7/site-packages/matplotlib/backends/backend_macosx.py", line 74, in _draw
    self.figure.draw(renderer)
  File "/env/lib/python3.7/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/env/lib/python3.7/site-packages/matplotlib/figure.py", line 1736, in draw
    renderer, self, artists, self.suppressComposite)
  File "/env/lib/python3.7/site-packages/matplotlib/image.py", line 137, in _draw_list_compositing_images
    a.draw(renderer)
  File "/env/lib/python3.7/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/env/lib/python3.7/site-packages/cartopy/mpl/geoaxes.py", line 479, in draw
    return matplotlib.axes.Axes.draw(self, renderer=renderer, **kwargs)
  File "/env/lib/python3.7/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/env/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 2630, in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
  File "/env/lib/python3.7/site-packages/matplotlib/image.py", line 137, in _draw_list_compositing_images
    a.draw(renderer)
  File "/env/lib/python3.7/site-packages/matplotlib/artist.py", line 38, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/env/lib/python3.7/site-packages/cartopy/mpl/feature_artist.py", line 155, in draw
    geoms = self._feature.intersecting_geometries(extent)
  File "/env/lib/python3.7/site-packages/cartopy/feature/__init__.py", line 302, in intersecting_geometries
    return super(NaturalEarthFeature, self).intersecting_geometries(extent)
  File "/env/lib/python3.7/site-packages/cartopy/feature/__init__.py", line 110, in intersecting_geometries
    return (geom for geom in self.geometries() if
  File "/env/lib/python3.7/site-packages/cartopy/feature/__init__.py", line 286, in geometries
    name=self.name)
  File "/env/lib/python3.7/site-packages/cartopy/io/shapereader.py", line 295, in natural_earth
    return ne_downloader.path(format_dict)
  File "/env/lib/python3.7/site-packages/cartopy/io/__init__.py", line 222, in path
    result_path = self.acquire_resource(target_path, format_dict)
  File "/env/lib/python3.7/site-packages/cartopy/io/shapereader.py", line 350, in acquire_resource
    shapefile_online = self._urlopen(url)
  File "/env/lib/python3.7/site-packages/cartopy/io/__init__.py", line 261, in _urlopen
    return urlopen(url)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 222, in urlopen
    return opener.open(url, data, timeout)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 525, in open
    response = self._open(req, data)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 543, in _open
    '_open', req)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 503, in _call_chain
    result = func(*args)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1360, in https_open
    context=self._context, check_hostname=self._check_hostname)
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 1319, in do_open
    raise URLError(err)
urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)>

我有一个非常相似的问题。我按照 .
解决了它 就我而言,我不需要 root 权限,因为我使用的是 conda 环境。
所以我得到了带有证书的目录:

$ dirname $(echo $REQUESTS_CA_BUNDLE)
/etc/ssl/certs

以及从 openssl_capath 创建 link 的目录来自:

$ python -c 'import ssl; print(ssl.get_default_verify_paths())'
DefaultVerifyPaths(cafile='/home/<user>/miniconda3/envs/<env_name>/ssl/cert.pem', capath='/home/<user>/miniconda3/envs/<env_name>/ssl/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/home/<user>/miniconda3/envs/<env_name>/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/home/<user>/miniconda3/envs/<env_name>/ssl/certs')

所以解决方案是:

ln -s /etc/ssl/certs/ /home/<user>/miniconda3/envs/<env_name>/ssl/

(替换为您的用户和环境名称)。

(Ubuntu 20.04.3 LTS,Python 3.10.2,cartopy 0.20.2,Spyder IDE 5.2.2)