[PYTHON] Grattage de l'horaire de la ligne Keikyu

introduction

Lorsque j'ai quitté le bureau, j'ai pu tweeter automatiquement depuis mon smartphone, donc Ensuite, je voudrais afficher l'heure de départ et les informations de retard de la gare la plus proche de mon lieu de travail. De cette façon, vous pouvez faire un détour parce que vous avez le temps, ou vous pouvez simplement marcher parce que vous n'avez pas le temps.

Il existe "Station Spaato Web Service" comme API pour obtenir les horaires, mais il y a des frais.

"Station Spa et Web Service" https://docs.ekispert.com/v1/

Ensuite, j'ai pensé que je devrais le faire moi-même, et quand j'ai fait des recherches sur diverses choses, un article intéressant est sorti.

Blog "Omettre les cisailles": Réflexions sur les outils de grattage d'horaires https://nkth.info/blog/dia_scraping/

Il semble qu'il n'y ait pas de problème pour un usage personnel en extrayant des informations de calendrier sans alourdir le serveur. Par conséquent, nous allons acquérir le calendrier et retarder les informations par grattage. Je fais la navette pour travailler sur la ligne Keikyu, donc cette fois je vais me concentrer sur la ligne Keikyu.

Dans cet article, nous obtiendrons l'heure de départ et les informations de retard de la ligne Keikyu en grattant.

2.png Objectif de cet article ↑

Environnement d'hypothèse et d'exécution

