[PYTHON] Gratter la page i-town avec du sélénium

Préface

Vers 2020, les spécifications de la page i-town ont changé, j'ai donc créé un script qui y correspond. Le script suivant est créé

Entrez des mots-clés et des zones et effectuez une recherche sur la page i-town → Obtenez le nom et l'adresse du magasin à partir des résultats de la recherche et la sortie au format csv

Remarque

Le programme présenté dans cet article n'effectue pas un accès continu à une vitesse qui dépasse largement la vitesse que les utilisateurs utilisent normalement, de sorte qu'il ne relève pas des éléments interdits (semble-t-il).

De plus, puisqu'il est interdit de le copier pour une utilisation dans un environnement qui peut être consulté par un tiers, L'image du site etc. ne sera pas affichée au moment de l'explication

Page de la ville

Le site sera mis à jour vers 2020, et lorsque vous faites défiler les résultats de recherche, un bouton appelé ** Afficher plus ** apparaîtra. Vous ne pouvez plus obtenir tous les résultats de la recherche (affichage maximum 1 000) sauf si vous appuyez plusieurs fois sur cette touche.

Aperçu du programme

Pour le moment, je posterai une explication approximative et l'ensemble du programme. (Une explication détaillée sera décrite plus tard)

Créez une interface d'entrée à l'aide de PysimpleGUI (peu importe si vous ne l'avez pas) Démarrez Chrome (ou Firefox) en utilisant le pilote Web de Selenium, affichez la page correspondante et appuyez sur tous les boutons d'affichage Utilisez beautifulsoup pour obtenir les éléments nécessaires (cette fois, deux types, nom et adresse du magasin) Façonnez les données à l'aide de pandas

main.py


#It is python3's app
#install selenium, beautifulsoup4, pandas with pip3
#download firefox, geckodriver
from selenium import webdriver
#from selenium.webdriver.firefox.options import Options
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException
from bs4 import BeautifulSoup
import pandas as pd
import time
import re
import csv
import PySimpleGUI as sg

#plese download browserdriver and writedown driver's path
#bdriverpath='./chromedriver'
bdriverpath="C:\chromedriver.exe"

#make popup window
layout= [
    [sg.Text('Area >> ', size=(15,1)), sg.InputText('Machida')],
    [sg.Text('Keyword >> ', size=(15,1)), sg.InputText('épicerie')],
    [sg.Submit(button_text='OK')]
]
window = sg.Window('Area and Keyword', layout)

#popup
while True:
    event, values = window.read()

    if event is None:
        print('exit')
        break

    if event == 'OK':
        show_message = "Area is " + values[0] + "\n"
        show_message += "Keyword is " + values[1] + "\n"
        print(show_message)
        sg.popup(show_message)
        break

window.close()
area =values[0]
keyword = values[1]

#initialize webdriver
options = Options()
options.add_argument('--headless')
driver=webdriver.Chrome(options=options, executable_path=bdriverpath)

#search page with keyword and area
driver.get('https://itp.ne.jp')
driver.find_element_by_id('keyword-suggest').find_element_by_class_name('a-text-input').send_keys(keyword)
driver.find_element_by_id('area-suggest').find_element_by_class_name('a-text-input').send_keys(area)
driver.find_element_by_class_name('m-keyword-form__button').click()
time.sleep(5)

#find & click readmore button
try:
    while driver.find_element_by_class_name('m-read-more'):
        button = driver.find_element_by_class_name('m-read-more')
        button.click()
        time.sleep(1)
except NoSuchElementException:
    pass
res = driver.page_source
driver.quit()

#output with html
with open(area + '_' + keyword + '.html', 'w', encoding='utf-8') as f:
    f.write(res)

#parse with beautifulsoup
soup = BeautifulSoup(res, "html.parser")
shop_names = [n.get_text(strip=True) for n in soup.select('.m-article-card__header__title')]
shop_locates = [n.get_text(strip=True) for n in soup.find_all(class_='m-article-card__lead__caption', text=re.compile("adresse de rue"))]

#incorporation lists with pandas
df = pd.DataFrame([shop_names, shop_locates])
df = df.transpose()

#output with csv
df.to_csv(area + '_' + keyword + '.csv', quoting=csv.QUOTE_NONE, index=False, encoding='utf_8_sig')

sg.popup("finished")

Explication pour chaque bloc

Environnement

Ce qui suit est un groupe de bibliothèques importantes cette fois. Tous peuvent être installés avec pip3. La partie commentée est de savoir s'il faut utiliser Chrome ou Firefox, veuillez donc le réécrire en fonction de vos goûts et de votre environnement.

import.py


from selenium import webdriver
#from selenium.webdriver.firefox.options import Options
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException
from bs4 import BeautifulSoup
import pandas as pd
import time
import re
import csv
import PySimpleGUI as sg

driver Pour utiliser le webdriver décrit ci-dessous, vous aurez besoin d'un chromedriver pour Chrome et d'un geckodriver pour Firefox. Veuillez télécharger celui qui s'applique sur le site suivant. https://github.com/mozilla/geckodriver/releases https://chromedriver.chromium.org/downloads De plus, pour le moment, cela ne fonctionnera que si les ** versions du navigateur, de python et du pilote 3 ** que vous utilisez sont en mesh.


Après avoir téléchargé le pilote, transmettez le chemin en tant que variable d'environnement ou placez-le dans un emplacement facile à comprendre et écrivez le chemin dans le programme. Dans mon environnement Windows, il est placé directement sous le lecteur C. Je l'ai commenté, mais sous linux (mac), je l'ai mis au même endroit où le programme est mis et utilisé.

driver.py


#plese download browserdriver and writedown driver's path
#bdriverpath='./chromedriver'
bdriverpath="C:\chromedriver.exe"

PySimpleGUI Références Si vous utilisez Tkinter, essayez d'utiliser PySimpleGUI

Décidez de la mise en page et écrivez l'entrée par défaut (Machida, dépanneur)

layout.py


#make popup window
layout= [
    [sg.Text('Area >> ', size=(15,1)), sg.InputText('Machida')],
    [sg.Text('Keyword >> ', size=(15,1)), sg.InputText('épicerie')],
    [sg.Submit(button_text='OK')]
]

Créez une fenêtre et continuez à charger en boucle. Lorsque vous appuyez sur le bouton OK dans la fenêtre, le contenu d'entrée est lu dans les valeurs []. Une fois le traitement terminé, quittez avec window.close () et transmettez le contenu d'entrée aux variables du programme.

window.py


window = sg.Window('Area and Keyword', layout)

#popup
while True:
    event, values = window.read()

    if event is None:
        print('exit')
        break

    if event == 'OK':
        show_message = "Area is " + values[0] + "\n"
        show_message += "Keyword is " + values[1] + "\n"
        print(show_message)
        sg.popup(show_message)
        break

window.close()
area =values[0]
keyword = values[1]

Démarrez Webdriver

webdriver (sélénium) est une bibliothèque permettant de faire fonctionner des navigateurs normaux (firefox, chrome, etc.) par programmation.

Tout d'abord, ajoutez --headless aux options de démarrage. Il s'agit d'une option pour exécuter le navigateur en arrière-plan. Si vous voulez que le navigateur fonctionne automatiquement, mettez en commentaire options.add_argument ('--headless'). Puis lancez chrome avec driver = webdriver.Chrome (). En même temps, entrez l'option et le chemin du pilote. options = options, executable_path = briverpath

init.py


#initialize webdriver
options = Options()
options.add_argument('--headless')
driver=webdriver.Chrome(options=options, executable_path=briverpath)

Rechercher avec Webdriver

Allez en haut de la page de la ville avec driver.get. Trouvez la zone de saisie pour saisir les mots-clés et les zones dans driver.find ~, et entrez également dans .send_keys (). Recherchez également le bouton de démarrage de la recherche de la même manière et appuyez sur le bouton avec .click ().

search.py


#search page with keyword and area
driver.get('https://itp.ne.jp')
driver.find_element_by_id('keyword-suggest').find_element_by_class_name('a-text-input').send_keys(keyword)
driver.find_element_by_id('area-suggest').find_element_by_class_name('a-text-input').send_keys(area)
driver.find_element_by_class_name('m-keyword-form__button').click()
time.sleep(5)

exemple html

Par exemple, sur la page suivante, la zone de saisie de mot-clé a un identifiant de «keyword-suggest» et une classe de «a-text-input».

keyword.html


<div data-v-1wadada="" id="keyword-suggest" class="m-suggest" data-v-1dadas14="">
<input data-v-dsadwa3="" type="text" autocomplete="off" class="a-text-input" placeholder="Entrez un mot-clé" data-v-1bbdb50e=""> 
<!---->
</div>

Poussez l'écran plus loin

Utilisez une boucle pour continuer à appuyer sur le bouton plus d'affichage nom_classe = m-read-more tant que vous le trouvez. De plus, si vous essayez de trouver le même bouton immédiatement après avoir appuyé sur le bouton, le nouveau bouton ne sera pas encore chargé et se terminera au milieu, alors définissez un temps d'attente avec time.sleep (1) Si le bouton n'est pas trouvé, le webdriver provoquera une erreur et le programme se terminera, alors prévoyez l'erreur «sauf» à l'avance. Après sauf, passez au suivant tel quel, mettez le html obtenu (tout l'affichage est enfoncé) dans res,driver.quit () Le pilote Web va quitter

