[PYTHON] J'ai essayé de ramper et de gratter le site de courses de chevaux Partie 2

introduction

"Python Crawling & Scraping [Augmented Revised Edition] -Guide de développement pratique pour la collecte et l'analyse de données-" Créez un programme original en utilisant les connaissances jusqu'au chapitre 3.

Cette fois, j'ai créé un programme qui acquiert l'URL d'une page individuelle à partir des résultats de la recherche de la fonction de recherche de chevaux de course de netkeiba, accède à cette URL, acquiert les informations de chaque cheval et les enregistre dans la base de données.

Structure de la page de résultats de recherche

La fenêtre de recherche est en haut du netkeiba de base, elle est donc omise. Avec la fonction de recherche avancée, vous pouvez spécifier diverses conditions de recherche telles que l'ascendance, la couleur des cheveux, l'ordre d'affichage, etc. Cette fois, sans utiliser la fenêtre de recherche, je suis passé à la page de résultats de recherche à partir de la colonne des performances d'élevage de Deep Impact Details Page (cette zone sera décrite plus tard). Lié à l'intrication JavaScript) (Cliquez sur le lien entouré en rouge)

Tout d'abord, voici la page de résultats de recherche. Les résultats de la recherche sont triés par prix par défaut. Cette fois, la page de chaque cheval lié à ce résultat de recherche sera grattée.

Des informations telles que le nom du cheval, l'écurie, le pedigree et le propriétaire du cheval peuvent être trouvées à partir de cette page de résultats de recherche, mais nous nous concentrerons d'abord sur l'obtention de l'URL de la page de détail de chaque cheval. Chaque nom de cheval est un lien vers la page de détails du cheval, et l'URL se termine par l'année de naissance + 6 chiffres.

Dans le paramètre URL de la page de résultats de recherche, le numéro "2002100816" à la fin de la page de détails sur l'impact profond est spécifié comme sire_id, et les chevaux qui ont un impact profond en tant que père sont réduits. (Il y a "Résultat de la recherche" en haut, mais si vous recherchez par nom de cheval, cette partie sera "Résultat de la recherche de (nom du cheval)".)

Cette fois, je veux obtenir non seulement la première page de résultats, mais aussi la deuxième et les pages suivantes qui peuvent être sautées en cliquant sur "Suivant", mais le lien de cette partie est

<a href="javascript:paging('2')">Suivant</a>

Bien que cela ressemble, lorsque vous cliquez dessus, la page suivante s'affiche L'URL est https://db.netkeiba.com/, et vous pouvez voir que la transition d'écran est effectuée à l'aide du POST. (La même chose s'applique à la page de résultats de recherche lors de l'utilisation du formulaire de recherche avancée.) La partie de la fonction de pagination réelle est

function paging(page)
{
document.sort.page.value = page;
document.sort.submit();
}

Vous pouvez voir qu'il est soumis en utilisant javascript. Lorsque vous démarrez l'outil de vérification du navigateur et cliquez sur "Suivant" 2019-11-03 19.04.56 db.netkeiba.com 06565a7f139a.png Puisque la valeur comme celle-ci est POSTÉE, db.netkeiba.com/?pid=horse_list&_sire_id=2002100816&page=(ページ番号) Si vous spécifiez le paramètre de page à la fin de l'URL de la page de résultats de recherche, vous pouvez obtenir la deuxième page et les suivantes par GET.

Structure de la page de détail

Cette fois, le nom du cheval, actif ou effacé, le sexe, la couleur des cheveux en haut du contenu principal sur la page de détail, Analysez la table contenant des informations telles que la date de naissance et la table d'ascendance en dessous, et enregistrez le résultat dans la base de données.

2019-10-20 23.17.03 db.netkeiba.com f349a0d9a4b6.png 2019-10-20 23.23.46 db.netkeiba.com a15e20bf34a7.png

