"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.
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"
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.
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.
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.
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 ... Kita━━━━━━ (゜ ∀ ゜) ━━━━━━ !!!!! Vous pouvez également affiner votre recherche en spécifiant diverses conditions de recherche
C ’est pourquoi il est terminé pour le moment.
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