button.py


from selenium.common.exceptions import NoSuchElementException

#find & click readmore button
try:
    while driver.find_element_by_class_name('m-read-more'):
        button = driver.find_element_by_class_name('m-read-more')
        button.click()
        time.sleep(1)
except NoSuchElementException:
    pass
res = driver.page_source
driver.quit()

HTML de sortie

Juste au cas où, je sortirai le html que j'ai obtenu. Non requis

html.py


#output with html
with open(area + '_' + keyword + '.html', 'w', encoding='utf-8') as f:
    f.write(res)

analyse html

Transmettez le code HTML que vous avez obtenu précédemment à beautifulsoup. Recherchez un élément avec soup.select et obtenez uniquement le nom du magasin (adresse) avec .get_text (). Si vous utilisez simplement get_text (), les sauts de ligne et les espaces seront inclus, mais si vous ajoutez l'option strip = True, vous n'obtiendrez que les caractères que vous voulez. En ce qui concerne l'adresse, sur le site de la page de la ville, la classe class_name = m-article-card__lead__caption a été définie non seulement pour l'adresse mais aussi pour le numéro de téléphone et la station la plus proche, donc seule l'adresse peut être extraite par chaîne de caractères. Je l'ai. text = re.compile (" adresse ")

parse.py


#parse with beautifulsoup
soup = BeautifulSoup(res, "html.parser")
shop_names = [n.get_text(strip=True) for n in soup.select('.m-article-card__header__title')]
shop_locates = [n.get_text(strip=True) for n in soup.find_all(class_='m-article-card__lead__caption', text=re.compile("adresse de rue"))]

