J'ai mis à jour le récupérateur Python pour les données BoardGameGeek

Patricia Arquette
Libérer: 2024-10-15 22:15:30
original
332 Les gens l'ont consulté

I

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
Copier après la connexion

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)
Copier après la connexion

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="
Copier après la connexion

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)
Copier après la connexion

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))
Copier après la connexion

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!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal