Ce script récupérera les données des éléments de l'API BoardGameGeek et stockera les données dans un fichier CSV.
J'ai mis à jour le script précédent. Étant donné que la réponse de l'API est au format XML et qu'il n'y a pas de point final pour récupérer tous les éléments à la fois, le script précédent parcourrait une plage d'ID fournie, effectuant des appels un par un pour chaque élément. Ce n'est pas optimal, cela prend beaucoup de temps pour obtenir une plus grande gamme d'identifiants (actuellement, le plus grand nombre d'éléments (ID) disponibles sur BGG atteint 400 000) et les résultats peuvent ne pas être fiables. Par conséquent, avec quelques modifications dans ce script, davantage d'ID d'élément seront ajoutés en tant que valeur de paramètre à une seule URL de requête, et avec cela, une seule réponse renverra plusieurs éléments (~ 800 était le nombre le plus élevé renvoyé par une seule réponse. BGG vous pourrez éventuellement modifier cela plus tard ; vous pouvez facilement modifier batch_size afin de l'ajuster si nécessaire).
De plus, ce script récupérera tous les éléments, et pas seulement les données liées aux jeux de société.
Les informations récupérées et stockées pour chaque jeu de société sont les suivantes :
nom, game_id, type, 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.
Les mises à jour dans ce script sont les suivantes ; 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
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', 'type', '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('bgg.csv', 'a', encoding='UTF8') as f: dictwriter_object = DictWriter(f, fieldnames=csv_header) if f.tell() == 0: dictwriter_object.writeheader() dictwriter_object.writerows(games)
Nous devrons définir les en-têtes des requêtes. La pause entre les requêtes peut être définie via SLEEP_BETWEEN_REQUESTS (j'ai vu des informations selon lesquelles la limite de débit est de 2 requêtes par seconde, mais il peut s'agir d'informations obsolètes puisque je n'ai eu aucun problème avec la pause définie sur 0). De plus, sont définies ici les valeurs de l'ID du point de départ (start_id_range), de la plage maximale (max_id_range) et batch_size correspond au nombre de jeux que la réponse doit renvoyer. L'URL de base est définie dans cette section, mais les identifiants sont ajoutés dans la partie suivante du script.
# 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 # Define max id range start_id_range = 0 max_id_range = 403000 batch_size = 800 base_url = "https://boardgamegeek.com/xmlapi2/thing?id="
La partie suivante présente la logique principale de ce script. Dans un premier temps, en fonction de la taille du lot, il créera une chaîne d'ID qui se trouvent dans la plage d'ID définie, mais pas plus d'ID que le nombre défini dans batch_size et qui sera ajouté au paramètre id de l'URL. Avec cela, chaque réponse renverra des données pour le nombre d'éléments identique à la taille du lot. Après cela, il traitera et ajoutera les données à la liste des jeux pour chaque réponse et enfin les ajoutera au fichier CSV.
# Main loop that will iterate between the starting and maximum range in intervals of the batch size for batch_start in range(start_id_range, max_id_range, batch_size): # Make sure that the batch size will not exceed the maximum ids range batch_end = min(batch_start + batch_size - 1, max_id_range) # Join and append to the url the IDs within batch size ids = ",".join(map(str, range(batch_start, batch_end + 1))) url = f"{base_url}?id={ids}&stats=1" # If by any chance there is an error, this will throw the exception and continue on the next batch try: response = requests.get(url, headers=headers) except Exception as err: print(err) continue if response.status_code == 200: soup = BeautifulSoup(response.text, features="html.parser") items = soup.find_all("item") games = [] for item in items: if item: try: # Find values in the XML name = item.find("name")['value'] if item.find("name") is not None else 0 year_published = item.find("yearpublished")['value'] if item.find("yearpublished") is not None else 0 min_players = item.find("minplayers")['value'] if item.find("minplayers") is not None else 0 max_players = item.find("maxplayers")['value'] if item.find("maxplayers") is not None else 0 min_play_time = item.find("minplaytime")['value'] if item.find("minplaytime") is not None else 0 max_play_time = item.find("maxplaytime")['value'] if item.find("maxplaytime") is not None else 0 min_age = item.find("minage")['value'] if item.find("minage") is not None else 0 rating = item.find("average")['value'] if item.find("average") is not None else 0 weight = item.find("averageweight")['value'] if item.find("averageweight") is not None else 0 owned = item.find("owned")['value'] if item.find("owned") is not None else 0 link_type = {'categories': [], 'mechanics': [], 'designers': [], 'artists': [], 'publishers': []} links = item.find_all("link") # Append value(s) for each link type for link in links: if link['type'] == "boardgamecategory": link_type['categories'].append(link['value']) if link['type'] == "boardgamemechanic": link_type['mechanics'].append(link['value']) if link['type'] == "boardgamedesigner": link_type['designers'].append(link['value']) if link['type'] == "boardgameartist": link_type['artists'].append(link['value']) if link['type'] == "boardgamepublisher": link_type['publishers'].append(link['value']) # Append 0 if there is no value for any link type for key, ltype in link_type.items(): if not ltype: ltype.append("0") game = { "name": name, "game_id": item['id'], "type": item['type'], "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(link_type['categories']), "mechanics": ', '.join(link_type['mechanics']), "designers": ', '.join(link_type['designers']), "artists": ', '.join(link_type['artists']), "publishers": ', '.join(link_type['publishers']), } # Append current item to games list games.append(game) except TypeError: print(">>> NoneType error. Continued on the next item.") continue save_to_csv(games) print(f">>> Request successful for batch {batch_start}-{batch_end}") else: print(f">>> FAILED batch {batch_start}-{batch_end}") # Pause between requests time.sleep(SLEEP_BETWEEN_REQUEST)
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('./bgg.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!