Rumah >pembangunan bahagian belakang >Tutorial Python >Pengambilan data permainan papan BoardGameGeek dengan 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!