Les hypothèses cette fois sont les suivantes. Ligne de chemin de fer utilisée: Keikyu Main Line Gare la plus proche du travail: Gare de Koganecho (Cela n'a rien à voir avec mon adresse) Train utilisé: train régulier descendant

Environnement d'exécution: Ubuntu18.04LTS (en supposant Android ou AWS dans le futur) Python 3.6.9

Environnement

Une bibliothèque bien connue pour le grattage est beautifulsoup.

Code Zine: Essayez d'analyser le HTML avec Python et de collecter des données? "Python second grade" qui comprend le grattage depuis le début https://codezine.jp/article/detail/12230

Cependant, dans le cas des horaires de la ligne Keikyu, beautifulsoup ne peut pas bien l'obtenir. Les données acquises par belle soupe pour essai sont les suivantes.

Données acquises


<html>
<head>
<title>Ligne principale de Keikyu: horaires de la gare de Keikyu Taura</title>
<meta content="max-age=1" http-equiv="Cache-Control"/>
</head>
<body>
★ Résultats de la recherche<br/>
Ligne principale Keikyu<br/>
Horaires de la gare de Keikyu Taura<br/>

Vers Uraga<br/>
Diamant de la semaine<br/>
23:04 Uraga<font color="#000000">d'habitude</font><br/>
23:17 Uraga<font color="#000000">d'habitude</font><br/>
23:27 Uraga<font color="#000000">d'habitude</font><br/>
23:40 Uraga<font color="#000000">d'habitude</font><br/>
23:52 Uraga<font color="#000000">d'habitude</font><br/>
 0:04 Uraga<font color="#000000">d'habitude</font><br/>
 0:23 Uraga<font color="#000000">d'habitude</font><br/>
2020/7/20 à partir de maintenant<br/>
<hr/>
<a href="T5?uid=27329&amp;dir=38&amp;path=2020102623438741&amp;slCode=250-40&amp;time=2125&amp;d=2&amp;dw=0&amp;date=&amp;pFlg=2&amp;reFlg=0&amp;USR=IM">↑ Temps précédent</a><br/>
<a accesskey="1" href="T3?uid=27329&amp;dir=38&amp;path=2020102623438741&amp;sf=%8B%9E%8B%7D%93%63%89%59&amp;sfCode=2053&amp;slCode=250-40&amp;d=2&amp;time=2300&amp;dw=0&amp;USR=IM">1.Direction/À la sélection du temps</a><br/>
<hr width="80%"/>
L'horaire des stations dans tout le pays<a href="http://1069.jp/">Recherche de stations ★ Horaires</a>Quoi<hr width="80%"/>
<a accesskey="8" href="/transit/norikae/T1?USR=IM&amp;sf=%8B%9E%8B%7D%93%63%89%59">8.Horaire de la gare en haut</a><br/>
<a accesskey="9" href="http://www.keikyu.co.jp/m/index.html">9.Jusqu'au sommet</a><br/>
<center>(C)KEIKYU</center>
</body>
</html>

Seule une partie du diamant est affichée. En effet, le serveur Web de Keikyu envoie uniquement des informations pour que le navigateur puisse dessiner. Informations visibles dans le navigateur ≠ Données renvoyées par le serveur C'est vrai.

GAMMASOFT: Comment gratter des pages Web qui ne peuvent pas être récupérées avec des requêtes https://gammasoft.jp/blog/how-to-download-web-page-created-javascript/

Donc, comme dans l'article ci-dessus, utilisez "requests-html" pour obtenir les informations de la page après qu'elles aient été traitées par le navigateur. Entrez la commande suivante pour installer "requests-html".

requests-installation html


$ pip install requests #requests-bibliothèque de dépendances html
$ pip install requests-html

Modifiez le fichier d'exemple, spécifiez l'URL de la gare de Koganecho et la descente normale dans l'horaire de la ligne Keikyu, traitez-le avec un navigateur, puis récupérez la source.

req.py


from requests_html import HTMLSession

url = "https://norikae.keikyu.co.jp/transit/norikae/T5?uid=34683&dir=7&path=202010272317801&USR=PC&dw=0&slCode=250-28&d=2&rsf=%89%A9%8B%E0%92%AC"
#Ligne Keikyu Station Koganecho Descente URL ordinaire

#Démarrer la session
session = HTMLSession()
r = session.get(url)

#Générer du HTML dans le moteur du navigateur
r.html.render()#Générer du HTML dans le navigateur
print(r.text)#HTML de sortie généré par le navigateur

Seulement au premier démarrage, "chrome" sera installé sans autorisation.

État au moment de la première exécution


$ python req.py 
[W:pyppeteer.chromium_downloader] start chromium download.
Download may take a few minutes.
100%|████████████████████████████████████████████████████████| 108773488/108773488 [00:09<00:00, 11116758.16it/s]
[W:pyppeteer.chromium_downloader] 
chromium download done.

Confirmez que les informations de page sont sorties en toute sécurité. (Il est trop long pour tout afficher, alors omettez-le.)

En passant, vous pouvez dire s'il fonctionne normalement avec juste la commande suivante.

$ python req.py |informations sur l'opération grep-A 1 #Affiche la ligne contenant la chaîne de recherche «informations d'opération» et la ligne suivante
<div style="font-size: larger;">[Informations sur l'opération]<a href="https://unkou.keikyu.co.jp/?from=top" target="_blank">
Fonctionne comme d'habitude

Créer une table de station

Nous ferons un tableau de correspondance avec le nom de la station, le jour (en semaine, le samedi, les jours fériés), la direction (Izumidakeji, Uraga) et l'URL.

Jetons un coup d'œil à l'URL de la page des horaires de la ligne Keikyu.

Nom de la station: Koganecho, Jour: Jours de la semaine, Direction: Uraga URL


https://norikae.keikyu.co.jp/transit/norikae/T5?uid=6403&dir=18&path=20201029203818692&USR=PC&dw=0&slCode=250-28&d=2&rsf=%89%A9%8B%E0%92%AC

Il existe différents paramètres d'URL, mais l'essentiel est ・ Dw (Jour de la semaine? 0 est normal, 1 est samedi, 2 est un jour férié) ・ SlCode (code unique de la station: à partir de 250-00 (Shinagawa)) ・ D (Direction: Abréviation de Direction? 1 monte et 2 descend) C'était juste. Par conséquent, les pages accessibles avec l'URL ci-dessus sont

Nom de la station: Koganecho, Jour: Jours de la semaine, Direction: URL Uraga (paramètres obligatoires uniquement)


https://norikae.keikyu.co.jp/transit/norikae/T5?dw=0&slCode=250-28&d=2

Est le même que. Je me sens rafraîchi. Il semble que la programmation soit facile s'il s'agit de cela. À propos, slCode (253-7) à l'aéroport de Haneda était un numéro manquant.

la mise en oeuvre

Maintenant que nous avons les informations sur la page, nous allons les gratter. Créez le programme suivant. Voir les commentaires pour plus de détails. Ce programme (keikyu_futsu.py) et le fichier de table de station (station_table.csv) sont également postés sur git-hub. https://github.com/zakuzakuzaki/zaki-aws/blob/main/station/koganecho.py

keikyu_futsu.py


from requests_html import HTMLSession #Grattage
import datetime #Obtenir l'heure actuelle
import csv #Lire le fichier csv
import sys #Argument de ligne de commande, arrêt du programme

def get_info(st, r):

    #Fractionner les sauts de ligne
    #URL de référence: https://karupoimou.hatenablog.com/entry/2019/07/08/112734
    page = r.text.split("\n")
    for i in range(len(page)):
        p = page[i]
        if "Informations sur le fonctionnement" in p:
            unko = page[i+1]#Le contenu est écrit sur la ligne suivante de la chaîne de caractères «informations d'opération».
    return st +"La gare est"+ unko

def get_timetable(r):

    #Obtenir le calendrier (heure)
    hour = r.html.find(".side01")#Jours de la semaine
    if len(hour)==0:
        hour = r.html.find(".side02")#En dehors des jours de la semaine
    hour_list = []
    for h in hour:
        hour_list.append(int(h.text))
    train = hour_list[0]#Obtenez la première heure de train

    #Obtenir les horaires (minutes)
    minute = r.html.find(".min1001")#Classe de train régulier
    minute_list = []
    for m in minute:
        minute_list.append(int(m.text))
    del minute_list[0]#Supprimez les premier et dernier éléments car ce ne sont pas des heures
    del minute_list[-1]#Comme ci-dessus

    #Initialisation d'un tableau bidimensionnel pour stocker le calendrier
    num = len(minute_list)
    dep = [[0 for i in range(2)] for j in range(num)]

    #Calendrier des travaux de construction
    for i in range(num):
        if  i>0 and minute_list[i-1] > minute_list[i]:
            train+=1
        dep[i] = (train, minute_list[i])
    return dep

def echo_dep(dep, time):

    #Définition de tableau pour stocker les trois heures de départ avant l'heure spécifiée
    dep_time = []
    #Obtenez l'heure de départ la plus proche de l'heure actuelle
    next=0
    now_i=0
    num = len(dep)
    for i in range(num):#Recherchez un par un dans le véhicule de première génération d'énergie.
        if dep[i][0]==time.hour:#Comparer avec l'heure actuelle (heure)
            now_i = i
            if dep[i][1]>time.minute:#Comparer avec l'heure actuelle (minutes)
                next = i
                break
    if next==0:#Traitement lorsque les minutes ne frappent pas (temps d'avance)
        next=now_i+1

    #Créer une liste à afficher
    for i in range(3):
        if next+i>=num:
            next = -1
            dep_time.append("~ dernier train ~")
        dep_time.append(str(dep[next+i][0]).zfill(2)+":"+str(dep[next+i][1]).zfill(2))

    return dep_time

def get_url(st , dir, dw):

    #Création du paramètre slCode
    #Référence: https://note.nkmk.me/python-csv-reader-writer/
    with open('station_table.csv') as f:
        reader = csv.reader(f)
        l = [row for row in reader]
    num = len(l)
    for i in range(num):
        if l[i][0]==st:#Recherche par nom de station
            slCode = l[i][1]
    if i==l:
        print("Erreur: nom de station inconnu.")
        sys.exit(1)
    #Paramètre d,dw reste tel quel
    return "https://norikae.keikyu.co.jp/transit/norikae/T5?dw="+dw+"&slCode="+slCode+"&d="+dir

if __name__ == '__main__':

    if len(sys.argv) != 4:
        print("Donnez les arguments de ligne de commande suivants.\n1->Nom de la station (japonais), 2->Montée:1, vers le bas:2,3->Jours de la semaine:0, samedi:1, vacances:2")
        sys.exit(1)

    url = get_url(sys.argv[1], sys.argv[2], sys.argv[3])
    #① Nom de la station (japonais), ② Montée:1, vers le bas:2, ③ en semaine:0, samedi:1, vacances:2

    #Démarrer la session
    session = HTMLSession()
    r = session.get(url)

    #Générer du HTML dans le moteur du navigateur
    r.html.render()

    #Obtenir des informations sur l'opération
    info = get_info(sys.argv[1],r)

    #Obtenir le calendrier
    dep = get_timetable(r)

    #Obtenez l'heure actuelle
    #URL de référence: https://note.nkmk.me/python-datetime-now-today/
    time = datetime.datetime.now()

    #Obtenez la prochaine heure de départ
    dep_time = echo_dep(dep, time)

    #Sortie de résultat
    print("Merci pour votre soutien aujourd'hui.")
    print(info)
    print("Le prochain départ est,")
    [print(i) for i in dep_time]

    sys.exit(0)

Le programme ci-dessus a été évoqué en se référant à l'article suivant. ・ Extraction de chaînes de caractères Enregistrement d'analyse Naro: [exemple de code Python] Explique une méthode simple lorsque vous souhaitez extraire uniquement des "lignes contenant une chaîne de caractères spécifique" par grattage. https://karupoimou.hatenablog.com/entry/2019/07/08/112734

note.nkmk.me: Extraire des chaînes de caractères avec Python (position / nombre de caractères, expression régulière) https://note.nkmk.me/python-str-extract/

・ Obtenez l'heure actuelle note.nkmk.me: Obtenez l'heure, la date, la date et l'heure actuelles avec Python https://note.nkmk.me/python-datetime-now-today/

・ Lire le fichier csv note.nkmk.me: Fichier CSV en lecture / écriture (entrée / sortie) avec Python https://note.nkmk.me/python-csv-reader-writer/

tester

Le résultat de l'exécution est le suivant.

$ python keikyu.py Koganecho 2 1#Désignez "Golden Town / Downhill / Weekdays"
Merci pour votre soutien aujourd'hui.
La gare de Koganecho fonctionne comme d'habitude
Le prochain départ est,
22:12
22:22
22:30

J'ai pu afficher en toute sécurité l'état de fonctionnement et l'heure de départ du prochain train. Nous avons confirmé que cela fonctionne normalement même si le nom de la station est changé.

en conclusion

J'ai pu afficher l'heure de départ et les informations de retard de la gare la plus proche de mon lieu de travail, en supposant que je quitterais le bureau. Je l'ai gratté pour la première fois, mais c'est assez amusant. Cependant, le code python est sale, j'espère donc pouvoir le rendre un peu plus propre. Au fait, cette fois, il ne s'agissait que d'un train ordinaire, mais si vous modifiez la classe à extraire, il peut être pris en charge par d'autres trains. Il semblait que cela prendrait du temps pour spécifier plusieurs trains, alors j'ai passé cette fois.

Correspondance entre le type de véhicule et la classe (à partir de l'horaire de la gare de Yokohama)


<span class="syasyu1004"><span class="min1004">10</span>Plaisir</span>&nbsp;&nbsp;
<span class="syasyu1003"><span class="min1003">10</span>Express limité</span>&nbsp;&nbsp;
<span class="syasyu1010"><span class="min1010">10</span>Express d'aéroport</span>&nbsp;&nbsp;
<span class="syasyu1001"><span class="min1001">10</span>d'habitude</span>

URL de la page ci-dessus (Horaires de la gare de Yokohama Uraga) https://norikae.keikyu.co.jp/transit/norikae/T5?uid=22537&dir=34&path=2020102723533416&USR=PC&dw=0&slCode=250-25&d=2&rsf=%89%A1%95%6C

Recommended Posts

Grattage de l'horaire de la ligne Keikyu
Grattage 1