ホームページ  >  記事  >  バックエンド開発  >  BoardGameGeek Python を使用したボードゲーム データの取得

BoardGameGeek Python を使用したボードゲーム データの取得

Patricia Arquette
Patricia Arquetteオリジナル
2024-10-15 22:15:02622ブラウズ

BoardGameGeek board games data fetching with Python

このスクリプトは、BoardGameGeek API からボード ゲーム データを取得し、CSV ファイルにデータを保存します。 API 応答は XML 形式であり、複数のボード ゲーム データを一度に取得するためのエンドポイントがないため、ボード ゲーム ID に基づいて 1 つのボード ゲームをエンドポイントにリクエストし、インクリメントすることで機能します。指定された範囲の ID 内の各リクエスト後の ID。

GitHub プロフィールのリポジトリをチェックしてください

各ボード ゲームについて取得および保存される情報は次のとおりです:

名前、game_id、レーティング、ウェイト、year_published、min_players、max_players、min_play_time、max_pay_time、min_age、owned_by、カテゴリ、メカニクス、デザイナー、アーティスト、パブリッシャー。

まず、このスクリプトに必要なライブラリをインポートします。

# Import libraries
from bs4 import BeautifulSoup
from csv import DictWriter
import pandas as pd
import requests
import time

リクエストのヘッダーと各リクエスト間の一時停止 (秒単位) を定義する必要があります。リクエストのレート制限に関する情報は BGG API ドキュメントには記載されておらず、フォーラムには 1 秒あたり 2 リクエストに制限されているという非公式情報がいくつかあります。スクリプトが制限レートに達し始めた場合は、リクエスト間の一時停止を調整する必要がある場合があります。

# Define request url headers
headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:85.0) Gecko/20100101 Firefox/85.0",
    "Accept-Language": "en-GB, en-US, q=0.9, en"
}

# Define sleep timer value between requests
SLEEP_BETWEEN_REQUEST = 0.5

次に、BGG から取得して処理する必要があるボード ゲーム ID の範囲を定義します。このスクリプトの作成時点では、既存のボードゲーム データが存在する範囲の上限は約 402000 ID であり、この数は将来的に増加する可能性が最も高くなります。

# Define game ids range
game_id = 264882 # initial game id
last_game_id = 264983 # max game id (currently, it's around 402000)

以下はIDの範囲に基づいてスクリプトが完了したときに呼び出される関数です。また、リクエスト時にエラーが発生した場合、例外が発生した時点までにゲーム リストに追加されたすべてのデータを保存するために、この関数が呼び出されます。

# CSV file saving function
def save_to_csv(games):
    csv_header = [
        'name', 'game_id', 'rating', 'weight', 'year_published', 'min_players', 'max_players',
        'min_play_time', 'max_play_time', 'min_age', 'owned_by', 'categories',
        'mechanics', 'designers', 'artists', 'publishers'
    ]
    with open('BGGdata.csv', 'a', encoding='UTF8') as f:
        dictwriter_object = DictWriter(f, fieldnames=csv_header)
        if f.tell() == 0:
            dictwriter_object.writeheader()
        dictwriter_object.writerows(games)

次の部分は、このスクリプトのメイン ロジックです。 ID の範囲内でコードが実行されます。つまり、BGG API にリクエストを出し、BeautifulSoup を使用してすべてのデータを取得し、データがボード ゲームに関連しているかどうか必要なチェックを行います (関連するデータがあります)。詳細については、BGG API を参照してください。)、その後、データが処理されてゲーム リストに追加され、最終的に CSV ファイルに保存されます。

# Create an empty 'games' list where each game will be appended
games = []

while game_id <= last_game_id:
    url = "https://boardgamegeek.com/xmlapi2/thing?id=" + str(game_id) + "&stats=1"

    try:
        response = requests.get(url, headers=headers)
    except Exception as err:
        # In case of exception, store to CSV the fetched items up to this point.
        save_to_csv(games)
        print(">>> ERROR:")
        print(err)


    soup = BeautifulSoup(response.text, features="html.parser")
    item = soup.find("item")

    # Check if the request returns an item. If not, break the while loop
    if item:
        # If the item is not a board game - skip
        if not item['type'] == 'boardgame':
            game_id += 1
            continue

        # Set values for each field in the item
        name = item.find("name")['value']
        year_published = item.find("yearpublished")['value']
        min_players = item.find("minplayers")['value']
        max_players = item.find("maxplayers")['value']
        min_play_time = item.find("minplaytime")['value']
        max_play_time = item.find("maxplaytime")['value']
        min_age = item.find("minage")['value']
        rating = item.find("average")['value']
        weight = item.find("averageweight")['value']
        owned = item.find("owned")['value']
        categories = []
        mechanics = []
        designers = []
        artists = []
        publishers = []

        links = item.find_all("link")

        for link in links:
            if link['type'] == "boardgamecategory":
                categories.append(link['value'])
            if link['type'] == "boardgamemechanic":
                mechanics.append(link['value'])
            if link['type'] == "boardgamedesigner":
                designers.append(link['value'])
            if link['type'] == "boardgameartist":
                artists.append(link['value'])
            if link['type'] == "boardgamepublisher":
                publishers.append(link['value'])

        game = {
            "name": name,
            "game_id": game_id,
            "rating": rating,
            "weight": weight,
            "year_published": year_published,
            "min_players": min_players,
            "max_players": max_players,
            "min_play_time": min_play_time,
            "max_play_time": max_play_time,
            "min_age": min_age,
            "owned_by": owned,
            "categories": ', '.join(categories),
            "mechanics": ', '.join(mechanics),
            "designers": ', '.join(designers),
            "artists": ', '.join(artists),
            "publishers": ', '.join(publishers),
        }

        # Append the game (item) to the 'games' list

        games.append(game)

    else:
        # If there is no data for the request - skip to the next one
        print(f">>> Empty item. Skipped item with id ({game_id}).")
        game_id += 1
        continue

    # Increment game id and set sleep timer between requests
    game_id += 1
    time.sleep(SLEEP_BETWEEN_REQUEST)

save_to_csv(games)    

以下では、CSV ファイル内のレコードの最初の数行を pandas DataFrame としてプレビューできます。

# Preview the CSV as pandas DataFrame
df = pd.read_csv('./BGGdata.csv')
print(df.head(5))

以上がBoardGameGeek Python を使用したボードゲーム データの取得の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。