Table of Contents
レスポンスのフック
>>> import requests
>>> def on_response(response:requests.models.Response, **send_args):
... print(response, send_args)
>>> requests.get('https://httpbin.org/get', hooks={'response': on_response})
<Response [200]> {'timeout': None, 'cert': None, 'stream': False, 'verify': True, 'proxies': OrderedDict()}
<Response [200]>
>>> requests.get('https://httpbin.org/redirect/1', hooks={'response': on_response})
<Response [302]> {'timeout': None, 'cert': None, 'stream': False, 'verify': True, 'proxies': OrderedDict()}
<Response [200]> {'timeout': None, 'stream': False, 'proxies': OrderedDict(), 'cert': None, 'verify': True}
<Response [200]>
>>> requests.get('https://httpbin.org/status/404', hooks={'response': on_response})
<Response [404]> {'timeout': None, 'cert': None, 'stream': False, 'verify': True, 'proxies': OrderedDict()}
<Response [404]>
>>> requests.get('https://httpbin.org/status/503', hooks={'response': on_response})
<Response [503]> {'timeout': None, 'cert': None, 'stream': False, 'verify': True, 'proxies': OrderedDict()}
<Response [503]>
リダイレクトされたときも呼び出されるので便利です。ここで HTML パーサーなどを呼び出して response オブジェクトの属性に設定したりします。大雑把ですが 50x なときなどに time.sleep() して回避するのも楽です。
セッションを使うと簡単にデフォルトパラメーターとして設定できます。
>>> with requests.Session() as session:
... session.hooks['response'] = on_response
... session.get('https://httpbin.org/get')
<Response [200]> {'timeout': None, 'cert': None, 'stream': False, 'verify': True, 'proxies': OrderedDict()}
<Response [200]>
30x による自動リダイレクトを無効化する
>>> requests.get('https://httpbin.org/redirect/1', hooks={'response': on_response}, allow_redirects=False)
<Response [302]> {'timeout': None, 'cert': None, 'stream': False, 'verify': True, 'proxies': OrderedDict()}
<Response [302]>
v2.9.1 ではデフォルトパラメーターとして設定することはできないようです。
リトライパラメーターをカスタマイズする
正気とは思えない設定の http サーバーを相手するときに特定のステータスコードでリトライさせるようにできます。
>>> with requests.Session() as session:
... http_adapter = requests.adapters.HTTPAdapter(
... max_retries=requests.packages.urllib3.util.Retry(total=10, status_forcelist=[500, 404, 302]),
... )
... session.mount('https://', http_adapter)
... session.mount('http://', http_adapter)
mount() の第一パラメーター prefix は内部で長い順にソートされて adapter の検索に使用されます。
PyQuery で iterate
for x in pq(‘selector’) すると x が lxml.html.HtmlElement になってとても面倒なので、items() か each() を使うといいようです。
requests + PyQuery
こんな感じで適当です。
def process_response(response, **send_args):
import pyquery
if response.headers.get('Content-Type').startswith('text/html')
response.doc = pyquery.PyQuery(response.content)
response.doc.make_links_absolute(response.url)
with requests.Session() as session:
session.hooks['response'] = process_response