Pour récolter des données sur internet, il est possible de créer un Web crawler ou Web scraping avec Python. Un robot d’exploration du Web est un outil qui permet d’extraire des données d’une ou plusieurs pages Web.
Configuration de l’environnement Python
Nous partons du principe que Python3 et pip sont installés sur votre machine. Vous pouvez également utiliser un environnement virtuel pour conserver un projet propre et maitriser les versions de librairies de votre web crawler Python.
Nous allons tout d’abord installer la librairie requests qui permet de faire des requêtes HTTP au serveur pour récupérer les données.
python -m pip install requests
Pour analyser et naviguer dans les données du Web, nous utilisons la librairie Beautiful Soup qui permet de travailler avec des scripts à balises comme le HTML ou le XML
python -m pip install beautifulsoup4
Enfin, nous installons la librairie Selenium qui permet d’automatiser les tâches d’un navigateur Web. Elle permet d’afficher des pages web dynamiques et de réaliser des actions sur l’interface. Cette librairie permet à elle seule de faire du Web scraping sur internet car elle peut travailler avec un site web dynamique qui fonctionne avec JavaScript.
python -m pip install selenium
Pour faire fonctionner Selenium avec Mozilla, vous aurez besoin de télécharger Geckodriver
Récupérer une page Web avec resquest
Imaginons que nous souhaitions récupérer les données techniques d’une carte Arduino, nous pouvons charger la page désirée avec requests et bs4
page = requests.get("https://docs.arduino.cc/hardware/uno-rev3/")
content = BeautifulSoup(page.text, 'html.parser')
En observant la structure de la page, vous pouvez repérer les balises, classes, identifiants ou textes qui vous intéressent. Dans cet exemple, nous récupérons
- le nom de la carte
- la description de la carte
N.B.: Vous pouvez retrouver la structure de la page web sur votre navigateur avec clique-droit sur la page puis “Inspecter”
import requests from bs4 import BeautifulSoup print("Starting Web Crawling ...") #website to crawl website="https://docs.arduino.cc/hardware/uno-rev3/" #google search #keywords = ["arduino","datasheet"] #googlesearch = "https://www.google.com/search?client=firefox-b-d&q=" #search = "+".join(keywords) #website = googlesearch+search # get page page = requests.get(website) #extract html data content = BeautifulSoup(page.text, 'html.parser') # extract tags h1_elms = content.find_all('h1') print("Board : ",h1_elms) #get element by class description = content.find(class_="product-features__description").text print("Description : ",description)
Starting Web Crawling ...
Board : [<h1>UNO R3</h1>]
Description : Arduino UNO is a microcontroller board based on the ATmega328P. It has 14 digital input/output pins (of which 6 can be used as PWM outputs), 6 analog inputs, a 16 MHz ceramic resonator, a USB connection, a power jack, an ICSP header and a reset button. It contains everything needed to support the microcontroller; simply connect it to a computer with a USB cable or power it with a AC-to-DC adapter or battery to get started. You can tinker with your UNO without worrying too much about doing something wrong, worst case scenario you can replace the chip for a few dollars and start over again.
On pourrait imaginer boucler cet opération sur une liste d’URL pour plusieurs cartes.
websites = [ "https://docs.arduino.cc/hardware/uno-rev3/", "https://docs.arduino.cc/hardware/nano/", "https://docs.arduino.cc/hardware/mega-2560/", "https://docs.arduino.cc/hardware/leonardo/", ]
Avec cette méthode, on ne peut malheureusement pas charger la liste détaillé des spécification “Tech Specs” pour cela nous devons nous servir du navigateur.
Mettre en place un Web Crawler avec Selenium
Pour charger une page rien de plus facile
from selenium import webdriver GECKOPATH = "PATH_TO_GECKO" sys.path.append(GECKOPATH) print("Starting Web Crawling ...") #website to crawl website="https://docs.arduino.cc/hardware/uno-rev3/" #create browser handler browser = webdriver.Firefox() browser.get(website) #browser.quit()
Validation des cookies
En affichant la page, vous aller certainement tomber sur la bannière de cookie qu’il faudra valider ou non pour continuer la navigation. Pour cela, il faut retrouver et cliquer sur le bouton “accepter”
def acceptcookies(): """class="iubenda-cs-accept-btn iubenda-cs-btn-primary""" browser.find_elements(By.CLASS_NAME,"iubenda-cs-accept-btn")[0].click() acceptcookies()
Attente de chargement
Comme la page est affiché dans le navigateur, il faut un certain temps pour qu’elle charge les données et que toutes les balises soient affichées. Pour attendre le chargement, vous pouvez attendre un temps arbitraire
browser.implicitly_wait(10)
Ou attendre qu’une balise particulière soit présente comme le bouton d’acceptation des cookies
from selenium.common.exceptions import TimeoutException from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions def waitForElement(locator, timeout ): elm = WebDriverWait(browser, timeout).until(expected_conditions.presence_of_element_located(locator)) return elm myElem =waitForElement((By.CLASS_NAME , 'iubenda-cs-accept-btn'),30)
N.B: Si vous rencontrez d’autre problème (élément inconnu , bouton non cliquable, etc.) dans le script alors qu’il n’y a pas de soucis sur la page Web, n’hésitez pas à utiliser la fonction time.sleep()
Chercher et appuyer sur un élément DOM
Pour afficher les spécifications techniques, le script doit cliquer sur l’onglet ‘Tech Specs’. Il faut donc trouver l’élément à partir du texte. Pour cela, il y a deux méthodes: tester le texte de l’élément ou utiliser Xpath
#get element by text btn_text = 'Tech Specs' btn_elms = browser.find_elements(By.CLASS_NAME,'tabs')[0].find_elements(By.TAG_NAME,'button') for btn in btn_elms: if btn.text == btn_text: btn.click() spec_btn = browser.find_element(By.XPATH, "//*[contains(text(),'Tech Specs')]") spec_btn.click()
Récupérer les données désirées
Une fois la page souhaitée chargée, vous pouvez récupérer les données
Soit toutes les données qui sont affichées sous forme de tableau
#get all rows and children print("Tech specs") print("-------------------------------------") tr_elms = browser.find_elements(By.TAG_NAME,'tr') for tr in tr_elms: th_elms = tr.find_elements(By.XPATH, '*') if len(th_elms)>1: print(th_elms[0].text, " : ", th_elms[1].text)
Soit une donnée spécifique
#get parent and siblings print("Specific data") print("-------------------------------------") data_row = browser.find_element(By.XPATH, "//*[contains(text(),'Main Processor')]") data = data_row.find_element(By.XPATH, "following-sibling::*[1]").text print(data_row.text, " : ", data)
Résultat du crawling des spécifications
Starting Web Crawling ...
Page is ready!
Tech specs
-------------------------------------
Name : Arduino UNO R3
SKU : A000066
Built-in LED Pin : 13
Digital I/O Pins : 14
Analog input pins : 6
PWM pins : 6
UART : Yes
I2C : Yes
SPI : Yes
I/O Voltage : 5V
Input voltage (nominal) : 7-12V
DC Current per I/O Pin : 20 mA
Power Supply Connector : Barrel Plug
Main Processor : ATmega328P 16 MHz
USB-Serial Processor : ATmega16U2 16 MHz
ATmega328P : 2KB SRAM, 32KB FLASH, 1KB EEPROM
Weight : 25 g
Width : 53.4 mm
Length : 68.6 mm
Specific data
-------------------------------------
Main Processor : ATmega328P 16 MHz
PS D:\Formation\Python\WebCrawler>
Récupérer des données sur différentes pages
Une fois que vous maitrisez ces outils et avez une bonne idée des données à récupérer et de la structure des pages Web, vous pouvez scraper des données sur plusieurs pages. Dans ce dernier exemple, nous récupérons les données techniques de différentes cartes Arduino. Pour cela, nous créons une boucle qui va exécuter le code précédent sur une liste de site
websites = [ "https://docs.arduino.cc/hardware/uno-rev3/", "https://docs.arduino.cc/hardware/nano/", "https://docs.arduino.cc/hardware/mega-2560/", "https://docs.arduino.cc/hardware/leonardo/", ]
import sys import time import requests from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import TimeoutException from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions GECKOPATH = "D:\\AranaCorp\\Marketing\\Prospects" sys.path.append(GECKOPATH) print("Starting Web Crawling ...") websites = [ "https://docs.arduino.cc/hardware/uno-rev3/", "https://docs.arduino.cc/hardware/nano/", "https://docs.arduino.cc/hardware/mega-2560/", "https://docs.arduino.cc/hardware/leonardo/", ] #create browser handler browser = webdriver.Firefox()#Firefox(firefox_binary=binary) def acceptcookies(): #class="iubenda-cs-accept-btn iubenda-cs-btn-primary browser.find_elements(By.CLASS_NAME,"iubenda-cs-accept-btn")[0].click() def waitForElement(locator, timeout ): elm = WebDriverWait(browser, timeout).until(expected_conditions.presence_of_element_located(locator)) return elm cookie_accepted=False for website in websites: browser.get(website) time.sleep(2) if not cookie_accepted: #accept cookie once myElem =waitForElement((By.CLASS_NAME , 'iubenda-cs-accept-btn'),30) print("Page is ready!") acceptcookies() cookie_accepted = True else: myElem =waitForElement((By.CLASS_NAME , 'tabs__item'),30) #get board name name = browser.find_element(By.TAG_NAME,'h1').text #get tab Tech Specs btn_text = 'Tech Specs' spec_btn = WebDriverWait(browser, 20).until(expected_conditions.element_to_be_clickable((By.XPATH, "//*[contains(text(),'{}')]".format(btn_text)))) spec_btn.click() #browser.execute_script("arguments[0].click();", spec_btn) #use script to click #get all rows and children print(name+" "+btn_text) print("-------------------------------------") tr_elms = browser.find_elements(By.TAG_NAME,'tr') for tr in tr_elms: th_elms = tr.find_elements(By.XPATH, '*') if len(th_elms)>1: print(th_elms[0].text, " : ", th_elms[1].text) #get parent and siblings print("Specific data") print("-------------------------------------") try: data_row = browser.find_element(By.XPATH, "//*[contains(text(),'Main Processor')]") except: data_row = browser.find_element(By.XPATH, "//*[contains(text(),'Processor')]") data = data_row.find_element(By.XPATH, "following-sibling::*[1]").text print(data_row.text, " : ", data) browser.quit()
Starting Web Crawling ...
Page is ready!
UNO R3 Tech Specs
-------------------------------------
Main Processor : ATmega328P 16 MHz
Nano Tech Specs
-------------------------------------
Processor : ATmega328 16 MHz
Mega 2560 Rev3 Tech Specs
-------------------------------------
Main Processor : ATmega2560 16 MHz
Leonardo Tech Specs
-------------------------------------
Processor : ATmega32U4 16 MHz
Combiner Selenium et BeautifulSoup
Il est possible de combiner les deux librairies afin de vous apporter toutes leurs fonctionnalités
from bs4 import BeautifulSoup from selenium import webdriver browser = webdriver.Firefox() browser.get(website) html = browser.page_source content = BeautifulSoup(html, 'lxml') browser.quit()
Applications
- Automatiser des tâches de relevée de données sur le Web
- Créer votre banque d’image pour l’entrainement de réseau de neurone
- Trouver des prospect
- Faire un étude de marché