Nauč se Python > Kurzy > Datový kurz PyLadies > API > API

Co je API?

Klient a server

API (Application Programming Interface) je dohoda mezi dvěma stranami o tom, jak si mezi sebou budou povídat. Těmto stranám se říká klient a server.

Server je ta strana, která má zajímavé informace nebo něco zajímavého umí a umožňuje ostatním na internetu, aby toho využili. Server je program, který donekonečna běží na nějakém počítači a je připraven všem ostatním na internetu odpovídat na požadavky.

Klient je program, který posílá požadavky na server a z odpovědí se snaží poskládat něco užitečného. Klient je tedy mobilní aplikace s mráčky a sluníčky nebo náš prohlížeč, v němž si můžeme otevřít kurzovní lístek ČNB. Je to ale i Heureka robot, který za Heureku načítá informace o zboží v e-shopech.

title

Základní pojmy

Než se pustíme do tvorby klienta, projdeme si některé základní pojmy kolem API.

Protokol

Celé dorozumívání mezi klientem a serverem se odehrává přes tzv. protokol. To není nic jiného, než smluvený způsob, co bude kdo komu posílat a jakou strukturu to bude mít. Protokolů je v počítačovém světě spousta, ale nás bude zajímat jen HTTP, protože ten využívají webová API a ostatně i web samotný. Není to náhoda, že adresa internetových stránek v prohlížeči zpravidla začíná http:// (nebo https://).

HTTP

Dorozumívání mezi klientem a serverem probíhá formou požadavku (HTTP request), jenž posílá klient na server, a odpovědi (HTTP response), kterou server posílá zpět. Každá z těchto zpráv má své náležitosti.

Požadavek

  • metoda (HTTP method): Například metoda GET má tu vlastnost, že pouze čte a nemůžeme s ní tedy přes API něco změnit - je tzv. bezpečná. Kromě metody GET existují ještě metody POST (vytvořit), PUT (aktualizovat) a DELETE (odstranit), které nepotřebujeme, protože data z API budeme pouze získávat.
  • adresa s parametry (URL s query parameters): Na konci běžné URL adresy otazník a za ním parametry. Pokud je parametrů víc, oddělují se znakem &. Adresa samotná nejčastěji určuje o jaká data půjde (v našem příkladě jsou to filmy) a URL parametry umožňují provést filtraci už na straně serveru a získat tím jen ta data, která nás opravdu zajímají (v našem případě dramata v délce 150 min)
      http://api.example.com/movies/
      http://api.example.com/movies?genre=drama&duration=150 
  • hlavičky (headers): Hlavičky jsou vlastně jen další parametry. Liší se v tom, že je neposíláme jako součást adresy a na rozdíl od URL parametrů podléhají nějaké standardizaci a konvencím.
  • tělo (body): Tělo zprávy je krabice, kterou s požadavkem posíláme, a do které můžeme vložit, co chceme. Tedy nejlépe něco, čemu bude API na druhé straně rozumět. Tělo může být prázdné. V těle můžeme poslat obyčejný text, data v nějakém formátu, ale klidně i obrázek. Aby API na druhé straně vědělo, co v krabici je a jak ji má rozbalovat, je potřeba s tělem zpravidla posílat hlavičku Content-Type.

Musíme vyčíst z dokumentace konkrétního API, jak požadavek správně poskládat.

Odpověď

  • status kód (status code): Číselný kód, kterým API dává najevo, jak požadavek zpracovalo. Podle první číslice kódu se kódy dělí na různé kategorie:
      1xx - informativní odpověď (požadavek byl přijat, ale jeho zpracování pokračuje)
      2xx - požadavek byl v pořádku přijat a zpracován
      3xx - přesměrování, klient potřebuje poslat další požadavek jinam, aby se dobral odpovědi
      4xx - chyba na straně klienta (špatně jsme poskládali dotaz)
      5xx - chyba na straně serveru (API nezvládlo odpovědět)
  • hlavičky (headers): Informace o odpovědi jako např. datum zpracování, formát odpovědi...
  • tělo (body): Tělo odpovědi - to, co nás zajímá většinou nejvíc

Formáty

Tělo může být v libovolném formátu. Může to být text, HTML, obrázek, PDF soubor, nebo cokoliv jiného. Hodnotě hlavičky Content-Type se dávají různé názvy: content type, media type, MIME type. Nejčastěji se skládá jen z typu a podtypu, které se oddělí lomítkem. Několik příkladů:

  • text/plain - obyčejný text
  • text/html - HTML
  • text/csv - CSV
  • image/gif - GIF obrázek
  • image/jpeg - JPEG obrázek
  • image/png - PNG obrázek
  • application/json - JSON
  • application/xml nebo text/xml - XML

Formát JSON

JSON vznikl kolem roku 2000 a brzy se uchytil jako stručnější náhrada za XML, především na webu a ve webových API. Dnes je to nejspíš nejoblíbenější formát pro obecná strukturovaná data vůbec. Jeho autorem je Douglas Crockford, jeden z lidí podílejících se na vývoji jazyka JavaScript.

JSON je datový formát NE datový typ!

Vstupem je libovolná datová struktura:

  • číslo
  • řetězec
  • pravdivostní hodnota
  • pole
  • objekt
  • None

Výsutpem je vždy řetězec (string)

title

Jazyk Python (a mnoho dalších) má podporu pro práci s JSON v základní instalaci (vestavěný).

V případě jazyka Python si lze JSON splést především se slovníkem (dictionary). Je ale potřeba si uvědomit, že JSON je text, který může být uložený do souboru nebo odeslaný přes HTTP, ale nelze jej přímo použít při programování. Musíme jej vždy nejdříve zpracovat na slovníky a seznamy.