Les deux premiers sont des pages détaillées des deux pièces de production à fort impact qui ont remporté les premier et deuxième prix au moment de la rédaction, mais je remarque que le nombre d'éléments dans le tableau qui affiche des données telles que la date de naissance est différent. Dans netkeiba, l'élément «informations de recrutement» est ajouté sur la page des chevaux appartenant à des clubs dits de morsure, de sorte que le nombre d'éléments dans le tableau est différent de celui des chevaux non-clubs, il faut donc en tenir compte lors du grattage. ..

De plus, (bien que la pièce de production à impact profond ciblé cette fois soit presque sans importance), les chevaux appartenant aux courses de chevaux locales et les chevaux étrangers ont des symboles tels que □ sol et ○ en dehors du nom du cheval, respectivement, donc à part cela, seul le nom du cheval est acquis Faire. De plus, comme vous pouvez le voir sur la première image ci-dessous, il n'y a aucune indication d'activation ou d'effacement sur le terrain □ (chevaux appartenant à des courses de chevaux locales), donc le grattage doit être pris en compte ici également. 2019-10-27 23.08.38 db.netkeiba.com 2cc6e24ab680.png 2019-10-27 23.08.53 db.netkeiba.com 86af2843684b.png

Code complété

keiba_scraping.py


import requests
import lxml.html
import time
from pymongo import MongoClient
import re
import sys

def main(sire_id,n):
    client = MongoClient('localhost', 27017) #Connectez-vous à MongoDB sur l'hôte local.
    collection = client.scraping.horse_data #base de données de raclage. Créer sinon
    collection.create_index('key', unique=True) #Créez un index unique dans le champ de clé qui stocke la clé qui identifie de manière unique les données.

    session = requests.Session()

    for i in range(n):
        response = session.get("https://db.netkeiba.com/?pid=horse_list&_sire_id=" + sire_id + "&page=" + str(i))
        response.encoding = response.apparent_encoding #Encodage d'apparence_Changer pour ce qui a été deviné par l'encodage
        urls = scrape_list_page(response) #Obtenir une liste des URL de page de détail
        for url in urls:
            key = extract_key(url) #Obtenez le numéro à la fin de l'URL comme clé
            h = collection.find_one({'key': key}) #Rechercher les données de la clé correspondante
            if not h: #S'il n'existe pas dans la base de données
                time.sleep(1) #Courir chaque seconde(Réduire la charge sur le site d'acquisition)
                response = session.get(url)#Obtenir la page de détails
                horse = scrape_horse_page(response)#Page de détail de raclage
                collection.insert_one(horse)#Enregistrer les informations du cheval dans DB

def scrape_list_page(response):#Fonction générateur pour extraire l'URL de la page de détail
    html = lxml.html.fromstring(response.text)
    html.make_links_absolute(response.url)
    for a in html.cssselect('#contents_liquid > div > form > table > tr > td.xml.txt_l > a'):
        url = a.get("href")
        yield url

