1から始めるPythonデータ分析 - やりたいこと逆引きリスト ▶︎▶︎

ポケモンで学ぶPython|#0 PokeAPIでポケモンデータを取得する

ポケモンのデータを取得するPokeAPI

今回は皆さんご存知の「ポケモン」に関するデータを、APIを利用して簡単に手元で扱えるようにする方法をご紹介します

アニメやゲームで有名なポケットモンスター(ポケモン)ですが、2021年現在、897匹ものモンスターが存在しています

そして各ポケモンそれぞれにユニークな能力、見た目が与えられています

今回は「Python」のAPI機能を利用して、ポケモンの情報を簡単に取得する方法をご説明します

PokeAPI

ポケモンの情報を取得できるPoke APIの公式サイトはこちらから

※リファレンスはしっかりしていますが、全て英語で書かれています

事前準備

APIでのデータ取得に必要なrequestsと、DataFrameの処理に必要なPandasを事前にインポートしておきましょう

import requests
import pandas as pd

PokeAPIを利用しポケモンの基本情報を取得する

まずはポケモンの基本的な情報(名前やタイプ、ステータス)をAPIから取得します

※単純にコードを記述するだけではなく、それぞれ説明していきます

最終的には繰り返し処理を用いて、全ポケモン分のデータを取得しますが、まずはNo1のフシギダネのデータから取得しましょう

① エンドポイント(URL)の確認

まずはPokeAPIのエンドポイント(URL)を指定します

基本は下記のURLを利用します


そこからポケモンの情報を取得したい場合は/pokemonをURLに追加したり、

進化に関する情報を取得したい場合は/evolution-chainをURLを追加したりします


さらに上記URLの末尾に「ポケモン固有のID」か「英語のポケモン名」を指定すれば、そのポケモンの情報を取得することができます

「ピカチュウ」は「ID=25」で「pikachu」という名前です

