見出し画像

【データの集め方講座】ポケモンの英和辞書を作る-Python×Selenium×PokemonAPI-

はじめに

ごあいさつ

ご高覧いただきありがとうございます.
ソフトウェアエンジニアのKitaharaです.
本日はSeleniumを使ってポケモンの英和辞書を作った後に辞書を使ってポケモンAPIを使ってみようと思います.

ポケモン英和辞典を作ろうと思ったきっかけ

先日ポケモンの最新作『Pokémon LEGENDS アルセウス』が発売されたとのことでポケモンのデータ収集できないかな…と考えていました.

そこでAPIが無いか探してみたところ, PokeAPIというRESTful APIを見つけました.

ただ, 調べてみたところ, 英語でリクエストを送るようなのでデータを調べるにはポケモンの英名が分かっていないといけないようです.

メタモン(Ditto)を検索

ピカチュウ(pikachu)のようにすべてのポケモンの英名が日本語とほぼ同じなら問題ないのですが, 実際はかなり違うようです.

そこで英和辞典を作ってみることにしました.

目標物

やることをまとめました

  • Seleniumを使ってインターネットサイトからポケモンの単語の日本語名と英語名を収集

  • [['日本語名', '英語名'], …, ['日本語名', '英語名']]のようなリストを作る

    • この際に英語は小文字英数字になるように正規化する

  • csvファイルの形式にして取得

    • csvファイルの形式にしておけば色々と便利です.

  • pokeAPIを日本語入力で動かしてみる

使用するものの説明

  • PokeAPI

    • 認証が無いオープンなポケモンのAPI

      • 無料でAPIを使用することができます

      • ポケモンの情報を収集することができる

    • Python用のライブラリが存在

      • pokebase

        • Python 3.6でテストされているそうです

      • pokepy

        • Python 2.7 | 3.4 | 3.5 | 3.6 | 3.7 | 3.8 で使うことができます

        • ドキュメントが読みやすくまとめられています.

        • 作り終わった後に気付きました…後ほど追記すると思います.

    • 公式ドキュメント

  • Python

    • プログラミング言語のひとつです.

    • 型宣言等が無く, 初心者にも扱いやすい言語だと言われています

    • 近年Deep Learningのライブラリが豊富であることから注目を集めている人気の言語です

    • 公式ドキュメント

  • Selenium

    • Webブラウザの操作を自動で行うためのフレームワークです

    • もともとはWebアプリケーションのテスト等で使うことを目的に開発されましたが, 現在ではWebスクレイピング(Webサイトからデータを取得すること)を目的に利用されることも多いです

    • 公式ドキュメント

  • Google Colab

    • Googleが提供するPythonの実行環境です

    • 主要なライブラリがインストールされている状態で使うことができます

    • Chromeでアクセスするだけで利用することができます

      • 環境構築が不要です

      • 無料で使うことができます

環境構築

まずはGoogle Colabに登録してSeleniumをインストールしましょう.
やり方が分からない方は下記の記事を参考にしてみてください.

seleniumの他にインストールするライブラリはありません!
お疲れ様でした.

ポケモンの英語名のデータを取得

ポケモンの日本語名・英語名のデータを取得する

下記のサイトに対してスクレイピングを実行します.

sleniumのchrome driverの場合, css selector を使うと非常に簡単にスクレイピングを実施することが可能です. (なお, このようなHTMLデータの場合, pandas.read_html()を使うという手もあります.)

chromeのディベロッパーツールで調べてみたところ, tbodyの下のtrに入っているようなのでcss selector を以下の用に設定します.

css selector は 'table tbody tr' にします

それではコードを書いていきましょう.
なお, version 4以前ですとfind_elements関数がfind_elements_by_css_selectorなので注意してください.

from selenium import webdriver
from selenium.webdriver.common.by import By

options = webdriver.ChromeOptions()
options.add_argument('--headless') # headlessモードを使用する
options.add_argument('--no-sandbox') # sandboxモードを解除する(クラッシュの回避)
options.add_argument('--disable-dev-shm-usage') # /dev/shmパーティションの使用を禁止にする(クラッシュの回避)
options.add_argument('--disable-extensions') # 拡張機能を無効にする


