fbpixel
Etiquetas:

Para recopilar datos en Internet, puedes crear un Web crawler o Web scraping con Python. Un rastreador web es una herramienta que extrae datos de una o varias páginas web.

Configuración del entorno Python

Asumimos que Python3 y pip están instalados en tu máquina. También puedes usar un entorno virtual para mantener tu proyecto limpio y controlar las versiones de las librerías de tu rastreador web Python.

Primero vamos a instalar la librería requests, que permite realizar peticiones HTTP al servidor para recuperar datos.

python -m pip install requests

Para analizar y navegar por los datos de la Web, utilizamos la biblioteca Beautiful Soup, que nos permite trabajar con scripts utilizando etiquetas como HTML o XML.

python -m pip install beautifulsoup4

Por último, vamos a instalar la biblioteca Selenium, que automatiza las tareas del navegador web. Se puede utilizar para mostrar páginas web dinámicas y realizar acciones en la interfaz. Esta biblioteca por sí sola se puede utilizar para el web scraping en Internet, ya que puede trabajar con un sitio web dinámico que utiliza JavaScript.

python -m pip install selenium

Para que Selenium funcione con Mozilla, deberá descargar Geckodriver

Recuperar una página web con resquest

Si queremos recuperar los datos técnicos de una placa Arduino, podemos cargar la página que queramos usando requests y bs4

page = requests.get("https://docs.arduino.cc/hardware/uno-rev3/")
content = BeautifulSoup(page.text, 'html.parser')

Observando la estructura de la página, puede identificar las etiquetas, clases, identificadores o textos que le interesen. En este ejemplo, recuperamos

  • el nombre de la tarjeta
  • descripción de la tarjeta

Nota: Puede ver la estructura de la página web en su navegador haciendo clic con el botón derecho del ratón en la página y seleccionando «Inspeccionar».

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.

Esta operación podría completarse con una lista de URL de varias tarjetas.

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/",
]

Lamentablemente, este método no nos permite cargar la lista detallada de especificaciones «Tech Specs», por lo que tenemos que utilizar el navegador.

Configuración de un rastreador web con Selenium

Cargar una página es fácil

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()
python-web-crawler-selenium Creación de un Web Crawler con Python

Validación de cookies

Cuando aparezca la página, es probable que te encuentres con el banner de cookies, que deberás aceptar o rechazar para poder seguir navegando. Para ello, busque y haga clic en el botón «aceptar».

def acceptcookies():
	"""class="iubenda-cs-accept-btn iubenda-cs-btn-primary"""
	browser.find_elements(By.CLASS_NAME,"iubenda-cs-accept-btn")[0].click()
acceptcookies()

Esperando para cargar

Cuando la página se muestra en el navegador, tarda algún tiempo en cargar los datos y en mostrar todas las etiquetas. Para esperar a que se cargue la página, puede esperar un tiempo arbitrario

browser.implicitly_wait(10)

O espere hasta que una etiqueta en particular esté presente, como el botón de aceptación de 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 encuentras cualquier otro problema (elemento desconocido, botón no clicable, etc.) en el script cuando no hay problemas en la página web, no dudes en utilizar la función time.sleep().

Buscar y pulsar un elemento DOM

Para mostrar las especificaciones técnicas, el script debe hacer clic en la pestaña «Especificaciones técnicas». A continuación, debe encontrar el elemento a partir del texto. Hay dos maneras de hacerlo: probar el texto del elemento o utilizar 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()

Recuperar los datos deseados

Una vez cargada la página que desea, puede recuperar los datos

Todos los datos en forma de tabla

#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)

Datos específicos

#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)

Resultado del rastreo de especificaciones

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> 

Recuperación de datos de diferentes páginas

Una vez que domines estas herramientas y tengas una buena idea de los datos a recuperar y de la estructura de las páginas web, podrás raspar datos de varias páginas. En este último ejemplo, estamos recuperando datos técnicos de varias placas Arduino. Para ello, creamos un bucle que ejecutará el código anterior en una lista de sitios

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

Combinación de Selenium y BeautifulSoup

Las dos bibliotecas pueden combinarse para ofrecerte todas sus funciones

from bs4 import BeautifulSoup
from selenium import webdriver

browser = webdriver.Firefox()
browser.get(website)

html = browser.page_source
content = BeautifulSoup(html, 'lxml')

browser.quit()

Aplicaciones

Fuentes