Etiquetas:

Para recolher dados na Internet, pode criar um Web crawler ou Web scraping com Python. Um Web crawler é uma ferramenta que extrai dados de uma ou mais páginas Web.

Configurar o ambiente Python

Assumimos que o Python3 e o pip estão instalados na sua máquina. Também pode usar um ambiente virtual para manter o seu projeto limpo e controlar as versões da biblioteca do seu rastreador web Python.

Primeiro, vamos instalar a biblioteca requests, que permite efetuar pedidos HTTP ao servidor para obter dados.

python -m pip install requests

Para analisar e navegar nos dados da Web, utilizamos a biblioteca Beautiful Soup, que nos permite trabalhar com scripts utilizando etiquetas como HTML ou XML.

python -m pip install beautifulsoup4

Finalmente, estamos a instalar a biblioteca Selenium, que automatiza as tarefas do navegador Web. Pode ser utilizada para apresentar páginas Web dinâmicas e executar acções na interface. Esta biblioteca, por si só, pode ser utilizada para a recolha de dados na Internet, uma vez que pode trabalhar com um sítio Web dinâmico que utilize JavaScript.

python -m pip install selenium

Para que o Selenium funcione com o Mozilla, é necessário descarregar o Geckodriver

Recuperação de uma página Web com resquest

Se pretendermos obter os dados técnicos de uma placa Arduino, podemos carregar a página que pretendemos utilizando requests e bs4

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

Ao observar a estrutura da página, pode identificar as etiquetas, classes, identificadores ou textos que lhe interessam. Neste exemplo, recuperamos

  • o nome do cartão
  • descrição do cartão

N.B.: Pode visualizar a estrutura da página Web no seu programa de navegação clicando com o botão direito do rato na página e seleccionando “Inspecionar”.

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 operação pode ser completada com uma lista de URLs para vários cartões.

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

Infelizmente, este método não nos permite carregar a lista detalhada das especificações “Tech Specs”, pelo que temos de utilizar o browser.

Configurar um Web Crawler com o Selenium

Carregar uma página é 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 Criar um Web Crawler com Python

Validação de cookies

Quando a página é apresentada, é provável que se depare com o banner dos cookies, que terá de aceitar ou rejeitar para poder continuar a navegar. Para o fazer, procure e clique no botão “aceitar”

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

À espera de carregar

Quando a página é apresentada no browser, demora algum tempo a carregar os dados e a apresentar todas as etiquetas. Para esperar que a página seja carregada, pode esperar um período de tempo arbitrário

browser.implicitly_wait(10)

Ou esperar até que uma determinada etiqueta esteja presente, como o botão de aceitação 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)

Nota: Se encontrar qualquer outro problema (elemento desconhecido, botão não clicável, etc.) no script quando não há problemas na página Web, não hesite em utilizar a função time.sleep().

Localizar e premir um elemento DOM

Para visualizar as especificações técnicas, o guião deve clicar no separador “Especificações técnicas”. De seguida, é necessário encontrar o elemento a partir do texto. Há duas formas de o fazer: testar o texto do elemento ou utilizar o 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 os dados pretendidos

Quando a página pretendida tiver sido carregada, pode obter os dados

Todos os dados apresentados em forma de tabela

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

Ou dados 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 da pesquisa de especificações

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> 

Recuperação de dados de diferentes páginas

Depois de dominar estas ferramentas e ter uma boa ideia dos dados a recuperar e da estrutura das páginas Web, pode extrair dados de várias páginas. Neste último exemplo, estamos a obter dados técnicos de várias placas Arduino. Para isso, criamos um loop que executa o código anterior numa lista de sites

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

Combinando Selenium e BeautifulSoup

As duas bibliotecas podem ser combinadas para oferecer todas as suas funcionalidades

from bs4 import BeautifulSoup
from selenium import webdriver

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

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

browser.quit()

Aplicações

Fontes