driver = webdriver.Chrome('chromedriver', options=options) # Driverを起動
driver.get('http://amalgame.jp/pokemon-eng-jpn/') # データを取得

# CSS セレクターを用いてクラスがrecipe-titlelinkのaタグを取得
# seleniumのversionが3以下だとfind_elements_by_css_selector(selector)なので注意
selector = 'table tbody tr'
elms = driver.find_elements(by=By.CSS_SELECTOR, value=selector)
print(elms)

# return
# [<selenium.webdriver.remote.webelement.WebElement...

データをリストの中に入れていきましょう

現在, elemsの中に各tr以下のデータが入っています.
私たちが欲しいデータはtextプロパティを使うと取り出すことができます.

そうするとカンマ区切りのstr型で出力されるのですが, このままでは使いにくいのでsplit関数でリストにしてしまいます.

split関数はカンマ区切りの文字列をカンマの部分で区切ったリストにしてくれます. 使う機会がそれなりにある関数です.

result = []
for i in range(len(elms)):
    data = [j for j in elms[i].text.split()]
    result.append(data)
print(result[:10])

# return
# [['1', 'フシギダネ', 'Bulbasaur'],
# ['2', 'フシギソウ', 'Ivysaur'],
# ['3', 'フシギバナ', 'Venusaur'],
# ['4', 'ヒトカゲ', 'Charmander'],
# ['5', 'リザード', 'Charmeleon'],
# ['6', 'リザードン', 'Charizard'],
# ['7', 'ゼニガメ', 'Squirtle'],
# ['8', 'カメール', 'Wartortle'],
# ['9', 'カメックス', 'Blastoise'],
# ['10', 'キャタピー', 'Caterpie']]

データの整形

データの内訳を調べてみたところ
ポケモンは「番号」「日本語名」「英語名」, それ以外のデータは「日本語名」「英語名」になっていることが分かりました.

また, 英語名に関しては, 単語間に半角の空白文字があったため, split 関数で区切られることが起こっているようでした. また, 半角英数字以外の文字も混じっているのでそれらを取り除く作業が必要です.

まとめると以下の作業をします

  • ポケモンとその他のデータごとにデータの整形を行う

    • 英語名の部分を一つにまとめる

    • 英語名を小文字に統一する

# ポケモンのリスト
pokemon_list = result[0:802]
pokemon_name_list = []
for i in range(len(pokemon_list)):
    pokemon_name_jp = pokemon_list[i][1] # ポケモンの要素番号0はポケモン図鑑番号なので使わない
    pokemon_name_en = ''
    for part_of_en_name in pokemon_list[i][2:]:
        pokemon_name_en += part_of_en_name.lower() # 小文字にする
    pokemon_name_list.append([pokemon_name_jp, pokemon_name_en]) 

# その他のリスト
others_list = result[802:]
others_name_list = []
for i in range(len(others_list)):
    others_name_jp = others_list[i][0]
    others_name_en = ''
    for part_of_en_name in others_list[i][1:]:
        others_name_en += part_of_en_name.lower() # 小文字にする
    others_name_list.append([others_name_jp, others_name_en]) 

# 各データが要素数2のリストになっているかチェックする
for i in range(len(pokemon_name_list)):
    if len(pokemon_name_list[i]) != 2:
        print('Error',pokemon_name_list[i])
print('done')
for i in range(len(others_name_list)):
    if len(others_name_list[i]) != 2:
        print('Error',others_name_list[i])
print('done')

二つのリストを合体させます.
出力して問題がないか確認しましょう.

jp_en_list = []
for i in range(len(result)):
    if i < 802:
        jp_en_list.append(pokemon_name_list[i])
    else:
        jp_en_list.append(others_name_list[i-802])
# 問題がないか確認
for i in range(len(jp_en_list)):
    print(jp_en_list[i])