In [1]:
import json

V následujícím JSONu je pod klíčem "people" seznam slovníků s další strukturou:

In [2]:
people_info = '''
{
    "people": [
    {
        "name": "John Smith",
        "phone": "555-246-999",
        "email": ["johns@gmail.com", "jsmith@gmail.com"],
        "is_employee": false
    },
    {
        "name": "Jane Doe",
        "phone": "665-296-659",
        "email": ["janed@gmail.com", "djane@gmail.com"],
        "is_employee": true
    }
  ]
}
'''

json.loads převede řetězec na objekt

In [3]:
data = json.loads(people_info)
In [4]:
data
Out[4]:
{'people': [{'name': 'John Smith',
   'phone': '555-246-999',
   'email': ['johns@gmail.com', 'jsmith@gmail.com'],
   'is_employee': False},
  {'name': 'Jane Doe',
   'phone': '665-296-659',
   'email': ['janed@gmail.com', 'djane@gmail.com'],
   'is_employee': True}]}
In [5]:
type(data)
Out[5]:
dict
In [6]:
type(data['people'])
Out[6]:
list
In [7]:
type(data['people'][0])
Out[7]:
dict
In [8]:
data['people']
Out[8]:
[{'name': 'John Smith',
  'phone': '555-246-999',
  'email': ['johns@gmail.com', 'jsmith@gmail.com'],
  'is_employee': False},
 {'name': 'Jane Doe',
  'phone': '665-296-659',
  'email': ['janed@gmail.com', 'djane@gmail.com'],
  'is_employee': True}]
In [9]:
data['people'][0]
Out[9]:
{'name': 'John Smith',
 'phone': '555-246-999',
 'email': ['johns@gmail.com', 'jsmith@gmail.com'],
 'is_employee': False}
In [10]:
data['people'][0]['name']
Out[10]:
'John Smith'

Práce s API klienty

Obecný klient

Mobilní aplikace na počasí je klient, který někdo vytvořil pro jeden konkrétní úkol a pracovat umí jen s jedním konkrétním API. Takový klient je užitečný, pokud chceme akorát vědět, jaké je počasí, ale už méně, pokud si chceme zkoušet práci s více API zároveň. Proto existují obecní klienti.

Prohlížeč jako obecný klient

Pokud z API chceme pouze číst a API nevyžaduje žádné přihlašování, můžeme jej vyzkoušet i v prohlížeči, jako by to byla webová stránka. Pokud na stránkách ČNB navštívíme kurzovní lístek a úplně dole klikneme na Textový formát, uvidíme odpověď z API serveru

Obecný klient v příkazové řádce: curl

Pokud se k API budeme potřebovat přihlásit nebo s ním zkoušet dělat složitější věci než jen čtení, nebude nám prohlížeč stačit.

Proto je dobré se naučit používat program curl. Spouští se v příkazové řádce a je to švýcarský nůž všech, kteří se pohybují kolem webových API.

Příklady s curl

title

Když příkaz zadáme a spustíme, říkáme tím programu curl, že má poslat požadavek na uvedenou adresu a vypsat to, co mu ČNB pošle zpět.

title

Vlastní klient

Obecného klienta musí ovládat člověk (ruční nastavování parametrů, pravidelné spuštění na základě podmínek či času atd.). To je přesně to, co potřebujeme, když si chceme nějaké API vyzkoušet, ale celý smysl API je v tom, aby je programy mohly využívat automaticky. Pokud chceme naprogramovat klienta pro konkrétní úkol, můžeme ve většině jazyků použít buď vestavěnou, nebo doinstalovanou knihovnu. V případě jazyka Python použijeme knihovnu Requests.

Práce s veřejným API