def scrape_horse_page(response):#Analyser la page de détail
    response.encoding = response.apparent_encoding #Spécifier l'encodage
    html = lxml.html.fromstring(response.text)

    #Nom, actif ou supprimé du haut de la page,sexe,Obtenez des informations sur la couleur des cheveux
    for title in html.cssselect('#db_main_box > div.db_head.fc > div.db_head_name.fc > div.horse_title'):
        name = parse_name(title.cssselect('h1')[0].text.strip()) #Obtenu un nom de cheval. Supprimez les caractères vierges supplémentaires avec la bande et l'analyse_Passer au nom
        #Étant donné qu'actifs ou supprimés, le sexe et la couleur des cheveux sont des chaînes de caractères séparées par des espaces, ils sont divisés par division et stockés dans des variables par carte.
        data = title.cssselect('p.txt_01')[0].text.split()
        if len(data) > 2:
            status,gender,color = map(str,data)
        else:
            gender,color = map(str,data) #Puisqu'il n'y a aucune information sur les périphériques actifs pour les chevaux locaux
            status = None

    #Obtenez des informations sur le père, la mère, la mère et le père à partir du tableau d'ascendance
    for bloodline in html.cssselect('#db_main_box > div.db_main_deta > div > div.db_prof_area_02 > div > dl > dd > table'):
        sire = bloodline.cssselect('tr:nth-child(1) > td:nth-child(1) > a')[0].text
        dam = bloodline.cssselect('tr:nth-child(3) > td.b_fml > a')[0].text
        broodmare_sire = bloodline.cssselect('tr:nth-child(3) > td.b_ml > a')[0].text

    club_info = html.cssselect('#owner_info_td > a') #Afficher le prix de recrutement pour les chevaux du club
    for data in html.cssselect('#db_main_box > div.db_main_deta > div > div.db_prof_area_02 > table'):
        birthday = data.cssselect('tr:nth-child(1) > td')[0].text #Obtenir des informations sur l'anniversaire et convertir en type de date
        trainer = data.cssselect('tr:nth-child(2) > td > a')[0].text #Obtenir des informations sur les formateurs
        owner = data.cssselect('tr:nth-child(3) > td > a')[0].text #Obtenir des informations sur le propriétaire du cheval
        #Pour les chevaux de club, en dessous du producteur::nth-Puisque le nombre d'enfants change un par un, club_Ajoutez 1 s'il y a un élément d'information
        if len(club_info) > 0:
            breeder = data.cssselect('tr:nth-child(5) > td > a')[0].text #Producteur
            prize_money = data.cssselect('tr:nth-child(8) > td')[0].text.strip().replace(' ','') #La bande de prix supprime les blancs aux deux extrémités, la replase supprime les espaces dans le texte
        else:
            breeder = data.cssselect('tr:nth-child(4) > td > a')[0].text
            prize_money = data.cssselect('tr:nth-child(7) > td')[0].text.strip().replace(' ','')


    horse = {
        'url': response.url,
        'key': extract_key(response.url),
        'name':name,
        'status': status,
        'gender':gender,
        'color':color,
        'birthday':birthday,
        'sire':sire,#père
        'dam':dam,#mère
        'broodmare_sire':broodmare_sire,#Mère père
        'owner':owner,
        'breeder':breeder,
        'trainer':trainer,
        'prize_money' : prize_money
    }

    return horse

def extract_key(url):
    m = re.search(r'\d{10}', url).group() #Dernier/Récupère de à la fin de la chaîne de caractères avec une expression régulière.
    return m

def parse_name(name):
    m = re.search(r'[\u30A1-\u30FF]+', name).group() #○ Au sol ou □ Ne retirez que le nom du cheval du cheval au sol. Si vous supprimez la partie qui correspond au modèle d'expression régulière de Katakana, k
    return m

if __name__ == "__main__":
    main(sys.argv[1],int(sys.argv[2]))#Obtenez le numéro à la fin de l'URL du cheval dont vous souhaitez obtenir la liste des résultats de recherche de la pièce de production à partir de l'argument de ligne de commande et le nombre de pages pour obtenir le résultat de la page de recherche et appeler la fonction principale
python keiba_scraping.py 2002100816 4

Exécuter la liste des pièces de production à fort impact sous condition d'acquérir 4 pages, Si vous affichez toute la collection de horse_data du shell mongo ... mongopng.png Kita━━━━━━ (゜ ∀ ゜) ━━━━━━ !!!!! Vous pouvez également affiner votre recherche en spécifiant diverses conditions de recherche mongo2.png

C ’est pourquoi il est terminé pour le moment.

en conclusion

Bien que ce ne soit pas un gros programme, il a fallu beaucoup de temps pour publier un article en raison de problèmes de motivation et de temps. En tant que fonction que je veux ajouter, je pense qu'il s'agit d'obtenir une page récursive comme une pièce de production à impact profond, puis cette pièce de production. Je vous serais reconnaissant si vous pouviez vous y référer ou si vous le trouviez intéressant. Aussi, si vous avez des questions ou des préoccupations, veuillez laisser un commentaire.

Recommended Posts

