Göm menyn

Laboration 3 - API-anrop och dictionaries

I denna laboration kommer ni att få arbeta med en grundläggande API - Application Programming Interface - för att samla ihop och filtrera information om Pokémon. Denna data kommer att hämtas från en API med hjälp av nätverksanrop, och den data ni får tillbaka kommer att vara i JSON-format.

Kort om modulen requests

För att göra det enkelt att hämta data via nätverksanrop så kommer vi att använda en modul som heter requests. Denna modul gör det väldigt enkelt att skicka t.ex. en GET-request till en server och att ta emot svaret från webbservern. Exakt hur detta objekt ser ut behöver vi inte känna till i detta skede, utan vi kan se det som en abstrakt datatyp som vi endast behöver veta hur vi interagerar med.

För att använda requests kommer denna modul eventuellt att behöva installeras. Du kan kolla om requests är installerat med följande kommando:

pip freeze | grep requests

Ser ni någonting i terminalen när ni kör detta kommando är paketet redan installerat. Får ni inte upp någonting kan ni behöva installera paketet med följande kommando:

python3 -m pip install requests

Funkar inte kommandot alls kan pip behöva installeras. Kolla följande länk för lite instruktioner för att installera pip.Kolla följande länk för lite instruktioner för att installera pip.

Modulen kommer därefter att finnas tillgängligt att använda i era Python-projekt.

Medan modulen har rätt mycket funktionalitet så kommer vi främst att använda en metod - GET. Nedan följer ett exempel som ni kan testa att köra själva.

import requests

response = requests.get("https://www.ida.liu.se/~TDP002/pokeapi/api/v2/pokemon/")

Med denna funktion skickar vi ett anrop till den URL-sträng som skickas med som argument. Detta är precis som att gå in på webbsidan manuellt i webbläsaren! Testar man att gå in på länken i webbläsaren https://www.ida.liu.se/~TDP002/pokeapi/api/v2/pokemon/ så kommer det att se väldigt bekant ut - nämligen som en dict. Detta är den JSON-data som vi får tillbaka från requests.get om allting gick bra.

En annan viktig detalj är ifall nätverksanropet gick bra eller inte. Detta får vi reda på genom att titta på anropets statuskod. För denna labb är det viktigt att komma ihåg två statuskoder - 200 om allt gick bra, och 404 om det vi försökte hämta inte finns. En enkel startpunkt för denna labb är alltså följande kod:

import requests 

response = requests.get("https://www.ida.liu.se/~TDP002/pokeapi/api/v2/pokemon/")

if response.status_code == 200:
  print("Nätverksanropet lyckades!")

print(response.text)    # Skriver ut allt vi fick som svar 
                        # Bra för att se vad vi fått tillbaka
                        # vid ett nätverksanrop

data = response.json()  # Gör om det vi fick tillbaka till en dict

Något som troligtvis blir tydligt ganska tidigt är att ni ofta kommer att skicka ett nätverksanrop och få tillbaka denna data som en dict. Det är därför väldigt lämpligt att ha en hjälpfunktion som gör allt detta åt er på en specifik URL som ni skickar in -- annars kommer ni att behöva upprepa denna kod väldigt många gånger under labbens gång.

def request_to_dict(url):
  # Hämta eventuell JSON-data från den givna URL:en, kolla statuskoden
  # samt skicka tillbaka som en färdigkonverterad dict!
  return result_dict

Kort om PokéAPI

PokéAPI är en öppen webbtjänst som låter oss hämta information om diverse Pokémon genom enkla API-anrop. För att inte belasta deras servrar så hostas denna API lokalt hos oss på IDA.

Genom att besöka URL:en https://www.ida.liu.se/~TDP002/pokeapi/api/v2/pokemon/ ser vi vad vi får tillbaka när vi gör en GET-request till denna URL. Där ser vi en lista på alla Pokémons namn och vilken URL vi kan få mer information om denna Pokémon genom. För att hämta hem mer information om en specifik Pokémon kan vi alltså "bygga ihop" en URL för denna Pokémon.

Om vi besöker den URL som listades ovan ser vi till exempel att det ser ut ungefär så här:

{
    "count": 964,
    "next": null,
    "previous": null,
    "results": [
        {
            "name": "bulbasaur",
            "url": "/api/v2/pokemon/1/"
        },
    # Fler inlägg...
    ]
  }

Med detta kan vi få mer information om Bulbasaur genom att besöka denna URL: https://www.ida.liu.se/~TDP002/pokeapi/api/v2/pokemon/1 -- alltså genom att lägga till den URL som vi fick för Bulbasaur till API-länken.

Laborationsuppgift

I denna labb ska ni skapa en enkel applikation som kan hämta information om en viss Pokémon och visa upp den för användaren. Den information vi vill visa är specifikt alla dess abilities, och för varje inlägg i abilites ska även denna abilities flavor_text_entry skrivas ut på engelska. Ett exempel på hur skriptet ska se ut när man kör det syns nedan:

$ ./pokedex.py 
Enter a Pokémon name: pidgey

pidgey has 3 abilities.

Ability 'big-pecks':
Protects the Pokémon from
Defense-lowering effects.

Ability 'tangled-feet':
Raises evasion if the Pokémon is confused.

Ability 'keen-eye':
Keen eyes prevent other Pokémon from lowering this
Pokémon's accuracy.

Enter a Pokémon name: 

Någonting viktigt att tänka på är hur många gånger ni skickar en request till en viss URL. Att skicka en request är en dyr operation, och vi vill undvika att göra det allt för ofta. Ett krav till denna uppgift är därför att ni endast får göra ett rimligt antal requests per sökning, och att ni försöker undviker att skicka en request i onödan. Försök att tänka på vad ni kan behålla och vad ni behöver hämta, och om det är någonting ni kan spara undan så att ni slipper skicka en request för att få tag på det igen.

Tips

Modulen `pprint` (Pretty Print) kan hjälpa till att skriva ut en dict på ett mer läsbart sätt. (Exemplet nedan kommer inte att göra mycket annorlunda, men testa det på er data när ni gör labben!)

import pprint

my_dict = {1: "hello", 2: "world"}

# Vanlig print
print(my_dict)

# Pretty print
pprint.pp(my_dict)
Krav på inlämningen

Utöver att din kod fungerar enligt beskrivningarna och körexemplena ovan så behöver den uppfylla kraven nedan.

  • Er kod ska köras i ett huvudprogram som kan hantera flera sökningar
  • Er lösning ska skicka ett rimligt antal requests per sökning och spara undan relevant data vid behov
  • Er kod ska vara lämpligt uppdelad i funktioner med ett tydligt avgränsat syfte
  • Era funktioner skall ha tydliga namn och skall lösa de delproblem som namnet indikerar
  • Lämpliga val av datastrukturer för att lagra redan genomförda nätverksanrop
  • Skriptet ska fortsätta fungera även om ett nätverksanrop misslyckas eller om en Pokémon man sökt efter inte existerar

Sidansvarig: Pontus Haglund
Senast uppdaterad: 2024-09-05