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', ...}
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': '*/*', 'User-Agent': 'python-requests/2.10.0', 'X-Test2': 'true', 'Host': 'httpbin.org', 'Accept-Encoding': 'gzip, deflate', 'X-Test': 'true', 'Cookie': 'mipyt=best'}}
Pro reálné použití si ukážeme, jak se dá pomocí requests získat seznam tweetů. Nebudeme samozřejmě nic parsovat z HTML stránek, ale použijeme API Twitteru.
>>> r = session.get('https://api.twitter.com/1.1/search/tweets.json')
>>> r.json()
{'errors': [{'code': 215, 'message': 'Bad Authentication data.'}]}
Jak můžete vidět v odpovědi, Twitter API neumožňuje data číst bez autentizace. Jak se autentizovat byste při troše hledání našli v dokumentaci, ale protože tu nevyučujeme úvod do OAuthu, ale Python, rozhodli jsme se vám to zjednodušit.
Nemáte-li na Twitter účet, vytvořte si ho. Můžete vytvořit nějaký dummy účet, který dál nebudete používat. Budete ale potřebovat ověřitelné telefonní číslo.
Po přihlášení na Twitter jděte na apps.twitter.com a vytvořte aplikaci
(URL si můžete vymyslet, třeba http://invalid
).
Po vytvoření najdete na kartě Keys and Access Tokens API Key a API Secret.
Pozor, jedná se prakticky o hesla k vašemu Twitter účtu,
a proto by je nikdo kromě vás neměl vidět.
Ochrana přihlašovacích tokenů
Ještě jednou – API Key a API Secret se chovají jako hesla. Nikomu je nesmíte ukazovat! Stane-li se přesto, že se k nim dostane někdo nepovolaný, na kartě Keys and Access Tokens je můžete zrušit.
Prozatím klíče nastavte do proměnných, později je schováme například do konfiguračního souboru.
>>> api_key = 'D4HJp6PKmpon9eya1b2c3d4e5'
>>> api_secret = 'rhvasRMhvbuHJpu4MIuAb4WO50gnoQa1b2c3d4e5f6g7h8i9j0'
Pomocí těchto kódů je potřeba si od Twitter API vyžádat přístupový token.
Používá se k tomu běžné HTTP přihlášení (HTTP Basic authentication),
kde je api_key
použit jako uživatelské jméno a api_secret
jako heslo.
Pro běžné HTTP přihlášení se v knihovně requests používá
requests.auth.HTTPBasicAuth
:
>>> r = session.post('https://api.twitter.com/oauth2/token',
auth=requests.auth.HTTPBasicAuth(api_key, api_secret),
data={'grant_type': 'client_credentials'})
>>>
>>> r.json()
{'token_type': 'bearer', 'access_token': 'AAAAAAAAAAAAAAAAAAAAAHhKXAAAAAAAaA1abB2bcC3cdD4deE5efF6fgG7ghH8hiI9ijJ0ja1b2c3d4e5f6g7h8i9j0a1b2c3d4e5f6g7h8i9j0'}
>>> bearer_token = r.json()['access_token']
Parametr 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.
requests.auth.HTTPBasicAuth
zde 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 jen dvojice (jméno, heslo):
>>> r = session.post('https://api.twitter.com/oauth2/token',
auth=(api_key, api_secret),
data={'grant_type': 'client_credentials'})
Pro další komunikaci s Twitter API je nutné přidat hlavičku se získaným tokenem. Jelikož používáte session, není nutné to dělat u každého požadavku zvlášť, ale je možné nastavit autentizační funkci pro celou session.
>>> def bearer_auth(req):
... req.headers['Authorization'] = 'Bearer ' + bearer_token
... return req
...
>>> session.auth = bearer_auth
Pak už by mělo API fungovat. Použijeme API pro vyhledávání tweetů:
>>> r = session.get(
... 'https://api.twitter.com/1.1/search/tweets.json',
... params={'q': '#python'},
... )
>>> for tweet in r.json()['statuses']:
... print(tweet['text'])
...
Once a framework decides to abstract the HTML layer from you. Customizing your UI becomes sorcery. #django #Python
...
Zde je pro zjednodušení k dispozici celá funkce pro vytvoření autentizované session:
import requests
def twitter_session(api_key, api_secret):
session = requests.Session()
r = session.post('https://api.twitter.com/oauth2/token',
auth=(api_key, api_secret),
data={'grant_type': 'client_credentials'})
bearer_token = r.json()['access_token']
def bearer_auth(req):
req.headers['Authorization'] = 'Bearer ' + bearer_token
return req
session.auth = bearer_auth
return session
Podíváme se i na GitHub API, které má jednodušší 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í). Token je opět třeba patřičně chránit.
Pomocí tokenu pak můžete z GitHubu získávat informace. 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'] = 'token ' + token
... return req
...
>>> session.auth = token_auth
>>> r = session.get('https://api.github.com/user')
>>> r.json()
Všimněte si 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:
[twitter]
key = D4HJp6PKmpon9eya1b2c3d4e5
secret = rhvasRMhvbuHJpu4MIuAb4WO50gnoQa1b2c3d4e5f6g7h8i9j0
[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['twitter']['key']
D4HJp6PKmpon9eya1b2c3d4e5
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:2017/pyknihovny-brno: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=\"/2017/pyknihovny-brno/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><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': '*/*', 'User-Agent': 'python-requests/2.10.0', 'X-Test2': 'true', 'Host': 'httpbin.org', 'Accept-Encoding': 'gzip, deflate', 'X-Test': 'true', 'Cookie': 'mipyt=best'}}</span>\n</pre></div><h2>Twitter API</h2>\n<p>Pro reálné použití si ukážeme, jak se dá pomocí requests získat seznam tweetů.\nNebudeme samozřejmě nic parsovat z HTML stránek, ale použijeme <a href=\"https://dev.twitter.com/rest/public\">API Twitteru</a>.</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\">get</span><span class=\"p\">(</span><span class=\"s1\">'https://api.twitter.com/1.1/search/tweets.json'</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\">{'errors': [{'code': 215, 'message': 'Bad Authentication data.'}]}</span>\n</pre></div><p>Jak můžete vidět v odpovědi, Twitter API neumožňuje data číst bez autentizace.\nJak se autentizovat byste při troše hledání našli v dokumentaci, ale protože\ntu nevyučujeme úvod do OAuthu, ale Python, rozhodli jsme se vám to zjednodušit.</p>\n<p>Nemáte-li na Twitter účet, vytvořte si ho. Můžete vytvořit nějaký <em>dummy</em> účet,\nkterý dál nebudete používat. Budete ale potřebovat ověřitelné telefonní číslo.</p>\n<p>Po přihlášení na Twitter jděte na <a href=\"https://apps.twitter.com/\">apps.twitter.com</a> a vytvořte aplikaci\n(URL si můžete vymyslet, třeba <code>http://invalid</code>).\nPo vytvoření najdete na kartě <em>Keys and Access Tokens</em> <strong>API Key</strong> a <strong>API Secret</strong>.\nPozor, jedná se prakticky o hesla k vašemu Twitter účtu,\na proto by je nikdo kromě vás neměl vidět.</p>\n<div class=\"admonition warning\"><p class=\"admonition-title\">Ochrana přihlašovacích tokenů</p>\n<p>Ještě jednou – <em>API Key</em> a <em>API Secret</em> se chovají jako hesla.\nNikomu je nesmíte ukazovat!\nStane-li se přesto, že se k nim dostane někdo nepovolaný, na kartě\n<em>Keys and Access Tokens</em> je můžete zrušit.</p>\n</div><p>Prozatím klíče nastavte do proměnných, později je schováme například do\nkonfiguračního souboru.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">api_key</span> <span class=\"o\">=</span> <span class=\"s1\">'D4HJp6PKmpon9eya1b2c3d4e5'</span>\n<span class=\"gp\">>>> </span><span class=\"n\">api_secret</span> <span class=\"o\">=</span> <span class=\"s1\">'rhvasRMhvbuHJpu4MIuAb4WO50gnoQa1b2c3d4e5f6g7h8i9j0'</span>\n</pre></div><p>Pomocí těchto kódů je potřeba si od Twitter API vyžádat přístupový token.\nPoužívá se k tomu běžné HTTP přihlášení (<a href=\"https://cs.wikipedia.org/wiki/Basic_access_authentication\">HTTP Basic authentication</a>),\nkde je <code>api_key</code> použit jako uživatelské jméno a <code>api_secret</code> jako heslo.</p>\n<p>Pro běžné HTTP přihlášení se v knihovně requests používá\n<code>requests.auth.HTTPBasicAuth</code>:</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\">post</span><span class=\"p\">(</span><span class=\"s1\">'https://api.twitter.com/oauth2/token'</span><span class=\"p\">,</span>\n<span class=\"go\"> auth=requests.auth.HTTPBasicAuth(api_key, api_secret),</span>\n<span class=\"go\"> data={'grant_type': 'client_credentials'})</span>\n<span class=\"gp\">>>> </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\">{'token_type': 'bearer', 'access_token': 'AAAAAAAAAAAAAAAAAAAAAHhKXAAAAAAAaA1abB2bcC3cdD4deE5efF6fgG7ghH8hiI9ijJ0ja1b2c3d4e5f6g7h8i9j0a1b2c3d4e5f6g7h8i9j0'}</span>\n<span class=\"gp\">>>> </span><span class=\"n\">bearer_token</span> <span class=\"o\">=</span> <span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">json</span><span class=\"p\">()[</span><span class=\"s1\">'access_token'</span><span class=\"p\">]</span>\n</pre></div><p>Parametr <code>auth</code> v příkladu výše je autentizační funkce, která nějakým způsobem\nmodifikuje HTTP požadavek za účelem autentizace, většinou přidává specifické\nhlavičky.\n<code>requests.auth.HTTPBasicAuth</code> zde dle specifikace zakóduje jméno a heslo pomocí\nalgoritmu base64 a přidá hlavičku <code>Authorization</code>.</p>\n<p>Základní HTTP přihlášení je tak běžné, že pro něj Requests mají zkratku –\nmísto <code>HTTPBasicAuth</code> se dá použít jen dvojice (jméno, heslo):</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\">post</span><span class=\"p\">(</span><span class=\"s1\">'https://api.twitter.com/oauth2/token'</span><span class=\"p\">,</span>\n<span class=\"go\"> auth=(api_key, api_secret),</span>\n<span class=\"go\"> data={'grant_type': 'client_credentials'})</span>\n</pre></div><p>Pro další komunikaci s Twitter API je nutné přidat hlavičku se získaným tokenem.\nJelikož používáte session, není nutné to dělat u každého požadavku zvlášť,\nale je možné nastavit autentizační funkci pro celou session.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"k\">def</span> <span class=\"nf\">bearer_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=\"s1\">'Bearer '</span> <span class=\"o\">+</span> <span class=\"n\">bearer_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\">bearer_auth</span>\n</pre></div><p>Pak už by mělo API fungovat.\nPoužijeme <a href=\"https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets.html\">API pro vyhledávání tweetů</a>:</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\">get</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span> <span class=\"s1\">'https://api.twitter.com/1.1/search/tweets.json'</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span> <span class=\"n\">params</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s1\">'q'</span><span class=\"p\">:</span> <span class=\"s1\">'#python'</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span><span class=\"p\">)</span>\n<span class=\"gp\">>>> </span><span class=\"k\">for</span> <span class=\"n\">tweet</span> <span class=\"ow\">in</span> <span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">json</span><span class=\"p\">()[</span><span class=\"s1\">'statuses'</span><span class=\"p\">]:</span>\n<span class=\"gp\">... </span> <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">tweet</span><span class=\"p\">[</span><span class=\"s1\">'text'</span><span class=\"p\">])</span>\n<span class=\"gp\">... </span>\n<span class=\"go\">Once a framework decides to abstract the HTML layer from you. Customizing your UI becomes sorcery. #django #Python</span>\n<span class=\"gp\">...\n</span></pre></div><p>Zde je pro zjednodušení k dispozici celá funkce pro vytvoření autentizované\n<em>session</em>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">twitter_session</span><span class=\"p\">(</span><span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">api_secret</span><span class=\"p\">):</span>\n <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\n <span class=\"n\">r</span> <span class=\"o\">=</span> <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">post</span><span class=\"p\">(</span><span class=\"s1\">'https://api.twitter.com/oauth2/token'</span><span class=\"p\">,</span>\n <span class=\"n\">auth</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">api_key</span><span class=\"p\">,</span> <span class=\"n\">api_secret</span><span class=\"p\">),</span>\n <span class=\"n\">data</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s1\">'grant_type'</span><span class=\"p\">:</span> <span class=\"s1\">'client_credentials'</span><span class=\"p\">})</span>\n\n <span class=\"n\">bearer_token</span> <span class=\"o\">=</span> <span class=\"n\">r</span><span class=\"o\">.</span><span class=\"n\">json</span><span class=\"p\">()[</span><span class=\"s1\">'access_token'</span><span class=\"p\">]</span>\n\n <span class=\"k\">def</span> <span class=\"nf\">bearer_auth</span><span class=\"p\">(</span><span class=\"n\">req</span><span class=\"p\">):</span>\n <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=\"s1\">'Bearer '</span> <span class=\"o\">+</span> <span class=\"n\">bearer_token</span>\n <span class=\"k\">return</span> <span class=\"n\">req</span>\n\n <span class=\"n\">session</span><span class=\"o\">.</span><span class=\"n\">auth</span> <span class=\"o\">=</span> <span class=\"n\">bearer_auth</span>\n <span class=\"k\">return</span> <span class=\"n\">session</span>\n</pre></div><h3>GitHub API</h3>\n<p>Podíváme se i na <a href=\"https://developer.github.com/v3\">GitHub API</a>, které má jednodušší 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í).\nToken je opět třeba patřičně chránit.</p>\n<p>Pomocí tokenu pak můžete z GitHubu získávat informace.\nTí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=\"s1\">'token '</span> <span class=\"o\">+</span> <span class=\"n\">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><div class=\"admonition note\"><p>Všimněte si hlavičky <code>User-Agent</code>. Ta je potřeba při komunikaci s GitHub API\nexplicitně nastavit. Nastavení 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<h3>Chraňte své tokeny</h3>\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\">[twitter]</span>\n<span class=\"na\">key</span> <span class=\"o\">=</span> <span class=\"s\">D4HJp6PKmpon9eya1b2c3d4e5</span>\n<span class=\"na\">secret</span> <span class=\"o\">=</span> <span class=\"s\">rhvasRMhvbuHJpu4MIuAb4WO50gnoQa1b2c3d4e5f6g7h8i9j0</span>\n\n<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\">'twitter'</span><span class=\"p\">][</span><span class=\"s1\">'key'</span><span class=\"p\">]</span>\n<span class=\"go\">D4HJp6PKmpon9eya1b2c3d4e5</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 " } } }