J'ai essayé de ramper et de gratter le site de courses de chevaux Partie 2
J'ai essayé d'obtenir une base de données sur les courses de chevaux en utilisant Pandas
Explorer et gratter n'importe quel site avec mitmproxy
J'ai essayé d'utiliser PyEZ et JSNAPy. Partie 2: J'ai essayé d'utiliser PyEZ
Site de courses de chevaux Web scraping avec Python
J'ai essayé de gratter
J'ai appris le grattage à l'aide de sélénium pour créer un modèle de prédiction de courses de chevaux.
J'ai essayé le web scraping en utilisant python et sélénium
Python grattage Extraire l'environnement de course du site de courses de chevaux
J'ai essayé de gratter la publicité du site de dessin animé piraté
Python: j'ai essayé menteur et honnête
J'ai essayé de gratter avec Python
J'ai essayé de [gratter] des images de mode et des phrases de texte avec Python.
[Courses de chevaux] J'ai essayé de quantifier la force du cheval de course
Exploration du site Web d'une société de titres
J'ai écrit un code qui dépasse le taux de récupération de 100% dans la prédiction des courses de chevaux en utilisant LightGBM (partie 2)
Flux de raclage des données de courses de chevaux
J'ai créé une classe en Python et essayé de taper du canard
J'ai essayé de gratter avec du python
J'ai essayé de faire un processus d'exécution périodique avec Selenium et Python
J'ai essayé d'utiliser PyEZ et JSNAPy. Partie 4: Automatisez la configuration du FAI avec PyEZ et JSNAPy
Gratter et manger des bûches - je veux trouver un bon restaurant! ~ (Travail)
J'ai essayé de créer des taureaux et des vaches avec un programme shell
J'ai créé un site d'apprentissage C ++
J'ai essayé webScraping avec python.
Récupération des données sur les courses de chevaux au Colaboratory
J'ai essayé de faire la reconnaissance de caractères manuscrits de Kana Partie 2/3 Création et apprentissage de données
Démarrez un serveur Web en utilisant Bottle et Flask (j'ai également essayé d'utiliser Apache)
J'ai créé un exemple pour accéder à Salesforce en utilisant Python et Bottle
Introduction à la création d'IA avec Python! Partie 3 J'ai essayé de classer et de prédire les images avec un réseau de neurones convolutifs (CNN)
J'ai essayé de créer un linebot (implémentation)
J'ai essayé de récupérer les données de conversation d'ASKfm
J'ai essayé de créer un linebot (préparation)
J'ai installé DSX Desktop et l'ai essayé
J'ai essayé de jouer au jeu ○ ✕ en utilisant TensorFlow
J'ai essayé un langage fonctionnel avec Python
J'ai essayé d'implémenter DeepPose avec PyTorch PartⅡ
J'ai créé une API Web
J'ai essayé de gratter la météo Yahoo (édition Python)
J'ai essayé d'utiliser pipenv, alors prenez note
J'ai essayé de comparer le cadre d'application Web
J'ai essayé la détection 3D d'une voiture
J'ai essayé de combiner Fabric, Cuisine et Jinja2
J'ai essayé de faire un processus périodique avec CentOS7, Selenium, Python et Chrome
[Python] J'ai essayé de résoudre 100 questions passées que les débutants et les intermédiaires devraient résoudre [Partie 5/22]
[Python] J'ai essayé de résoudre 100 questions passées que les débutants et les intermédiaires devraient résoudre [Partie 7/22]
Programmation Python: j'ai essayé d'obtenir (l'exploration) des articles de presse en utilisant Selenium et BeautifulSoup4
[Python] J'ai essayé de résoudre 100 questions passées que les débutants et les intermédiaires devraient résoudre [Partie 4/22]
[Python] J'ai essayé de résoudre 100 questions passées que les débutants et les intermédiaires devraient résoudre [Part3 / 22]
Un débutant en apprentissage automatique a essayé de créer un modèle de prédiction de courses de chevaux avec python
J'ai essayé d'automatiser le dépôt de 100 yens des courses de chevaux Rakuten (python / sélénium)
J'ai appliqué le classement SIF à un document japonais et essayé d'extraire des phrases clés
J'ai essayé de classer Hanana Oba et Emiri Otani par apprentissage profond (partie 2)
[Python] J'ai essayé de résoudre 100 questions passées que les débutants et les intermédiaires devraient résoudre [Partie 6/22]
J'ai essayé de créer une API de reconnaissance d'image simple avec Fast API et Tensorflow