源自于前几天对一批转录本的批量化操作的一些记录。
即想要通过 Python 在线获取某个转录本对应的基因 Symbol 时,发现出现 SSL 无法获取本地证书:unable to get local issuer certificate (_ssl.c:1056)!
>>> from Bio import SeqIO>>> from Bio import Entrez>>> Entrez.email = "A.N.Other@example.com">>> records = SeqIO.parse(Entrez.efetch(id='NM_001009537.4', db="nucleotide", rettype="gb", retmode="text"), "gb")Traceback (most recent call last):File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/urllib/request.py", line 1317, in do_openencode_chunked=req.has_header('Transfer-encoding'))File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/http/client.py", line 1229, in requestself._send_request(method, url, body, headers, encode_chunked)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/http/client.py", line 1275, in _send_requestself.endheaders(body, encode_chunked=encode_chunked)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/http/client.py", line 1224, in endheadersself._send_output(message_body, encode_chunked=encode_chunked)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/http/client.py", line 1016, in _send_outputself.send(msg)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/http/client.py", line 956, in sendself.connect()File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/http/client.py", line 1392, in connectserver_hostname=server_hostname)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/ssl.py", line 412, in wrap_socketsession=sessionFile "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/ssl.py", line 853, in _createself.do_handshake()File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/ssl.py", line 1117, in do_handshakeself._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 "<stdin>", line 1, in <module>File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/Bio/Entrez/__init__.py", line 184, in efetchreturn _open(cgi, variables, post=post)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/Bio/Entrez/__init__.py", line 543, in _openhandle = _urlopen(cgi)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/urllib/request.py", line 222, in urlopenreturn opener.open(url, data, timeout)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/urllib/request.py", line 525, in openresponse = self._open(req, data)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/urllib/request.py", line 543, in _open'_open', req)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/urllib/request.py", line 503, in _call_chainresult = func(*args)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/urllib/request.py", line 1360, in https_opencontext=self._context, check_hostname=self._check_hostname)File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/urllib/request.py", line 1319, in do_openraise URLError(err)urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)>
根据网络上的解析,当使用 urllib.urlopen 打开一个 https 链接时,会验证一次 SSL 证书。而当目标网站使用的是自签名的证书时就会抛出如下异常:
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
解决方法也很简单,下面是个人简单总结的 3 种常用解决方法。
方法一,全局取消证书验证
>>> import ssl>>> ssl._create_default_https_context = ssl._create_unverified_context
方法二,指定位置安装证书
查看证书默认位置。
>>> import ssl>>> print(ssl.get_default_verify_paths())DefaultVerifyPaths(cafile=None, capath='/Bioinfo/Pipeline/SoftWare/LibDependence/openssl-1.1.1/ssl/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/Bioinfo/Pipeline/SoftWare/LibDependence/openssl-1.1.1/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/Bioinfo/Pipeline/SoftWare/LibDependence/openssl-1.1.1/ssl/certs')
由于在 openssl_cafile 中指定的 ca 文件(cert.pem)不存在,所以导致上面的错误。
下载 ca 文件,将下载的 ca 文件放到 openssl_cafile 指定位置。注意,如果放到 openssl_capath 目录下还会出现类似的问题,一定要放到 openssl_cafile 指定的位置。
$ cd /Bioinfo/Pipeline/SoftWare/LibDependence/openssl-1.1.1/ssl$ wget http://curl.haxx.se/ca/cacert.pem -O cert.pem --no-check-certificate
方法三,设置环境变量
也可以参考 stackoverflow 上的做法,通过修改下面环境变量的方式解决(亲测可行)。
export SSL_CERT_FILE=/usr/local/etc/openssl/cert.pemexport REQUESTS_CA_BUNDLE=/usr/local/etc/openssl/cert.pem
最后,问题解决。
>>> from Bio import SeqIO>>> from Bio import Entrez>>> Entrez.email = "A.N.Other@example.com">>> records = SeqIO.parse(Entrez.efetch(id='NM_001009537.4', db="nucleotide", rettype="gb", retmode="text"), "gb")>>> for record in records:... for feature in record.features:... if feature.type == "gene":... print(feature.qualifiers['gene'])...['Zfp799']
