Knihovna requests je určená pro HTTP požadavky (klienty). Přestože vytvářet HTTP požadavky jde i bez requests, pomocí standardní knihovny Pythonu, requests mají mnohem lidštější rozhraní a používají se mnohem jednodušeji.
Instaluje se standardním způsobem:
$ python -m pip install requests
Budeme předpokládat, že znáte alespoň základy HTTP protokolu, a vrhneme se rovnou na příklad.
Pokud základy neznáte, můžete se podívat na shrnutí pro začátečníky, které vysvětluje vše potřebné.
>>> import getpass
>>> import requests
>>> username = input('Username: ')
Username: hroncok
>>> password = getpass.getpass()
Password:
>>> r = requests.get('https://api.github.com/user', auth=(username, password))
>>> r.status_code
200
>>> r.headers['content-type']
'application/json; charset=utf8'
>>> r.encoding
'utf-8'
>>> r.text
'{"login":"hroncok"...'
>>> r.json()
{'avatar_url': 'https://avatars.githubusercontent.com/u/2401856?v=3', ...}
Tento příklad pracuje přímo se jménem a heslem. To se většinou nedělá a webové API to často ani nepodporují. Pokud na GitHub používáte dvoufaktorovou autentizaci, příklad nebude fungovat.
Příklady použití pro další HTTP metody najdete v dokumentaci.
Hlavně v budoucnu se nám bude hodit použití tzv. session.
Session má několik výhod. První je, že využívá na pozadí jedno otevřené HTTP spojení a poskytuje tak při více sousledných požadavcích výrazné zrychlení.
Dále pak session automaticky ukládá cookies a je možné u ní nastavit výchozí hlavičky.
Zkuste si cookies vyzkoušet s httpbin.org – službou k testování HTTP dotazů:
>>> session = requests.Session()
>>> session.get('http://httpbin.org/cookies/set/mipyt/best')
<Response [200]>
>>> r = session.get('http://httpbin.org/cookies')
>>> r.json()
{'cookies': {'mipyt': 'best'}}
>>> session.headers.update({'x-test': 'true'})
>>> r = session.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
>>> r.json()
{'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Cookie': 'mipyt=best', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.19.1', 'X-Test': 'true', 'X-Test2': 'true'}}
Podíváme se teď, podobně jako v úvodním příkladu, na GitHub API, které má poměrně jednoduchou autentizaci (od GitHubu přímo získáte token). Stačí jít do nastavení a vyrobit nový token (zatím není třeba zaškrtávat žádná oprávnění).
Ochrana přihlašovacích tokenů
Váš token je něco jako vaše heslo. Nikomu je nesmíte ukazovat a nesmíte jej dát do Gitu. Stane-li se přesto, že se k němu dostane někdo nepovolaný, můžete jej v nastavení opět smazat.
Pomocí tokenu můžete z GitHubu získávat informace. Prozatím token nastavte do proměnné, později jej schováme například do konfiguračního souboru.
Tímto kódem lze například získat popis přihlášeného uživatele, tedy sebe sama.
>>> token = 'd7313dab254b7fd0d0f3ec3cbf754b3abce462d5'
>>> session = requests.Session()
>>> session.headers = {'User-Agent': 'Python'}
>>> def token_auth(req):
... req.headers['Authorization'] = f'token {token}'
... return req
...
>>> session.auth = token_auth
>>> r = session.get('https://api.github.com/user')
>>> r.json()
Funkce session.auth
v příkladu výše je autentizační funkce,
která nějakým způsobem modifikuje HTTP požadavek za účelem autentizace,
většinou přidává specifické hlavičky (jak je tomu i zde).
Lze ji nastavit buďto na celé session nebo předat argumentem auth
s každým
požadavkem.
Existují předpřipravené funkce v modulu requests.auth
, například
requests.auth.HTTPBasicAuth
provádí základní HTTP přihlášení.
Dle specifikace zakóduje jméno a heslo pomocí
algoritmu base64 a přidá hlavičku Authorization
.
Základní HTTP přihlášení
je tak běžné, že pro něj Requests mají zkratku –
místo HTTPBasicAuth
se dá použít i dvojice (jméno, heslo):
>>> requests.get('https://httpbin.org/basic-auth/AzureDiamond/hunter2',
auth=requests.auth.HTTPBasicAuth('AzureDiamond', 'hunter2'))
>>>
>>> requests.get('https://httpbin.org/basic-auth/AzureDiamond/hunter2',
auth=('AzureDiamond', 'hunter2'))
Všimněte si také hlavičky User-Agent
.
Ta je potřeba při komunikaci s GitHub API explicitně nastavit.
Nastavení na objektu session zajistí, že tato hlavička
bude ve všech požadavcích.
Pokud budete chtít něco provést, například dát hvězdičku repozitáři s těmito
materiály, musíte tokenu nastavit patřičné oprávnění
(u hvězdičky je to public_repo
).
To se dělá přes nastavení na GitHubu.
Hvězdičku pak přidáte takto:
>>> r = session.put('https://api.github.com/user/starred/pyvec/naucse.python.cz')
>>> r.text
''
Jak vidíte, API nevrací žádný text (žádné tělo odpovědi). Můžete ale zkontrolovat návratový stav:
>>> r.status_code
204
Případně vyhodit výjimku, pokud je stavový kód divný (např 404 Nenalezeno, 401 Chybí oprávnění apod.):
>>> r.raise_for_status()
Pokud hvězdičku chcete odebrat, použijte metodu DELETE. My ale věříme, že ji odebrat nechcete :)
Dokumentace ke GitHub API.
Když ukládáte skript do gitu, mějte na paměti, že tokeny a klíče do něj nikdy nepatří. Můžete je uložit do konfiguračního souboru, který bude gitem ignorován, například takhle:
[github]
token = d7313dab254b7fd0d0f3ec3cbf754b3abce462d5
A následně konfiguraci načtete pomocí modulu configparser:
>>> import configparser
>>> config = configparser.ConfigParser()
>>> with open('auth.cfg') as f:
... config.read_file(f)
>>> config['github']['token']
'd7313dab254b7fd0d0f3ec3cbf754b3abce462d5'
Do souboru .gitignore
pak musíte přidat název ignorovaného souboru, např.:
auth.cfg
Ověřte si, že git soubor auth.cfg
opravdu ignoruje, t.j. soubor se neukáže
ve výstupu git status
.
Jelikož ostatní tento konfigurační soubor neuvidí,
je vhodné jim vysvětlit, jak takový soubor (s jejich údaji) vytvořit.
Můžete například vložit do gitu soubor auth.cfg.sample
s vymyšlenými údaji, či příklad uvést v README.
{ "data": { "sessionMaterial": { "id": "session-material:2019/mipyt-zima:requests-click:1", "title": "Requests – Weboví klienti", "html": "\n \n \n\n <h1>requests</h1>\n<p>Knihovna requests je určená pro HTTP požadavky (klienty).\nPřestože vytvářet HTTP požadavky jde i bez requests, pomocí standardní knihovny\nPythonu, requests mají mnohem lidštější rozhraní a používají se mnohem\njednodušeji.</p>\n<p>Instaluje se standardním způsobem:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">$ </span>python -m pip install requests\n</pre></div><p>Budeme předpokládat, že znáte alespoň základy HTTP protokolu,\na vrhneme se rovnou na příklad.</p>\n<div class=\"admonition note\"><p>Pokud základy neznáte, můžete se podívat na\n<a href=\"/2019/mipyt-zima/fast-track/http/\">shrnutí pro začátečníky</a>,\nkteré vysvětluje vše potřebné.</p>\n</div><div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"kn\">import</span> <span class=\"nn\">getpass</span>\n<span class=\"gp\">>>> </span><span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"gp\">>>> </span><span class=\"n\">username</span> <span class=\"o\">=</span> <span class=\"nb\">input</span><span class=\"p\">(</span><span class=\"s1\">'Username: '</span><span class=\"p\">)</span>\n<span class=\"go\">Username: hroncok</span>\n<span class=\"gp\">>>> </span><span class=\"n\">password</span> <span class=\"o\">=</span> <span class=\"n\">getpass</span><span class=\"o\">.</span><span class=\"n\">getpass</span><span class=\"p\">()</span>\n<span class=\"go\">Password: </span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">'https://api.github.com/user'</span><span class=\"p\">,</span> <span class=\"n\">auth</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">username</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"p\">))</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">status_code</span>\n<span class=\"go\">200</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">headers</span><span class=\"p\">[</span><span class=\"s1\">'content-type'</span><span class=\"p\">]</span>\n<span class=\"go\">'application/json; charset=utf8'</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">encoding</span>\n<span class=\"go\">'utf-8'</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">text</span>\n<span class=\"go\">'{"login":"hroncok"...'</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">json</span><span class=\"p\">()</span>\n<span class=\"go\">{'avatar_url': 'https://avatars.githubusercontent.com/u/2401856?v=3', ...}</span>\n</pre></div><div class=\"admonition note\"><p>Tento příklad pracuje přímo se jménem a heslem.\nTo se většinou nedělá a webové API to často ani nepodporují.\nPokud na GitHub používáte dvoufaktorovou autentizaci, příklad nebude fungovat.</p>\n</div><p>Příklady použití pro další HTTP metody najdete v <a href=\"http://docs.python-requests.org/en/master/user/quickstart/\">dokumentaci</a>.</p>\n<h2>Použití session</h2>\n<p>Hlavně v budoucnu se nám bude hodit použití tzv.\n<a href=\"http://docs.python-requests.org/en/master/user/advanced/#session-objects\"><em>session</em></a>.</p>\n<p>Session má několik výhod.\nPrvní je, že využívá na pozadí jedno otevřené HTTP spojení a poskytuje tak\npři více sousledných požadavcích výrazné zrychlení.</p>\n<p>Dále pak session automaticky ukládá <em>cookies</em> a je možné u ní nastavit výchozí\nhlavičky.</p>\n<p>Zkuste si <em>cookies</em> vyzkoušet s <a href=\"http://httpbin.org\">httpbin.org</a> – službou\nk testování HTTP dotazů:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">session</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">Session</span><span class=\"p\">()</span>\n<span class=\"gp\">>>> </span><span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">'http://httpbin.org/cookies/set/mipyt/best'</span><span class=\"p\">)</span>\n<span class=\"go\"><Response [200]></span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">'http://httpbin.org/cookies'</span><span class=\"p\">)</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">json</span><span class=\"p\">()</span>\n<span class=\"go\">{'cookies': {'mipyt': 'best'}}</span>\n<span class=\"gp\">>>> </span><span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">headers</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">({</span><span class=\"s1\">'x-test'</span><span class=\"p\">:</span> <span class=\"s1\">'true'</span><span class=\"p\">})</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">'http://httpbin.org/headers'</span><span class=\"p\">,</span> <span class=\"n\">headers</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s1\">'x-test2'</span><span class=\"p\">:</span> <span class=\"s1\">'true'</span><span class=\"p\">})</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">json</span><span class=\"p\">()</span>\n<span class=\"go\">{'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Cookie': 'mipyt=best', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.19.1', 'X-Test': 'true', 'X-Test2': 'true'}}</span>\n</pre></div><h2>GitHub API</h2>\n<p>Podíváme se teď, podobně jako v úvodním příkladu, na <a href=\"https://developer.github.com/v3\">GitHub API</a>,\nkteré má poměrně jednoduchou autentizaci (od GitHubu přímo\nzískáte token). Stačí jít do <a href=\"https://github.com/settings/tokens\">nastavení</a> a vyrobit nový token\n(zatím není třeba zaškrtávat žádná oprávnění).</p>\n<div class=\"admonition warning\"><p class=\"admonition-title\">Ochrana přihlašovacích tokenů</p>\n<p>Váš token je něco jako vaše heslo.\nNikomu je nesmíte ukazovat a nesmíte jej dát do Gitu.\nStane-li se přesto, že se k němu dostane někdo nepovolaný,\nmůžete jej v <a href=\"https://github.com/settings/tokens\">nastavení</a> opět smazat.</p>\n</div><p>Pomocí tokenu můžete z GitHubu získávat informace.\nProzatím token nastavte do proměnné, později jej schováme například do\nkonfiguračního souboru.</p>\n<p>Tímto kódem lze například získat popis přihlášeného uživatele, tedy sebe sama.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">token</span> <span class=\"o\">=</span> <span class=\"s1\">'d7313dab254b7fd0d0f3ec3cbf754b3abce462d5'</span>\n<span class=\"gp\">>>> </span><span class=\"n\">session</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">Session</span><span class=\"p\">()</span>\n<span class=\"gp\">>>> </span><span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">headers</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">'User-Agent'</span><span class=\"p\">:</span> <span class=\"s1\">'Python'</span><span class=\"p\">}</span>\n<span class=\"gp\">>>> </span><span class=\"k\">def</span> <span class=\"nf\">token_auth</span><span class=\"p\">(</span><span class=\"n\">req</span><span class=\"p\">):</span>\n<span class=\"gp\">... </span> <span class=\"n\">req</span><span class=\"o\">.</span><span class=\"n\">headers</span><span class=\"p\">[</span><span class=\"s1\">'Authorization'</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">f</span><span class=\"s1\">'token {token}'</span>\n<span class=\"gp\">... </span> <span class=\"k\">return</span> <span class=\"n\">req</span>\n<span class=\"gp\">... </span>\n<span class=\"gp\">>>> </span><span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">auth</span> <span class=\"o\">=</span> <span class=\"n\">token_auth</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">'https://api.github.com/user'</span><span class=\"p\">)</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">json</span><span class=\"p\">()</span>\n</pre></div><p>Funkce <code>session.auth</code> v příkladu výše je autentizační funkce,\nkterá nějakým způsobem modifikuje HTTP požadavek za účelem autentizace,\nvětšinou přidává specifické hlavičky (jak je tomu i zde).\nLze ji nastavit buďto na celé session nebo předat argumentem <code>auth</code> s každým\npožadavkem.</p>\n<p>Existují předpřipravené funkce v modulu <code>requests.auth</code>, například \n<code>requests.auth.HTTPBasicAuth</code> provádí základní HTTP přihlášení.\nDle specifikace zakóduje jméno a heslo pomocí\nalgoritmu base64 a přidá hlavičku <code>Authorization</code>.</p>\n<p><a href=\"https://cs.wikipedia.org/wiki/Basic_access_authentication\">Základní HTTP přihlášení</a>\nje tak běžné, že pro něj Requests mají zkratku –\nmísto <code>HTTPBasicAuth</code> se dá použít i dvojice (jméno, heslo):</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">'https://httpbin.org/basic-auth/AzureDiamond/hunter2'</span><span class=\"p\">,</span>\n<span class=\"go\"> auth=requests.auth.HTTPBasicAuth('AzureDiamond', 'hunter2'))</span>\n<span class=\"gp\">>>> </span>\n<span class=\"gp\">>>> </span><span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">'https://httpbin.org/basic-auth/AzureDiamond/hunter2'</span><span class=\"p\">,</span>\n<span class=\"go\"> auth=('AzureDiamond', 'hunter2'))</span>\n</pre></div><div class=\"admonition note\"><p>Všimněte si také hlavičky <code>User-Agent</code>.\nTa je potřeba při komunikaci s GitHub API explicitně nastavit.\nNastavení na objektu session zajistí, že tato hlavička\nbude ve všech požadavcích.</p>\n</div><p>Pokud budete chtít něco provést, například dát hvězdičku repozitáři s těmito\nmateriály, musíte tokenu nastavit patřičné oprávnění\n(u hvězdičky je to <code>public_repo</code>).\nTo se dělá přes <a href=\"https://github.com/settings/tokens\">nastavení</a> na GitHubu.</p>\n<p>Hvězdičku pak přidáte takto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">put</span><span class=\"p\">(</span><span class=\"s1\">'https://api.github.com/user/starred/pyvec/naucse.python.cz'</span><span class=\"p\">)</span>\n<span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">text</span>\n<span class=\"go\">''</span>\n</pre></div><p>Jak vidíte, API nevrací žádný text (žádné tělo odpovědi).\nMůžete ale zkontrolovat návratový stav:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">status_code</span>\n<span class=\"go\">204</span>\n</pre></div><p>Případně vyhodit výjimku, pokud je stavový kód divný (např <em>404 Nenalezeno</em>,\n<em>401 Chybí oprávnění</em> apod.):</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n</pre></div><p>Pokud hvězdičku chcete odebrat, použijte metodu DELETE.\nMy ale věříme, že ji odebrat nechcete :)</p>\n<p><a href=\"https://developer.github.com/v3/\">Dokumentace</a> ke GitHub API.</p>\n<h2>Chraňte své tokeny</h2>\n<p>Když ukládáte skript do gitu, mějte na paměti, že tokeny a klíče do něj nikdy\nnepatří. Můžete je uložit do konfiguračního souboru, který bude gitem ignorován,\nnapříklad takhle:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">[github]</span>\n<span class=\"na\">token</span> <span class=\"o\">=</span> <span class=\"s\">d7313dab254b7fd0d0f3ec3cbf754b3abce462d5</span>\n</pre></div><p>A následně konfiguraci načtete pomocí modulu\n<a href=\"https://docs.python.org/3/library/configparser.html\">configparser</a>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"kn\">import</span> <span class=\"nn\">configparser</span>\n<span class=\"gp\">>>> </span><span class=\"n\">config</span> <span class=\"o\">=</span> <span class=\"n\">configparser</span><span class=\"o\">.</span><span class=\"n\">ConfigParser</span><span class=\"p\">()</span>\n<span class=\"gp\">>>> </span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">'auth.cfg'</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span> <span class=\"n\">config</span><span class=\"o\">.</span><span class=\"n\">read_file</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n<span class=\"gp\">>>> </span><span class=\"n\">config</span><span class=\"p\">[</span><span class=\"s1\">'github'</span><span class=\"p\">][</span><span class=\"s1\">'token'</span><span class=\"p\">]</span>\n<span class=\"go\">'d7313dab254b7fd0d0f3ec3cbf754b3abce462d5'</span>\n</pre></div><p>Do souboru <code>.gitignore</code> pak musíte přidat název ignorovaného souboru, např.:</p>\n<div class=\"highlight\"><pre><code>auth.cfg\n\n</code></pre></div><p>Ověřte si, že git soubor <code>auth.cfg</code> opravdu ignoruje, t.j. soubor se neukáže\nve výstupu <code>git status</code>.</p>\n<p>Jelikož ostatní tento konfigurační soubor neuvidí,\nje vhodné jim vysvětlit, jak takový soubor (s jejich údaji) vytvořit.\nMůžete například vložit do gitu soubor <code>auth.cfg.sample</code>\ns vymyšlenými údaji, či příklad uvést v README.</p>\n\n\n " } } }