Maison >développement back-end >Tutoriel Python >Récupération de données de jeux de société BoardGameGeek avec Python
Ce script récupérera les données des jeux de société depuis l'API BoardGameGeek et stockera les données dans un fichier CSV. La réponse de l'API est au format XML et comme il n'y a pas de point final pour récupérer plusieurs données de jeux de société à la fois, cela fonctionnera en faisant une requête au point final pour un seul jeu de société basé sur l'ID du ou des jeux de société, tout en incrémentant l'ID après chaque demande dans la plage d'ID donnée.
Consultez le dépôt sur mon profil GitHub
Les informations récupérées et stockées pour chaque jeu de société sont les suivantes :
nom, game_id, note, poids, année_publiée, min_players, max_players, min_play_time, max_pay_time, min_age,owned_by, catégories, mécaniciens, designers, artistes et éditeurs.
Nous commençons par importer les bibliothèques nécessaires à ce script :
# Import libraries from bs4 import BeautifulSoup from csv import DictWriter import pandas as pd import requests import time
Nous devrons définir les en-têtes de la requête et la pause entre chaque requête (en secondes). Les informations sur la limite de taux de requêtes ne sont pas disponibles dans la documentation de l'API BGG et il existe des informations non officielles dans leurs forums selon lesquelles elle est limitée à 2 requêtes par seconde. La pause entre les requêtes devra peut-être être ajustée si le script commence à atteindre le taux limite.
# 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
La prochaine étape consiste à définir la gamme d'identifiants de jeux de société qui doivent être récupérés depuis BGG et traités. Au moment de la création de ce script, la limite supérieure pour laquelle il existe des données de jeu de société existantes est d'environ 402 000 identifiants et ce nombre est très susceptible d'augmenter à l'avenir.
# Define game ids range game_id = 264882 # initial game id last_game_id = 264983 # max game id (currently, it's around 402000)
Ce qui suit est une fonction qui sera appelée lorsque le script sera terminé en fonction de la plage d'ID. De plus, s'il y a une erreur lors de la demande, cette fonction sera appelée afin de stocker toutes les données ajoutées à la liste des jeux jusqu'au moment où l'exception s'est produite.
# 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)
La partie suivante présente la logique principale de ce script. Il exécutera le code dans la plage des identifiants, ce qui signifie qu'il fera des requêtes à l'API BGG, obtiendra toutes les données en utilisant BeautifulSoup, effectuera les vérifications nécessaires si les données sont liées aux jeux de société (il existe des données liées à d'autres catégories. Reportez-vous à l'API BGG pour plus d'informations.), après cela, il traitera et ajoutera les données à la liste des jeux et enfin les stockera dans le fichier 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)
Ci-dessous, vous pouvez prévisualiser les premières lignes d'enregistrements du fichier CSV en tant que pandas DataFrame.
# Preview the CSV as pandas DataFrame df = pd.read_csv('./BGGdata.csv') print(df.head(5))
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!