Rumah >pembangunan bahagian belakang >Tutorial Python >Pengambilan data permainan papan BoardGameGeek dengan Python

Pengambilan data permainan papan BoardGameGeek dengan Python

Patricia Arquette
Patricia Arquetteasal
2024-10-15 22:15:02760semak imbas

BoardGameGeek board games data fetching with Python

Skrip ini akan mengambil data permainan papan daripada API BoardGameGeek dan menyimpan data dalam fail CSV. Respons API adalah dalam format XML dan kerana tiada titik akhir untuk mengambil berbilang data permainan papan sekaligus, ini akan berfungsi dengan membuat permintaan kepada titik akhir untuk permainan papan tunggal berdasarkan ID permainan papan, sambil menambah ID selepas setiap permintaan dengan julat ID yang diberikan.

Lihat repo pada profil GitHub saya

Maklumat yang diambil dan disimpan untuk setiap permainan papan adalah seperti berikut:

nama, id_permainan, rating, berat, tahun_terbitan, min_players, max_players, min_play_time, max_pay_time, min_age, owned_by, kategori, mekanik, pereka bentuk, artis dan penerbit.

Kami bermula dengan mengimport perpustakaan yang diperlukan untuk skrip ini:

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

Kami perlu mentakrifkan pengepala untuk permintaan dan jeda antara setiap permintaan (dalam saat). Maklumat tentang had kadar permintaan tidak tersedia dalam dokumentasi API BGG dan terdapat beberapa maklumat tidak rasmi dalam forum mereka yang terhad kepada 2 permintaan sesaat. Jeda antara permintaan mungkin perlu dilaraskan, jika skrip mula mencapai kadar had.

# 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

Perkara seterusnya ialah menentukan julat ID permainan papan yang perlu diambil daripada BGG dan diproses. Pada masa mencipta skrip ini, had julat atas yang mempunyai data permainan papan sedia ada ialah lebih kurang 402000 id dan jumlah ini berkemungkinan besar akan meningkat pada masa hadapan.

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

Berikut ialah fungsi yang akan dipanggil apabila skrip selesai berdasarkan julat ID. Selain itu, jika terdapat ralat semasa membuat permintaan, fungsi ini akan dipanggil untuk menyimpan semua data yang dilampirkan pada senarai permainan sehingga tahap pengecualian berlaku.

# 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)

Bahagian berikut adalah logik utama skrip ini. Ia akan melaksanakan kod semasa dalam julat ID, yang bermaksud ia akan membuat permintaan kepada API BGG, mendapatkan semua data dengan menggunakan BeautifulSoup, membuat semakan yang diperlukan jika data berkaitan dengan permainan papan (terdapat data yang berkaitan kepada kategori lain. Rujuk BGG API untuk mendapatkan maklumat lanjut.), selepas itu ia akan memproses dan menambahkan data ke senarai permainan dan akhirnya disimpan ke fail 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)    

Di bawah anda boleh pratonton beberapa baris pertama rekod dalam fail CSV sebagai DataFrame panda.

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

Atas ialah kandungan terperinci Pengambilan data permainan papan BoardGameGeek dengan Python. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn