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
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
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.
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")
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.
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')]
]
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]
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)
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)
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>
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()
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)
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"))]
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()
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')
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