ピカチュウの画像
出典:Poke API(https://pokeapi.co/)
注意

Pythonの繰り返し処理を実施するために、ポケモンのURL指定は数値(1.2.3…)で指定します

② GETリクエストでデータを取得

さっそくフシギダネのデータを取得していきましょう

# 事前にrequestsをインポートしておく
import requests

# フシギダネ(No.1)の基本情報を取得するエンドポイント(URL)
url = "https://pokeapi.co/api/v2/pokemon/1"

# GETリクエストでデータを取得し、JSON形式に変える
response = requests.get(url)
pokemon_data = response.json()

# データを見る
pokemon_data
ポケモンデータのJSON

JSON形式でフシギダネのデータを取得することができました

ただし/pokemon では「名前」や「タイプ」「高さ」などのデータに加えて、「ゲーム時の情報」や「形」など必要以上に細かいデータが入っています

③ 取得したいデータの指定

JSON形式のデータは取得できたので、あとは必要なデータを絞るために添え字で情報を限定します

名前を取得するためにpokemon_dataのJSON形式の変数に対し、下記を指定します

# JSON形式の変数に対し、名前を指定する
pokemon_data['name']

bulbasaur」という文字列が出てきました

これは英語名で、日本語では「フシギダネ」のことです

フシギダネの画像
出典:Poke API(https://pokeapi.co/)

他にもデータを取得してみます(ID、名前、高さ、重さ)

また変数に格納してprintで出力してみます

# ID、名前、高さ、重さを変数に格納する
id = pokemon_data['id']
name = pokemon_data['name']
height = pokemon_data['height']
weight = pokemon_data['weight']

print(id,name,height,weight)

④ DataFrameに格納

データ分析に適した形に変換するために、JSON形式で取得できたデータをPandasのDataframeに格納していきます

繰り返し処理でも利用するため変数をかませる方法を使用しています

# 事前に変数を作成
result = []

# 情報を変数に格納
id = pokemon_data['id']
name = pokemon_data['name']
height = pokemon_data['height']
weight = pokemon_data['weight']

# resultという変数に、上記情報を追加(append)する
result.append([id,name,height,weight])

# resultをDataFrameの形式に変換
df = pd.DataFrame(result,columns=['id','name','height','weight'])
df.head()
PokeAPIで取得したポケモンのデータ

appendを利用し、JSON形式で取得したデータをDataFrameに格納する処理を実施しました

⑤ 繰り返し処理で複数のポケモンの情報を取得

forを利用して「No.1:フシギダネ」から「No.10:キャタピー」の情報を取得します

また繰り返し処理の過程でDataFrameへ都度格納していくと、最終的に各ポケモンのデータが取得できます

# 取得するポケモン数を決めておく(今回は10匹)
number = 10

result = []

# forを利用し、1から10までの繰り返し処理を実施
for i in range(1,number+1):

  # URLの末尾にrangeの数値を入れる
  url = "https://pokeapi.co/api/v2/pokemon/" + str (i)
  response = requests.get(url)
  pokemon_data = response.json()

  id = pokemon_data['id']
  name = pokemon_data['name']
  height = pokemon_data['height']
  weight = pokemon_data['weight']

  result.append([id,name,height,weight])
  df = pd.DataFrame(result,columns=['id','name','height','weight'])
df
PokeAPIで取得したポケモンのデータ

上記手法では変数をカラム分書く必要があるため、もっと簡単にかける方法を利用します

また「types:タイプ」「stats:ステータス」「sprites:ポケモン画像」を追加で取得します

number = 10

# 必要なカラムをリストで用意しておく
required_tags = ['id','name','height','weight','types','stats','sprites']
result = []
for i in range(1,number+1):

  url = "https://pokeapi.co/api/v2/pokemon/" + str (i)
  response = requests.get(url)
  pokemon_data = response.json()
  
  # JSON形式の変数からKeyを順に取り出し、先ほどのリストに当てはまらなかったら削除(不要なKeyを消す)
  for key in list(pokemon_data.keys()):
      if key not in required_tags:
        del pokemon_data[key]

  result.append(pokemon_data)
  df = pd.DataFrame(result)
df
PokeAPIで取得したポケモンのデータ

この書き方だと取得するカラム数が増えたとしても、簡潔に記述することが可能です

また新しく追加したカラムをよく見ると、単純なデータではなく「ネストされた値」になっています

⑥ ネストされた値を取得する

先ほど設定したDataFrameの「stats」というカラムを見ると、さらに複雑な形をしています

PokeAPIで取得したポケモンのデータ

「stats」だけを取り出してみます

df['stats']
PokeAPIで取得したポケモンのデータ

ここから「フシギダネ」のNo.1を指定するためには[0]添え字を付けます

# フシギダネを指定
df['stats'][0]
PokeAPIで取得したポケモンのデータ

さらに複雑な形式になっていますが、一段目にhp(体力)・二段目にattack(こうげき)というように

ポケモンのステータスがそれぞれの段に格納されています


詳細化していくと、どんどん情報が絞られていきます

# フシギダネのこうげきステータスを指定
df['stats'][0][1]
PokeAPIで取得したポケモンのデータ

# フシギダネのこうげきステータスの値(base_stat)を指定
df['stats'][0][1]['base_stat']

最終的に「こうげき:49」という値を取得することができました

かなり細かい指定方法になってしまいしたが、これをDataFrameとして格納していきます


先ほどのDataFrameの「stats」の情報を、別の変数として取り出します

結合ができるように「id」の情報も合わせて取得しておきましょう

# 事前にリストを準備
stats_list = []

# 先ほどのDataFrameのデータ数をshapeで取得し、必要情報をリストに追加
for i in range(df.shape[0]):
  stats_list.append([
  df['id'][i],
  df['stats'][i][0]['base_stat'], #hp
  df['stats'][i][1]['base_stat'], #attack
  df['stats'][i][2]['base_stat'], #defense
  df['stats'][i][3]['base_stat'], #special-attack
  df['stats'][i][4]['base_stat'], #special-defense
  df['stats'][i][5]['base_stat'], #speed
  df['sprites'][i]['other']['official-artwork']['front_default'] #ポケモン画像
  ])

# 別名のDataFrameとして追加しておく
df_stats = pd.DataFrame(stats_list,columns=['id','hp','attack','defense','special-attack','special-defense','speed','png'])
df_stats
PokeAPIで取得したポケモンのデータ

⑦ 基本情報とステータスをIDで結合

最初に取得していたデータ(df)と、ステータスを分解したデータ(df_stats)をIDで結合します

df = df.merge(df_stats, on='id', how='left')
df.dtypes
PokeAPIで取得したポケモンのデータ

データ数が多いためdtypesでカラム名のみ可視化しています

「name:名前」や「height:高さ」に加えて、「hp:体力」や「attack:こうげき」などの情報が追加されました

【Python】merge|2つのデータを結合する方法

⑧ 情報が無い場合の分岐処理

「ステータス」に関しては必ずデータが存在していましたが、データがある場合とない場合があるものも存在します

例えばポケモンの「タイプ」は1種類だけ持っている場合と、2種類持っている場合があります

リザードン(charizard)は「ほのお」と「ひこう」の2種類持ちです

ポケモンのリザードンの画像
出典:Poke API(https://pokeapi.co/)
# リザードン(「ほのお」と「ひこう」の2種類のタイプ持ち)
df['types'][5]

図のように「fire:ほのお」と「flying:ひこう」の二段のデータが存在します


今回問題になるのが、タイプが1つだけの場合です

リザードンの進化前であるヒトカゲ(charmander)は「ほのお」タイプのみです

ポケモンのヒトカゲの画像
出典:Poke API(https://pokeapi.co/)
# ヒトカゲ(「ほのお」タイプのみ)
df['types'][3]
PokeAPIで取得したポケモンのデータ

繰り返し処理を実施する際に2つ目のタイプが無い場合は、指定してしまうとエラーが出てしまいます

そこでtryexceptを活用して、2つ目のタイプが無い場合はNullを入れる処理を実施します

# Numpyを準備する
import numpy as np

type_list = []
for i in range(df.shape[0]):
  # タイプ1とタイプ2をリストに入れる(最初の処理)
  try:
    type_list.append([
    df['id'][i],
    df['types'][i][0]['type']['name'],
    df['types'][i][1]['type']['name']
    ])
  # タイプ1とNullをリストに入れる(最初の処理で失敗したときの処理)
  except:
    type_list.append([
    df['id'][i],
    df['types'][i][0]['type']['name'],
    np.nan
    ])
df_types = pd.DataFrame(type_list,columns=['id','type1','type2'])
df_types
PokeAPIで取得したポケモンのデータ

※IDとタイプしか出力されないため、名前を取得しております

タイプが1つしかない ヒトカゲ(charmander) の「type2」はNaNになっています

⑨ ポケモンの日本語名を取得

ポケモンの英語名だと分かりにくいため、日本語名を取得します

エンドポイント(URL)は/pokemon-speciesを利用します

required_tags = ['id','name','names']
result = []

x = 0
while x < number:
    x=x +1
    url = "https://pokeapi.co/api/v2/pokemon-species/" + str (x)
    response = requests.get(url)
    pokemon_data = response.json()
    for key in list(pokemon_data.keys()):
      if key not in required_tags:
        del pokemon_data[key]
    result.append(pokemon_data)

result
df_species = pd.DataFrame(result)
df_species.head()
PokeAPIで取得したポケモンのデータ

「names」には各国のポケモンの呼び方が存在しています

df_species['names'][0]
PokeAPIで取得したポケモンのデータ

繰り返し処理で日本語名とIDのDataFrameを作成します

name_list = []
for i in range(df_species.shape[0]):
  name_list.append([
  df_species['id'][i],
  df_species['names'][i][0]['name']
  ])
df_name = pd.DataFrame(name_list,columns=['id','ja_name'])
df_name.head()
PokeAPIで取得したポケモンのデータ

IDをキーとして結合をすれば完成です

df = df.merge(df_name, on='id', how='left')

まとめ

今回はPythonのAPIを利用して簡単に手元で扱えるようにする方法をご紹介してきました

PokeAPIを利用することで簡単にポケモンの情報を取得することができます

繰り返し処理を全ポケモン分で実施することで、全てのポケモンの情報を取得します

最終的にはこのようなデータが完成しました

ポケモンのデータ一覧

Excelデータもご用意しているので、ぜひ手元で確認してみてください

ポケモンのデータ(Excel:105 KB)

ポケモンで学ぶPython|#1 セットアップを始めよう
お気に入り登録お願いします

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です