おおむね問題はないのですが, 以下のような例がありました.

  • ハイフンが存在

    • ['ジャラコ', 'jangmo-o']

    • ['ジャランゴ', 'hakamo-o']

    • ['ジャラランガ', 'kommo-o']

  • カンマが存在

    • ['1000まんボルト', '10,000,000voltthunderbolt']

  • ハイフンが存在

    • ['キングシールド', 'king’sshield']

これらの表現をなくすためにもう一度処理をかけます.

en_jp_list_adjusted = []
for i in range(len(jp_en_list)):
    jp_name = jp_en_list[i][0]
    en_name = ''
    for j in range(len(jp_en_list[i][1])):
        if jp_en_list[i][1][j].isalnum():
            en_name += jp_en_list[i][1][j]
    en_jp_list_adjusted.append([jp_name, en_name])

英語名の一文字一文字に対して「英数字か?」という判定を行い, 英数字のみを文字列として加えています.

  • ハイフンが存在 =>解決

    • ['ジャラコ', 'jangmoo']

    • ['ジャランゴ', 'hakamoo']

    • ['ジャラランガ', 'kommoo']

  • カンマが存在 => 解決

    • ['1000まんボルト', '10000000voltthunderbolt'],

  • ハイフンが存在 => 解決

    • ['キングシールド', 'kingsshield'],

目標の形になったので, csvファイルとして保存します.
Google Colabは時間がたってしまうと接続が切れてしまい, 変数等がリセットされてしまうのですが, ファイルで保存しておけば, リセットされても心配ありません.

import pandas as pd
df = pd.DataFrame(en_jp_list_adjusted, columns = ['jp_name', 'en_name'])
df.to_csv('pokemon_en_jp_dict.csv') # defaultではutf-8

# windowsで見たいという方はencodingの設定を変えてみてください
# df.to_csv('pokemon_en_jp_dict_sjis.csv', encoding='shift-jis')

日本語入力でpokeAPIを呼び出す

先程作ったcsvファイルを読み込みましょう.
Google Colabの左にあるファイルマークをクリックするとこのような画面になっていると思うので, 確認してください.

もしsample_data以外にファイルが無い場合はcsvファイルのアップロードが必要ですので, 右クリックをしてアップロードを選択し, 先程作成したファイルをアップロードしましょう.

pokemon_en_jp_dictがあればOKです
import pandas
en_jp_df = pd.read_csv('pokemon_en_jp_dict.csv', index_col=0)

ファイルが読み込めたらAPIにリクエストを送ってみましょう.
ドキュメントはコチラ

# 日本語のポケモンの名前を英語に変換
pokemon_jp_name = 'リザードン'
pokemon_en_name = list(df[df['jp_name']==pokemon_jp_name]['en_name'])[0]
print(pokemon_en_name)

# return
# charizard
import requests
url = 'https://pokeapi.co/api/v2/pokemon/'+pokemon_en_name+'/'
response = requests.get(url)
print(response)

# return
# <Response [200]>

データの構造を見ていきます

results = response.json()
for result in results:
    print(result)

# return
# abilities
# base_experience
# form
# game_indices
# height
# held_items
# id
# is_default
# location_area_encounters
# moves
# name
# order
# past_types
# species
# sprites
# stats
# types
# weight

ドキュメントを確認してみたところmovesにポケモンの覚える「わざ」のデータが入っているようです.

折角なので日本語で出力してみましょう

for move in results['moves']:
    move_en_name = ''
    for string in move['move']['name']:
        if string.isalnum():
            move_en_name += string
    move_jp_name = list(df[df['en_name']==move_en_name]['jp_name'])[0]
    print(move_jp_name)

# return
# メガトンパンチ
# ほのおのパンチ
# かみなりパンチ...

これで日本語でもデータを検索できそうですね!
(※一部英語名を整形している関係上検索が失敗する可能性があります)

おわりに

今回はPythonとSelenium, PokeAPIを使って天気情報を取得をする方法を解説しました! 「参考になった!」「面白かった♪」という方はぜひハートボタンを押していってください!

モチベーションが上がります!

記事内で不明な点等ございましたら気軽にご連絡ください.

Twitter: @kitahara_dev
email: kitahara.main1@gmail.com


この記事が気に入ったらサポートをしてみませんか?