Mise en forme des données

J'utilise des pandas pour organiser les données. Les données obtenues par beautifulsoup sont une liste, alors combinez les deux. Cela seul donnera des données de paysage, alors utilisez transpose () pour le faire portrait.

pandas.py


#incorporation lists with pandas
df = pd.DataFrame([shop_names, shop_locates])
df = df.transpose()

Sortie de données

Cette fois, je l'ai sortie au format csv. Utilisez la «zone» et le «mot-clé» saisis par l'utilisateur pour le nom du fichier. Lorsque les données pandas sont sorties, elles sont numérotées verticalement, mais comme c'est un obstacle, elles sont effacées avec index = False. De plus, si vous ouvrez les données de sortie dans Excel, il y a un problème que les caractères sont déformés, utilisez donc encoding = 'utf_8_sig' pour l'éviter.

csv.py


#output with csv
df.to_csv(area + '_' + keyword + '.csv', quoting=csv.QUOTE_NONE, index=False, encoding='utf_8_sig')

À la fin

J'ai essayé le grattage Web avec du sélénium, mais j'ai eu l'impression que l'opération n'était pas stable. Le navigateur étant en cours d'exécution, l'opération après le chargement ou la pression sur le bouton n'est pas garantie. Cette fois, j'ai utilisé «time.sleep» pour l'éviter. (J'ai initialement utilisé l'attente implicite / explicite du sélénium, mais cela n'a pas fonctionné pour moi.) De plus, lorsque j'ai téléchargé le pilote Web, c'était une ancienne version pour une raison quelconque, et je souffrais d'une erreur pendant environ 2 jours sans m'en apercevoir, donc j'étais très en colère (envers moi-même)

Recommended Posts

Gratter la page i-town avec du sélénium
Grattage au sélénium
Grattage avec du sélénium
Grattage réussi avec Selenium
Grattage avec du sélénium [Python]
Grattage au sélénium en Python
Grattage avec Selenium + Python Partie 1
Grattage avec Selenium + Python Partie 2
Scraping avec Selenium en Python (Basic)
Grattage WEB avec BeautifulSoup4 (page en couches)
Grattage avec Python
Grattage avec Python
Commençant par Selenium
[Note personnelle] Scraping de pages Web en python3
Pratiquer le web scraping avec Python et Selenium
Grattage WEB avec BeautifulSoup4 (page du numéro de série)
Scraping de pages i-Town: je voulais prendre la place de Wise-kun
Grattage en Python (préparation)
Essayez de gratter avec Python.
Grattage avec Python + PhantomJS
Grattage avec coquille tremblante
ScreenShot avec Selenium (édition Python)
Scraping avec Python + PyQuery
Gratter avec une belle soupe
Scraping RSS avec Python
J'étais accro au grattage avec Selenium (+ Python) en 2020
Impossible de manipuler l'iframe dans la page avec Selenium
J'ai essayé de gratter avec Python
Télécharger automatiquement des images avec grattage
Web scraping avec python + JupyterLab
Grattage festif avec Python, scrapy
Enregistrez des images avec le web scraping
Python: travailler avec Firefox avec du sélénium
Grattage avec Tor en Python
Web scraping avec Selenium (Python)
Scraping prévisions météorologiques avec python
Souvenirs de combats avec Selenium
Gratter la moyenne du Nikkei avec le dramaturge-python
Essayez Selenium Grid avec Docker
[Python + Selenium] Conseils pour le grattage
J'ai essayé de gratter avec du python
Web scraping débutant avec python
Grattage de table avec belle soupe
[Python, Selenium, PhantomJS] Une histoire lors de la capture d'un site Web avec une charge paresseuse
J'ai essayé de me connecter automatiquement à Twitter avec du sélénium (RPA, scraping)
Essayez de gratter avec Python + Beautiful Soup
Scraping avec Node, Ruby et Python
Résumé de la relation de grattage (sélénium, pyautogui)
Web scraping avec Python Première étape
J'ai essayé webScraping avec python.
Grattage avec Python et belle soupe
Gratter avec une belle soupe en 10 minutes
Des tests plus familiers avec Selenium
Faisons du scraping d'images avec Python
Gratter la page du portefeuille SBI Securities
Mémo d'apprentissage "Scraping & Machine Learning avec Python"