Python requests SSLError: EOF occurred in violation of protocol
とあるs付きのAPIにリクエストを投げた時に発生したエラー_φ(・_・
- python 2.7.10
- opelssl 1.0.1e
- requests 2.8.1
In [21]: r = requests.get(url) --------------------------------------------------------------------------- SSLError Traceback (most recent call last) <ipython-input-21-0aec23ab0de0> in <module>() ----> 1 r = requests.get(url) /root/.pyenv/versions/2.7.10/envs/pydata_env_2.7.10/lib/python2.7/site-packages/requests/api.pyc in get(url, params, **kwargs) 67 68 kwargs.setdefault('allow_redirects', True) ---> 69 return request('get', url, params=params, **kwargs) 70 71 /root/.pyenv/versions/2.7.10/envs/pydata_env_2.7.10/lib/python2.7/site-packages/requests/api.pyc in request(method, url, **kwargs) 48 49 session = sessions.Session() ---> 50 response = session.request(method=method, url=url, **kwargs) 51 # By explicitly closing the session, we avoid leaving sockets open which 52 # can trigger a ResourceWarning in some cases, and look like a memory leak /root/.pyenv/versions/2.7.10/envs/pydata_env_2.7.10/lib/python2.7/site-packages/requests/sessions.pyc in request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json) 466 } 467 send_kwargs.update(settings) --> 468 resp = self.send(prep, **send_kwargs) 469 470 return resp /root/.pyenv/versions/2.7.10/envs/pydata_env_2.7.10/lib/python2.7/site-packages/requests/sessions.pyc in send(self, request, **kwargs) 574 575 # Send the request --> 576 r = adapter.send(request, **kwargs) 577 578 # Total elapsed time of the request (approximately) /root/.pyenv/versions/2.7.10/envs/pydata_env_2.7.10/lib/python2.7/site-packages/requests/adapters.pyc in send(self, request, stream, timeout, verify, cert, proxies) 431 except (_SSLError, _HTTPError) as e: 432 if isinstance(e, _SSLError): --> 433 raise SSLError(e, request=request) 434 elif isinstance(e, ReadTimeoutError): 435 raise ReadTimeout(e, request=request) SSLError: EOF occurred in violation of protocol (_ssl.c:590)
使われるSSLのバージョンの問題らしい。
requestsで使われるのは基底となるurllib3の実装によるようなので、特定のバージョンを使いたい場合は、下記のようにHTTPAdapterのサブクラスを作って、ssl_versionを明示するようにするとのこと。
今回は、ssl_version=ssl.PROTOCOL_TLSv1 とすることでうまくいった。
In [28]: from requests.adapters import HTTPAdapter In [29]: from requests.packages.urllib3.poolmanager import PoolManager In [30]: import ssl In [31]: class MyAdapter(HTTPAdapter): ....: def init_poolmanager(self, connections, maxsize, block=False): ....: self.poolmanager = PoolManager(num_pools=connections, ....: maxsize=maxsize, ....: block=block, ....: ssl_version=ssl.PROTOCOL_TLSv1) ....: In [32]: import requests In [33]: s = requests.Session() In [34]: s.mount('https://', MyAdapter()) In [35]: r = s.get(url)
参考
Curl, Python, PHP で HTTPS 接続する際固まるサイトがあるので、TLS1.2 を使わないようにする | ytyng.com
Choosing The SSL Version In Python Requests • Lukasa's Echochamber
Advanced Usage — Requests 2.8.1 documentation
openssl - Python Requests requests.exceptions.SSLError: [Errno 8] _ssl.c:504: EOF occurred in violation of protocol - Stack Overflow
OpenSSL 1.0.1c and TLSv1 Handshake Failures · Issue #1083 · kennethreitz/requests · GitHub