Vyzkoušíme si dotazy na API s daty zločinnosti v UK, která jsou dostupná na měsiční bázi dle přibližné lokace (viz https://data.police.uk/docs/method/stops-at-location/)

In [11]:
import requests
In [12]:
api_url = "https://data.police.uk/api/stops-street"

Nastavení parametrů volání API dle dokumentace https://data.police.uk/docs/method/stops-at-location/ Jako lokaci jsem vybral nechvalně proslulý obvod Hackney v Londýně :)

In [13]:
params = {
    "lat" : "51.5487158",
    "lng" : "-0.0613842",
    "date" : "2018-06"
}

Pomocí funkce get pošleme požadavek na URL adresu API. URL adresa doplněná o parametry vypadá takto: https://data.police.uk/api/stops-street?lat=51.5487158&lng=-0.0613842&date=2018-06 a je možné ji vyzkoušet i v prohlížeči.

V proměnné response máme uložený objekt, který obsahuje odpověď od API.

In [14]:
response = requests.get(api_url, params=params)

Pokud je status kód jiný, než 200 (success), vyhodí skript chybu a chybový status code

In [15]:
if response.status_code != 200:
    print('Failed to get data:', response.status_code)
else:
    print('First 100 characters of data are')
    print(response.text[:100])
First 100 characters of data are
[{"age_range":"18-24","outcome":"Community resolution","involved_person":true,"self_defined_ethnicit

Hlavička s doplňujícími informacemi o opdovědi

In [16]:
response.headers
Out[16]:
{'Date': 'Wed, 25 Mar 2020 14:33:39 GMT', 'Content-Type': 'application/json', 'Content-Length': '5687', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'Access-Control-Allow-Origin': '*', 'Content-Encoding': 'gzip', 'Strict-Transport-Security': 'max-age=31536000;', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY', 'Content-Security-Policy': "default-src 'self' 'unsafe-inline' ; script-src 'self' data: www.google-analytics.com ajax.googleapis.com 'unsafe-inline';", 'Referer-Policy': 'strict-origin-when-cross-origin'}
In [17]:
response.headers['content-type']
Out[17]:
'application/json'

Obsah odpovědi je řetězec bytů

In [18]:
response.content[:200]
Out[18]:
b'[{"age_range":"18-24","outcome":"Community resolution","involved_person":true,"self_defined_ethnicity":"Black\\/African\\/Caribbean\\/Black British - Any other Black\\/African\\/Caribbean background","gend'

Vypadá jako seznam (list) nebo slovník (dictionary), ale nechová se tak:

In [19]:
response[0]["age_range"]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-19-ec7ac01c28cf> in <module>
----> 1 response[0]["age_range"]

TypeError: 'Response' object is not subscriptable

Převedeme řetězec bytů metodou .json() z knihovny requests

In [20]:
data = response.json()

Ověříme datový typ

In [21]:
type(data)
Out[21]:
list

Nyní můžeme přistupovat k "data" jako ke klasickému seznamu (list)

In [22]:
data[0]["age_range"]
Out[22]:
'18-24'

Převední seznamu(list) na řetězec s parametry pro zobrazení struktury v čitelné podobě

In [23]:
datas = json.dumps(data, sort_keys=True, indent=4)
In [24]:
print(datas[:1600])
[
    {
        "age_range": "18-24",
        "datetime": "2018-06-01T09:45:00+00:00",
        "gender": "Male",
        "involved_person": true,
        "legislation": "Misuse of Drugs Act 1971 (section 23)",
        "location": {
            "latitude": "51.551330",
            "longitude": "-0.068037",
            "street": {
                "id": 968551,
                "name": "On or near Downs Park Road"
            }
        },
        "object_of_search": "Controlled drugs",
        "officer_defined_ethnicity": "Black",
        "operation": false,
        "operation_name": null,
        "outcome": "Community resolution",
        "outcome_linked_to_object_of_search": null,
        "outcome_object": {
            "id": "bu-community-resolution",
            "name": "Community resolution"
        },
        "removal_of_more_than_outer_clothing": null,
        "self_defined_ethnicity": "Black/African/Caribbean/Black British - Any other Black/African/Caribbean background",
        "type": "Person search"
    },
    {
        "age_range": "18-24",
        "datetime": "2018-06-02T02:37:00+00:00",
        "gender": "Male",
        "involved_person": true,
        "legislation": "Misuse of Drugs Act 1971 (section 23)",
        "location": {
            "latitude": "51.549626",
            "longitude": "-0.054738",
            "street": {
                "id": 968830,
                "name": "On or near Dalston Lane"
            }
        },
        "object_of_search": "Controlled drugs",
        "officer_defined_ethnicity": "Black",
        "operation": false,
        "operat

Cyklus, kterým přistupujeme k věkovému rozpětí lidí lustrovaných policií

In [25]:
age_range = [i["age_range"] for i in data]
In [26]:
print(age_range)
['18-24', '18-24', 'over 34', '18-24', '10-17', '10-17', 'over 34', '25-34', 'over 34', '25-34', None, '25-34', '18-24', '10-17', None, '18-24', None, '18-24', '10-17', 'over 34', '18-24', '18-24', '18-24', '18-24', '18-24', '18-24', '18-24', '18-24', '18-24', '25-34', '18-24', '18-24', '18-24', 'over 34', '10-17', '10-17', '25-34', '18-24', '18-24', '25-34', '25-34', '25-34', 'over 34', 'over 34', '18-24', '18-24', '18-24', '18-24', '18-24', '25-34', '25-34', 'over 34', '25-34', 'over 34', '18-24', '25-34', '25-34', 'over 34', '18-24', None, '18-24', '18-24', None, '18-24', '18-24', '25-34', '10-17', '25-34', '18-24', '25-34', '18-24', None, '18-24', '25-34', '25-34', '25-34', '18-24', '25-34', '25-34', '18-24', '18-24', '10-17', 'over 34', 'over 34', '18-24', '18-24', '25-34', '10-17', '18-24', 'over 34', '10-17', '25-34', 'over 34', '18-24', '25-34', 'over 34', '25-34', '18-24', '18-24', '18-24', '18-24', '10-17', '10-17', '18-24', '25-34', '18-24', '25-34', '18-24', '18-24', '10-17', '25-34', '18-24', 'over 34', '10-17', '18-24', 'over 34', '18-24', '10-17', '10-17', 'over 34', '25-34', '10-17', '10-17', '25-34', '10-17', '10-17', '10-17', '10-17', '18-24', '10-17', '10-17', None, 'over 34', '10-17', '10-17', '25-34', '10-17', '18-24', '10-17', None, '10-17', '10-17', '25-34', '18-24', '18-24', '25-34', '10-17', '10-17', '25-34', '10-17', None, '25-34', '25-34', '18-24', '10-17', '25-34', '18-24', '10-17', '10-17', '25-34', None, '18-24', '25-34', '25-34', '10-17', '10-17', '18-24', 'over 34', '18-24', '18-24', '10-17', '10-17', '25-34', 'over 34', 'over 34', '18-24', '18-24', '25-34', '10-17']

Cyklus, kterým přistupujeme k id ulice, kde došlo lustraci podezřelé(ho)

In [27]:
street_id = [i["location"]["street"]["id"] for i in data]
In [28]:
print(street_id)
[968551, 968830, 968830, 968740, 964026, 964026, 968844, 968662, 968662, 968662, 971832, 971832, 968828, 968828, 968805, 968828, 968805, 968805, 968805, 968584, 964086, 968632, 968632, 964132, 968632, 968632, 968584, 968584, 968872, 971832, 968717, 968866, 971656, 964226, 968662, 968662, 968703, 968668, 968668, 968703, 964013, 968505, 968830, 968500, 968662, 968830, 968830, 968662, 968662, 968705, 964150, 968663, 968663, 968830, 968467, 968662, 968663, 968830, 964370, 964370, 968500, 964287, 964329, 971656, 971656, 968830, 968829, 968830, 968829, 968608, 968703, 968703, 968469, 968662, 968754, 968662, 968872, 968748, 968872, 968691, 968641, 968641, 964023, 964322, 968872, 968872, 968872, 968662, 964219, 964092, 964219, 968854, 968662, 968662, 968662, 968786, 968584, 968662, 964266, 964316, 964266, 968637, 968637, 968804, 968804, 968804, 971758, 968804, 968662, 964297, 968830, 968770, 968500, 968662, 968804, 968500, 964324, 964266, 964225, 968816, 968500, 964266, 968641, 968575, 968828, 968828, 968828, 968489, 968815, 968564, 964266, 968871, 968687, 964091, 968815, 971713, 971801, 968662, 964208, 968614, 968802, 968839, 964085, 968630, 968642, 964098, 964312, 964312, 968872, 964248, 971656, 968872, 968872, 968804, 968647, 968884, 968844, 968872, 968763, 968830, 968804, 968854, 968609, 968662, 968830, 968489, 968603, 971832, 968641, 968830, 968647, 968489, 968496, 968606, 968626, 968606, 968369, 968660, 968815]
In [29]:
import pandas as pd

Spojíme seznamy do dataframe

In [30]:
df_from_lists = pd.DataFrame(list(zip(age_range, street_id)), 
                columns = ['age_range', 'street_id'])
In [31]:
df_from_lists.head()
Out[31]:
age_range street_id
0 18-24 968551
1 18-24 968830
2 over 34 968830
3 18-24 968740
4 10-17 964026

Jakou věkovou skupinu lustrovala policie nejčastěji?

In [32]:
%matplotlib inline
In [33]:
df_from_lists["age_range"].value_counts().plot.bar();

Json_normalize

aneb jak jednoduše převést JSON na DataFrame

In [34]:
norm_data = pd.json_normalize(data)
In [35]:
norm_data.head()
Out[35]:
age_range outcome involved_person self_defined_ethnicity gender legislation outcome_linked_to_object_of_search datetime removal_of_more_than_outer_clothing operation officer_defined_ethnicity type operation_name object_of_search outcome_object.id outcome_object.name location.latitude location.street.id location.street.name location.longitude
0 18-24 Community resolution True Black/African/Caribbean/Black British - Any ot... Male Misuse of Drugs Act 1971 (section 23) None 2018-06-01T09:45:00+00:00 None False Black Person search None Controlled drugs bu-community-resolution Community resolution 51.551330 968551 On or near Downs Park Road -0.068037
1 18-24 A no further action disposal True Black/African/Caribbean/Black British - Any ot... Male Misuse of Drugs Act 1971 (section 23) None 2018-06-02T02:37:00+00:00 None False Black Person search None Controlled drugs bu-no-further-action A no further action disposal 51.549626 968830 On or near Dalston Lane -0.054738
2 over 34 Arrest True White - Any other White background Male Misuse of Drugs Act 1971 (section 23) None 2018-06-02T09:45:00+00:00 None False White Person search None Controlled drugs bu-arrest Arrest 51.549626 968830 On or near Dalston Lane -0.054738
3 18-24 A no further action disposal True Black/African/Caribbean/Black British - African Male Misuse of Drugs Act 1971 (section 23) None 2018-06-02T10:50:00+00:00 None False Black Person and Vehicle search None Controlled drugs bu-no-further-action A no further action disposal 51.550209 968740 On or near Rowe Lane -0.051944
4 10-17 A no further action disposal True Black/African/Caribbean/Black British - Caribbean Female Police and Criminal Evidence Act 1984 (section 1) None 2018-06-02T19:30:00+00:00 None False Black Person search None Offensive weapons bu-no-further-action A no further action disposal 51.542304 964026 On or near St Thomas'S Square -0.054589
In [36]:
norm_data["gender"].value_counts()
Out[36]:
Male      170
Female      9
Name: gender, dtype: int64
In [37]:
norm_data["gender"].value_counts().plot.bar();
In [38]:
norm_data["age_range"].value_counts().plot.bar();

Tvoříme klienta pro práci s veřejným API

V následujícím bloku si vytvoříme klienta, který nám stáhne data za dva měsíce (místo jednoho) a uloží je do seznamu seznamů (list of lists). Případné chyby spojení s API ošetříme výjimkami (exceptions) - více viz dokumentace requests

In [39]:
def get_uk_crime_data(latitude, longitude, dates_list):
    """
    Function loops through a list of dates 
    
    Three arguments latitude, longitude and a list of dates
    
    Returns a dataframe with crime data for each day
    """
    appended_data = []
    
    for i in dates_list:
        api_url = "https://data.police.uk/api/stops-street"
        params = {
            "lat" : latitude,
            "lng" : longitude,
            "date" : i
        }
        response = requests.get(api_url, params=params)
        data_foo = response.json()
            
        data = pd.json_normalize(data_foo)
        # store DataFrame in list
        appended_data.append(data)
       
    return pd.concat(appended_data)

Zavolání funkce get_uk_crime_data s parametry zeměpisné šíře a délky přiřazené proměnné df_uk_crime_data

In [40]:
dates_list = ["2018-06","2018-07"]
lat = "51.5487158"
lng = "-0.0613842"

df_uk_crime_data = get_uk_crime_data(lat, lng, dates_list)
In [41]:
df_uk_crime_data.head()
Out[41]:
age_range outcome involved_person self_defined_ethnicity gender legislation outcome_linked_to_object_of_search datetime removal_of_more_than_outer_clothing operation officer_defined_ethnicity type operation_name object_of_search outcome_object.id outcome_object.name location.latitude location.street.id location.street.name location.longitude
0 18-24 Community resolution True Black/African/Caribbean/Black British - Any ot... Male Misuse of Drugs Act 1971 (section 23) None 2018-06-01T09:45:00+00:00 None False Black Person search None Controlled drugs bu-community-resolution Community resolution 51.551330 968551 On or near Downs Park Road -0.068037
1 18-24 A no further action disposal True Black/African/Caribbean/Black British - Any ot... Male Misuse of Drugs Act 1971 (section 23) None 2018-06-02T02:37:00+00:00 None False Black Person search None Controlled drugs bu-no-further-action A no further action disposal 51.549626 968830 On or near Dalston Lane -0.054738
2 over 34 Arrest True White - Any other White background Male Misuse of Drugs Act 1971 (section 23) None 2018-06-02T09:45:00+00:00 None False White Person search None Controlled drugs bu-arrest Arrest 51.549626 968830 On or near Dalston Lane -0.054738
3 18-24 A no further action disposal True Black/African/Caribbean/Black British - African Male Misuse of Drugs Act 1971 (section 23) None 2018-06-02T10:50:00+00:00 None False Black Person and Vehicle search None Controlled drugs bu-no-further-action A no further action disposal 51.550209 968740 On or near Rowe Lane -0.051944
4 10-17 A no further action disposal True Black/African/Caribbean/Black British - Caribbean Female Police and Criminal Evidence Act 1984 (section 1) None 2018-06-02T19:30:00+00:00 None False Black Person search None Offensive weapons bu-no-further-action A no further action disposal 51.542304 964026 On or near St Thomas'S Square -0.054589

Neveřejné API Oxford Dictionaries

Přístup k tomuto API je možné získat po registraci na developer.oxforddictionaries.com. Pro malé množství požadavků je API dostupné zdarma, ale při jeho vyšším využití se pak za každý požadavek na platí.

Po registraci je nutné vytvořit aplikaci, která získá své jedinečné ID a klíč, které se posílají v hlavičkách s každým požadavkem a tak je možné získat k API přístup a také ověřit, kdo se API ptá.

Kódy níže přestanou po lekci fungovat. Pokud chceš v prozkoumávání API pokračovat, udělej si vlastní registraci.

In [42]:
api_url = "https://od-api.oxforddictionaries.com/api/v2"
app_id = "06126da7"
app_key = "d3edae649c4072e2f36af99bb8283069"

Jak se Oxford dictionaries API ptát je popsáno v dokumentaci. Pro získání definice slova jej stačí spolu s jazykem vložit do URL adresy.

In [43]:
language = "en"
word = "ace"

r = requests.get(api_url + f"/entries/{language}/{word}",
                 headers={"app_id" : app_id, "app_key":app_key})
In [44]:
r.json()
Out[44]:
{'id': 'ace',
 'metadata': {'operation': 'retrieve',
  'provider': 'Oxford University Press',
  'schema': 'RetrieveEntry'},
 'results': [{'id': 'ace',
   'language': 'en-gb',
   'lexicalEntries': [{'entries': [{'etymologies': ['Middle English (denoting the ‘one’ on dice): via Old French from Latin as‘unity, a unit’'],
       'homographNumber': '100',
       'senses': [{'definitions': ['a playing card with a single spot on it, ranked as the highest card in its suit in most card games'],
         'domains': [{'id': 'cards', 'text': 'Cards'}],
         'examples': [{'text': 'the ace of diamonds'},
          {'registers': [{'id': 'figurative', 'text': 'Figurative'}],
           'text': 'life had started dealing him aces again'}],
         'id': 'm_en_gbus0005680.006',
         'shortDefinitions': ['playing card with single spot on it, ranked as highest card in its suit in most card games']},
        {'definitions': ['a person who excels at a particular sport or other activity'],
         'domains': [{'id': 'sport', 'text': 'Sport'}],
         'examples': [{'text': 'a motorcycle ace'}],
         'id': 'm_en_gbus0005680.010',
         'registers': [{'id': 'informal', 'text': 'Informal'}],
         'shortDefinitions': ['person who excels at particular sport or other activity'],
         'subsenses': [{'definitions': ['a pilot who has shot down many enemy aircraft'],
           'domains': [{'id': 'air_force', 'text': 'Air_Force'}],
           'examples': [{'text': 'a Battle of Britain ace'}],
           'id': 'm_en_gbus0005680.011',
           'shortDefinitions': ['pilot who has shot down many enemy aircraft']}],
         'synonyms': [{'id': 'expert', 'language': 'en', 'text': 'expert'},
          {'id': 'master', 'language': 'en', 'text': 'master'},
          {'language': 'en', 'text': 'genius'},
          {'id': 'virtuoso', 'language': 'en', 'text': 'virtuoso'},
          {'id': 'maestro', 'language': 'en', 'text': 'maestro'},
          {'id': 'professional', 'language': 'en', 'text': 'professional'},
          {'id': 'adept', 'language': 'en', 'text': 'adept'},
          {'id': 'past_master', 'language': 'en', 'text': 'past master'},
          {'language': 'en', 'text': 'doyen'},
          {'language': 'en', 'text': 'champion'},
          {'language': 'en', 'text': 'star'},
          {'language': 'en', 'text': 'winner'}],
         'thesaurusLinks': [{'entry_id': 'ace',
           'sense_id': 't_en_gb0000173.001'}]},
        {'definitions': ['(in tennis and similar games) a service that an opponent is unable to return and thus wins a point'],
         'domains': [{'id': 'tennis', 'text': 'Tennis'}],
         'examples': [{'text': 'Nadal banged down eight aces in the set'}],
         'id': 'm_en_gbus0005680.013',
         'shortDefinitions': ['(in tennis and similar games) service that opponent is unable to return and thus wins point'],
         'subsenses': [{'definitions': ['a hole in one'],
           'domains': [{'id': 'golf', 'text': 'Golf'}],
           'examples': [{'text': "his hole in one at the 15th was Senior's second ace as a professional"}],
           'id': 'm_en_gbus0005680.014',
           'registers': [{'id': 'informal', 'text': 'Informal'}],
           'shortDefinitions': ['hole in one']}]}]}],
     'language': 'en-gb',
     'lexicalCategory': {'id': 'noun', 'text': 'Noun'},
     'phrases': [{'id': 'an_ace_up_one%27s_sleeve',
       'text': "an ace up one's sleeve"},
      {'id': 'hold_all_the_aces', 'text': 'hold all the aces'},
      {'id': 'play_one%27s_ace', 'text': "play one's ace"},
      {'id': 'within_an_ace_of', 'text': 'within an ace of'}],
     'pronunciations': [{'audioFile': 'http://audio.oxforddictionaries.com/en/mp3/ace_1_gb_1_abbr.mp3',
       'dialects': ['British English'],
       'phoneticNotation': 'IPA',
       'phoneticSpelling': 'eɪs'}],
     'text': 'ace'},
    {'entries': [{'homographNumber': '101',
       'senses': [{'definitions': ['very good'],
         'examples': [{'text': 'an ace swimmer'},
          {'notes': [{'text': 'as exclamation', 'type': 'grammaticalNote'}],
           'text': "Ace! You've done it!"}],
         'id': 'm_en_gbus0005680.016',
         'registers': [{'id': 'informal', 'text': 'Informal'}],
         'shortDefinitions': ['very good'],
         'synonyms': [{'id': 'excellent',
           'language': 'en',
           'text': 'excellent'},
          {'language': 'en', 'text': 'very good'},
          {'id': 'first-rate', 'language': 'en', 'text': 'first-rate'},
          {'language': 'en', 'text': 'first-class'},
          {'id': 'marvellous', 'language': 'en', 'text': 'marvellous'},
          {'id': 'wonderful', 'language': 'en', 'text': 'wonderful'},
          {'language': 'en', 'text': 'magnificent'},
          {'id': 'outstanding', 'language': 'en', 'text': 'outstanding'},
          {'id': 'superlative', 'language': 'en', 'text': 'superlative'},
          {'id': 'formidable', 'language': 'en', 'text': 'formidable'},
          {'id': 'virtuoso', 'language': 'en', 'text': 'virtuoso'},
          {'id': 'masterly', 'language': 'en', 'text': 'masterly'},
          {'id': 'expert', 'language': 'en', 'text': 'expert'},
          {'language': 'en', 'text': 'champion'},
          {'language': 'en', 'text': 'fine'},
          {'language': 'en', 'text': 'consummate'},
          {'id': 'skilful', 'language': 'en', 'text': 'skilful'},
          {'id': 'adept', 'language': 'en', 'text': 'adept'}],
         'thesaurusLinks': [{'entry_id': 'ace',
           'sense_id': 't_en_gb0000173.002'}]}]}],
     'language': 'en-gb',
     'lexicalCategory': {'id': 'adjective', 'text': 'Adjective'},
     'phrases': [{'id': 'an_ace_up_one%27s_sleeve',
       'text': "an ace up one's sleeve"},
      {'id': 'hold_all_the_aces', 'text': 'hold all the aces'},
      {'id': 'play_one%27s_ace', 'text': "play one's ace"},
      {'id': 'within_an_ace_of', 'text': 'within an ace of'}],
     'pronunciations': [{'audioFile': 'http://audio.oxforddictionaries.com/en/mp3/ace_1_gb_1_abbr.mp3',
       'dialects': ['British English'],
       'phoneticNotation': 'IPA',
       'phoneticSpelling': 'eɪs'}],
     'text': 'ace'},
    {'entries': [{'grammaticalFeatures': [{'id': 'transitive',
         'text': 'Transitive',
         'type': 'Subcategorization'}],
       'homographNumber': '102',
       'senses': [{'definitions': ['(in tennis and similar games) serve an ace against (an opponent)'],
         'domains': [{'id': 'tennis', 'text': 'Tennis'}],
         'examples': [{'text': 'he can ace opponents with serves of no more than 62 mph'}],
         'id': 'm_en_gbus0005680.020',
         'registers': [{'id': 'informal', 'text': 'Informal'}],
         'shortDefinitions': ['(in tennis and similar games) serve ace against'],
         'subsenses': [{'definitions': ['score an ace on (a hole) or with (a shot)'],
           'domains': [{'id': 'golf', 'text': 'Golf'}],
           'examples': [{'text': 'there was a prize for the first player to ace the hole'}],
           'id': 'm_en_gbus0005680.026',
           'shortDefinitions': ['score ace on hole or with']}]},
        {'definitions': ['achieve high marks in (a test or exam)'],
         'examples': [{'text': 'I aced my grammar test'}],
         'id': 'm_en_gbus0005680.028',
         'regions': [{'id': 'north_american', 'text': 'North_American'}],
         'registers': [{'id': 'informal', 'text': 'Informal'}],
         'shortDefinitions': ['achieve high marks in'],
         'subsenses': [{'definitions': ['outdo someone in a competitive situation'],
           'examples': [{'text': 'the magazine won an award, acing out its rivals'}],
           'id': 'm_en_gbus0005680.029',
           'notes': [{'text': '"ace someone out"', 'type': 'wordFormNote'}],
           'shortDefinitions': ['outdo someone in competitive situation']}]}]}],
     'language': 'en-gb',
     'lexicalCategory': {'id': 'verb', 'text': 'Verb'},
     'phrases': [{'id': 'an_ace_up_one%27s_sleeve',
       'text': "an ace up one's sleeve"},
      {'id': 'hold_all_the_aces', 'text': 'hold all the aces'},
      {'id': 'play_one%27s_ace', 'text': "play one's ace"},
      {'id': 'within_an_ace_of', 'text': 'within an ace of'}],
     'pronunciations': [{'audioFile': 'http://audio.oxforddictionaries.com/en/mp3/ace_1_gb_1_abbr.mp3',
       'dialects': ['British English'],
       'phoneticNotation': 'IPA',
       'phoneticSpelling': 'eɪs'}],
     'text': 'ace'}],
   'type': 'headword',
   'word': 'ace'},
  {'id': 'ace',
   'language': 'en-gb',
   'lexicalEntries': [{'entries': [{'etymologies': ['early 21st century: abbreviation of asexual, with alteration of spelling on the model of ace'],
       'homographNumber': '200',
       'senses': [{'definitions': ['a person who has no sexual feelings or desires'],
         'domains': [{'id': 'sex', 'text': 'Sex'}],
         'examples': [{'text': 'both asexual, they have managed to connect with other aces offline'}],
         'id': 'm_en_gbus1190638.004',
         'shortDefinitions': ['asexual person']}]}],
     'language': 'en-gb',
     'lexicalCategory': {'id': 'noun', 'text': 'Noun'},
     'pronunciations': [{'audioFile': 'http://audio.oxforddictionaries.com/en/mp3/ace_1_gb_1_abbr.mp3',
       'dialects': ['British English'],
       'phoneticNotation': 'IPA',
       'phoneticSpelling': 'eɪs'}],
     'text': 'ace'},
    {'entries': [{'homographNumber': '201',
       'senses': [{'definitions': ['(of a person) having no sexual feelings or desires; asexual'],
         'domains': [{'id': 'sex', 'text': 'Sex'}],
         'examples': [{'text': "I didn't realize that I was ace for a long time"}],
         'id': 'm_en_gbus1190638.006',
         'shortDefinitions': ['asexual']}]}],
     'language': 'en-gb',
     'lexicalCategory': {'id': 'adjective', 'text': 'Adjective'},
     'pronunciations': [{'audioFile': 'http://audio.oxforddictionaries.com/en/mp3/ace_1_gb_1_abbr.mp3',
       'dialects': ['British English'],
       'phoneticNotation': 'IPA',
       'phoneticSpelling': 'eɪs'}],
     'text': 'ace'}],
   'type': 'headword',
   'word': 'ace'}],
 'word': 'ace'}

Přistupování k tweetům přes Twitter API pomocí knihovny Tweepy

Příkaz na instalaci knihovny tweepy uvnitř notebooku. Stačí odkomentovat a spustit.

In [45]:
#%pip install tweepy

Import knihovny Tweepy

In [46]:
import tweepy

Pro získání dat z Twitteru musí náš klient projít OAuth autorizací.

Jak funguje OAuth autorizace na Twitteru?

  1. vývojář aplikace se zaregistruje u poskytovatele API
  2. zaregistruje aplikaci, získá consumer_key, consumer_secret, access_token a access_secret na https://developer.twitter.com/en/apps
  3. aplikace volá API a prokazuje se consumer_key, consumer_secret, access_token a access_secret

Opět, přístupové údaje už po lekci fungovat nebudou. Pro další průzkum bude potřeba udělat si vlastní registraci.

In [47]:
consumer_key = "2v7VOqqG01BZaK20QImzUlbuk"
consumer_secret = "jD0vrWDgiBdFBR15jOfpOSnRfjyPVQeztSKJXonbt5qHtrPUB3"
access_token = "102983608-rwLGu2zXw5XvgByk9XHoXUbU5ZyDzDggMg26epGn"
access_secret = "aMKyBBOpAJTVrcnuKuxzYMcgJlDXLgLlkCsQZPKwTOqhh"

Další krok je vytvoření instance OAuthHandleru, do kterého vložíme náš consumer token a consumer secret

In [48]:
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_secret)

Ověření funkčnosti autentifikace

In [49]:
api = tweepy.API(auth)

try:
    api.verify_credentials()
    print("Authentication OK")
except Exception:
    print("Error during authentication")
Authentication OK

V API dokumentaci k Tweepy http://docs.tweepy.org/en/v3.5.0/api.html najdeme metodu která např. vypíše ID přátel, resp. sledujících účtu

In [50]:
api.friends_ids('@kdnuggets')[:20]
Out[50]:
[1236557193752657926,
 785618379201654784,
 1408142352,
 1720046887,
 1223302770771595265,
 453124512,
 357606935,
 3363584909,
 133028836,
 427089628,
 2711212681,
 865622395,
 1482581556,
 130745589,
 1034844617261248512,
 68746721,
 204014237,
 14567619,
 731279155,
 911297187664949248]

Nebo vypíše ID, které účet sleduje

In [51]:
api.followers_ids('@kdnuggets')[:20]
Out[51]:
[43787434,
 1241954399200653314,
 704134333510975489,
 1111600265982107649,
 1195612679710400512,
 1239601251375071233,
 1228367607209889793,
 1236518605895991296,
 110091822,
 407635381,
 758284065661419520,
 805670766503084032,
 933118891315703808,
 346474415,
 956356673882517505,
 106900152,
 779250326574596096,
 1147329370458972160,
 1242559364919177220,
 1179831345712893958]

Metoda, která vrátí posledních 20 tweetů podle ID uživatele

In [52]:
twitter_user = api.user_timeline('@kdnuggets')
In [53]:
kdnuggets_tweets = [i.text for i in twitter_user]
print(kdnuggets_tweets)
['KDnuggets 20:n12: 24 Best (and Free) Books To Understand #MachineLearning; #Coronavirus Daily Change and Poll Analy… https://t.co/lDYwOe81ri', 'Customer Churn Prediction Using #MachineLearning: Main Approaches and Models #KDN https://t.co/7BCMF3A1O2', '#Coronavirus Deaths by US State and Country Over Time: Daily Tracking @nytimes https://t.co/X9fPwdgrfV https://t.co/tqsDnSJBaN', 'Custom classifier on top of #BERT-like Language Model - guide #DeepLearning #PyTorch #NLP https://t.co/iKOdHDD5zJ https://t.co/BcS5mJIzW7', 'How to build an API for a #MachineLearning model in 5 minutes using Flask #KDN https://t.co/OsIP2AFnLO', 'Using topological text analysis for COVID-19 Open Research Challenge https://t.co/8lCzJpMNrv https://t.co/g4FlZk0fAi', 'The History of Euler’s Number, E=2.718281828 ... https://t.co/RtmFgVfGny https://t.co/PdOt9EpKnj', 'An Easy Introduction to #MachineLearning Recommender Systems #KDN https://t.co/NNN18ZJPw0', 'Excellent source of #Coronavirus info - @FinancialTimes  the latest figures - Free to read https://t.co/WGOiJrv91t https://t.co/oWllgHte5h', '#Coronavirus cases by country trend @tableau public dashboard https://t.co/3st2aJGVxB https://t.co/JXuILSMTqw', 'How To Ultralearn #DataScience: summary, for those in a hurry #KDN https://t.co/hSZEE6jBqj', 'While you might be stuck inside, you can keep learning and exploring with these online AI resources.… https://t.co/95SGuvlkeL', '10 Best and #Free #MachineLearning Courses, Online #KDN https://t.co/QuaACqgQiF', 'Webinar: @thisismetis will break down #Python for #datascience and analytics, explain what is driving its adoption,… https://t.co/ESf2VQ31xY', 'MIT #COVID19 Challenge - Beat the #coronavirus Pandemic - April 3-5 Virtual #Hackathon  https://t.co/WgOxIHynBw https://t.co/y1KPyVE5JG', 'How to Speed up Pandas by 4x with one line of code #KDN https://t.co/MGSSoERsyI', 'predictions by @Datarobot US counties likely to have 1st first #coronavirus cases in the next 5, as of Mar 23: VA\xa0C… https://t.co/HheuNzjPhq', 'Useful #Coronavirus / #COVID19  Dashboards to track the spread https://t.co/OcK7j7lWk3 https://t.co/nYeJd7LGtS', 'Python and R Courses for #DataScience #KDN https://t.co/qf4fzWKnbf', 'Why BERT Fails in Commercial Environments - KDnuggets https://t.co/fH2zjx1UxC https://t.co/W28ZxyBYq8']
In [54]:
def get_tweets(consumer_key, consumer_secret, access_token, access_secret, twitter_account):
    """
    Function gets the last 20 tweets and adds those not in the list
    
    Five arguments consumer_key, consumer_secret, access_token, access_secret, and twitter_account name
    
    Returns a dataframe with tweets for given account
    """
    
    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_secret)
    api = tweepy.API(auth)

    try:
        api.verify_credentials()
        print("Authentication OK")
        twitter_user = api.user_timeline(twitter_account)
        
        tweets_list = [i.text for i in twitter_user]
                      
    except Exception:
        print("Error during authentication")
    
    return pd.DataFrame(tweets_list, columns = [twitter_account])
In [55]:
get_tweets(consumer_key, consumer_secret, access_token, access_secret, '@kdnuggets')
Authentication OK
Out[55]:
@kdnuggets
0 KDnuggets 20:n12: 24 Best (and Free) Books To ...
1 Customer Churn Prediction Using #MachineLearni...
2 #Coronavirus Deaths by US State and Country Ov...
3 Custom classifier on top of #BERT-like Languag...
4 How to build an API for a #MachineLearning mod...
5 Using topological text analysis for COVID-19 O...
6 The History of Euler’s Number, E=2.718281828 ....
7 An Easy Introduction to #MachineLearning Recom...
8 Excellent source of #Coronavirus info - @Finan...
9 #Coronavirus cases by country trend @tableau p...
10 How To Ultralearn #DataScience: summary, for t...
11 While you might be stuck inside, you can keep ...
12 10 Best and #Free #MachineLearning Courses, On...
13 Webinar: @thisismetis will break down #Python ...
14 MIT #COVID19 Challenge - Beat the #coronavirus...
15 How to Speed up Pandas by 4x with one line of ...
16 predictions by @Datarobot US counties likely t...
17 Useful #Coronavirus / #COVID19 Dashboards to ...
18 Python and R Courses for #DataScience #KDN htt...
19 Why BERT Fails in Commercial Environments - KD...

Kam dál?

API existuje celá řada. Některé jsou veřejně dostupné, jiné mají omezený přístup nebo se za ně platí, ale to svoje si najde úplně každý. Na internetu se válí i spousta seznamů, jako je tento na Githubu, kde je možné začít pátrat po tom pravém API pro tebe.


Toto je stránka lekce z kurzu, který probíhá nebo proběhl naživo s instruktorem.