Voltar ao blogue
Guias
Mihnea-Octavian ManolacheLast updated on Mar 31, 202611 min read

Como executar um navegador sem interface gráfica com Python para extração de dados da Web: dicas e truques

Como executar um navegador sem interface gráfica com Python para extração de dados da Web: dicas e truques

A utilização de um navegador sem interface gráfica em Python com o Selenium é praticamente a norma na extração de dados da Web. Mas o que é, afinal, um navegador sem interface gráfica? E qual é o melhor navegador sem interface gráfica para o Selenium? E por que razão utilizar um navegador sem interface gráfica em Python quando se tem o `requests`? Bem, há muitas questões em torno deste tema. O que significa que temos muitas respostas para descobrir juntos. Mas antes de aprofundarmos o assunto, vamos definir alguns objetivos de aprendizagem. No final deste artigo, deverá ser capaz de:

  • Compreender o que é um navegador headless e os seus casos de utilização
  • Saber como abrir um navegador headless em Python
  • Criar um web scraper com Python e Selenium

E, finalmente, também falaremos sobre alternativas aos navegadores headless em Python. Embora o foco seja o Python, o meu objetivo é descobrir a melhor solução de scraping. E isso leva em conta o tempo de resposta, os recursos utilizados, etc. Então, sem mais delongas, vamos mergulhar no assunto!

O que significa navegador headless em Python?

Em termos gerais, um navegador é um programa de computador que permite aos utilizadores navegar e interagir com uma página web. Um navegador headless é exatamente isso, mas sem uma interface gráfica de utilizador. Isto significa que um navegador headless em Python é um programa que pode:

  • Navegar para qualquer site na Internet
  • Renderizar ficheiros JavaScript fornecidos pelo site
  • Interagir com os componentes dessa página web

Compreender que não existe uma GUI associada a ele levanta algumas questões sobre a interação. No entanto, a resposta é bastante simples. Como não há GUI, os humanos não podem interagir diretamente com a página. E é aí que os web drivers entram em ação. Um web driver é uma interface que permite a introspecção e o controlo. Em termos simples, os web drivers são frameworks que nos permitem controlar programaticamente vários navegadores web.

Existem algumas estruturas que permitem a automação de navegadores em Python. Mas a principal é o Selenium. O Selenium é um conjunto de ferramentas criado principalmente para testes automatizados. Mas, na prática, é amplamente utilizado também para web scraping.

Porquê utilizar um navegador headless em Python?

De acordo com o cabeçalho da página inicial do Selenium:

“O Selenium automatiza navegadores. É isso! O que faz com esse poder depende inteiramente de si.”

Isto leva-nos a acreditar que os navegadores automatizados têm vários casos de utilização. Mas porquê executá-los no modo headless? Bem, a resposta é, mais uma vez, simples. Um navegador headless em Python utiliza menos recursos (CPU e memória) em comparação com um navegador headful. E isso deve-se principalmente ao facto de não haver elementos gráficos a serem renderizados.

Mais uma vez, menos ainda é mais quando comparado com um cliente HTTP básico como o `requests` do Python, por exemplo. E isso deve-se ao facto de o navegador headless ainda abrir muitos processos para interagir com a página e renderizar ficheiros JavaScript. Como sabe, o `requests` não consegue renderizar JavaScript. Só é possível obter HTML bruto utilizando-o. E nos dias de hoje, isso não chega nem perto do suficiente para web scraping. A maioria das plataformas web modernas depende fortemente de JavaScript para preencher o DOM. Por exemplo, se tentares usar `curl` numa aplicação React, obterás uma página web vazia que te pede para «ativar o JavaScript»:

<!doctype html>

<html lang="en">

  <head>

 	...

  </head>

  <body>

 	<noscript> You need to enable JavaScript to run this app. </noscript>

 	<div id="root"></div>

  </body>

</html>

Embora não seja possível fazer isso com o `requests`, pode fazê-lo com um navegador headless. E isso responde a uma das nossas perguntas iniciais. Os web scrapers modernos utilizam navegadores headless em vez de requests porque, caso contrário, a resposta seria inconclusiva.

Quais são as desvantagens de um navegador headless?

A principal desvantagem de um navegador headless em Python (e da maioria dos navegadores automatizados) é a sua «impressão digital». Se acompanha os meus artigos, sabe que por vezes falo sobre discrição. Trata-se da capacidade de um navegador automatizado passar despercebido.

E em Python, os navegadores headless são facilmente distinguíveis. Para começar, verificar uma propriedade simples do navegador, como `navigator.webdriver`, é uma indicação imediata de que um navegador é controlado por um web driver. No web scraping, um dos principais desafios é encontrar formas de evitar a deteção. Chamamos a estes métodos ou técnicas de evasão. Pode ler mais sobre isso aqui.

Na Web Scraping API, por exemplo, temos uma equipa dedicada a trabalhar constantemente no nosso Modo Stealth. Isso é para garantir que a impressão digital do nosso navegador é única e indetetável em cada pedido.

Em primeiro lugar, saiba que o Selenium é muito poderoso. E nem sequer se limita ao Python. Existem clientes Selenium e web drivers para C#, Ruby, Java, Python e até mesmo JavaScript. E o suporte do web driver Selenium é ainda mais impressionante. Suporta todos os principais navegadores:

No mundo do web scraping, os navegadores headless mais utilizados em Python são o Chrome e o Firefox. Penso que isso se deve principalmente ao facto de estes dois navegadores serem eficientes e multiplataforma. Pode, por exemplo, desenvolver o seu projeto de web scraping num ambiente MacOS e, em seguida, implementá-lo facilmente no Linux.

Como abrir um navegador headless em Python

Agora que abordámos alguns conceitos teóricos, penso que é seguro avançar e explorar a parte prática. Nesta secção, vou mostrar-lhe como criar um web scraper com o Selenium. Para este projeto, certifique-se de que o seu computador tem o Python e o Chrome instalados.

#1: Configurar o ambiente

Como de costume, em Python devemos encapsular tudo dentro de um ambiente virtual. Se não estiver familiarizado com ambientes virtuais, leia isto primeiro. Agora vamos abrir uma nova janela de terminal e vamos:

  • Criar uma nova pasta
  • Navegar até à pasta
  • Criar um novo ambiente virtual
  • Ativar o ambiente virtual

~ mkdir headless_scraper

~ cd headless_scraper

~ python3 -m venv env

~ source env/bin/activate

#2: Instalar dependências

É bastante óbvio que precisamos do Selenium e de um web driver para o nosso projeto. Felizmente, podemos instalar ambos usando o gestor de pacotes do Python, o `pip`. Na mesma janela do terminal, digite o seguinte comando:

~ pip install selenium webdriver-manager

Agora está tudo pronto para o sucesso! Podemos passar à programação propriamente dita. Uma breve nota: este artigo centra-se na interação com um navegador headless. Uma solução completa de web scraping requer muito mais esforço. Mas tenho a certeza de que, se acompanhar as nossas publicações no blogue, conseguirá fazê-lo num instante.

#3: Abrir um navegador automatizado

Até agora, temos o projeto, mas não há nenhum ficheiro que possamos executar. Vamos criar um novo ficheiro `.py` e abri-lo no nosso IDE:

~ touch headles_scraper.py

~ code .

Deve estar agora no Visual Studio Code ou no seu IDE. Pode começar por importar os pacotes necessários para dentro de `handle_scraper.py`:

from selenium import webdriver

from webdriver_manager.chrome import ChromeDriverManager

Este último é um pacote que o ajuda a gerir facilmente os web drivers para os diferentes navegadores suportados pelo Selenium. Pode ler mais sobre isso aqui. A seguir, queremos criar um novo navegador com o Selenium e abrir um site:

driver = webdriver.Chrome(ChromeDriverManager().install())

driver.get('https://webscrapingapi.com')

Execute este ficheiro agora e verá que funciona. Mas, em vez de utilizar um navegador Python headless, abre-se uma janela do Chrome com interface gráfica:

#4: Criar em modo headless

Configuramos para construir um web scraper que economize recursos. Portanto, idealmente, queremos abrir um navegador headless com o Selenium. Felizmente, existe um método fácil que podemos usar para mudar o Selenium de headful para headless. Só precisamos de utilizar as opções do driver web do Chrome. Então, vamos importar `Options` e adicionar mais duas linhas de código:

...

from selenium.webdriver.chrome.options import Options

...

options = Options()

options.headless = True

driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)

driver.get('https://webscrapingapi.com')

Execute o seu script novamente. Como pode ver, desta vez não aparece nenhuma janela. Mas será que está realmente a funcionar em segundo plano? Uma forma rápida de visualizar e verificar isso é tirar uma captura de ecrã usando o Selenium. Basta adicionar esta linha no final do seu script:

driver.get_screenshot_as_file('headless.png')

Se tudo correu bem, deve ter a mesma imagem que eu:

#5: Adicionar capacidades de scraping

O que é um web scraper? Bem, na sua essência, um web scraper é um programa que chama um endpoint de um servidor e recolhe dados a partir dele. No caso de sites, esses dados consistem geralmente em ficheiros HTML. Mas, atualmente, certos servidores também servem objetos JSON. Por isso, vamos manter este termo: dados. Para a secção seguinte, vamos elevar os nossos objetivos. Vamos usar alguma programação orientada para objetos! Os nossos objetivos são:

  • Criar uma classe Scraper
  • Adicionar um método para extrair dados brutos
  • Adicionar um método para extrair dados de um único elemento
  • Adicionar um método para extrair dados de elementos da mesma classe

Portanto, temos três métodos básicos que queremos construir. No entanto, para fins de aprendizagem, estes três métodos abrem um caminho não só para o web scraping, mas também para a POO com Python. E acho isso muito fixe! Agora vamos remover tudo o que codificámos e vamos começar do zero:

from selenium import webdriver

from selenium.webdriver.chrome.options import Options

from selenium.webdriver.common.by import By

from selenium.webdriver.remote.webelement import WebElement

class Scraper:

   def __init__(self, headless: bool = True) -> None:

       self.headless = headless

       pass

   def setup_scraper(self) -> None:

       self.options = Options()

       self.options.headless = self.headless

       self.driver = webdriver.Chrome(options=self.options)

   def navigate(self, target) -> None:

       self.driver.get(target) if target else print('[!] No target given. Please specify a URL.')

   def extract_raw_data(self) -> str:

       return self.driver.page_source

   def extract_single_element(self,  selector: str, selector_type: By = By.CSS_SELECTOR) -> WebElement:

      return self.driver.find_element(selector_type, selector)

  

   def extract_all_elements(self, selector: str, selector_type: By = By.CSS_SELECTOR) -> list[WebElement]:

       return self.driver.find_elements(selector_type, selector)

Adicionei anotações de tipo para facilitar a compreensão, em vez de melhorar o desempenho. Desta forma, pode realmente visualizar a aplicação de uma perspetiva de E/S. Agora, os métodos são bastante autoexplicativos. Não estamos a realizar qualquer tipo de ação sobre os dados, estamos apenas a devolvê-los. Se quiser, isso pode ser um ponto de partida para criar um scraper complexo com um navegador headless em Python.

Até agora, a execução do ficheiro não faz nada. Isso porque apenas declarámos o nosso Scraper e os seus métodos. Agora temos de os utilizar. Vamos, portanto, adicionar os seguintes trechos de código:

# Initialize a new Scraper and navigate to a target

scraper = Scraper()

scraper.setup_scraper()

scraper.navigate('https://httpbin.org')

# Extract and print the entire HTML document

raw_data = scraper.extract_raw_data()

print(raw_data)

# Extract and print an element by its class name

single_element = scraper.extract_single_element('title', By.CLASS_NAME)

print(single_element.text)

# Extract and print all elements belonging to a tag type

all_elements = scraper.extract_all_elements('a', By.TAG_NAME)

print([el.get_attribute('href') for el in all_elements])

E é isso. Se executares o teu script agora, poderás ver alguma ação a acontecer. Mais uma vez, isto é apenas um protótipo concebido para te ajudar a começar. Se quiseres saber mais sobre como um navegador headless em Python pode ser usado na extração de dados da web, desafio-te a:

Desta forma, irá adquirir conhecimentos e adicionar um projeto ao seu portfólio.

Quais são as melhores alternativas aos navegadores headless em Python?

O Python é uma das linguagens de programação mais populares para criar web scrapers. No entanto, não é a única solução. Nem é a melhor! Nesta secção, discutiremos alternativas a um navegador headless em Python. Começaremos por explicar por que razão se deve procurar soluções alternativas e analisaremos também exemplos específicos.

A principal razão pela qual optaria por uma alternativa à criação de um web scraper em Python por conta própria são os recursos. Uma solução completa de web scraping requer que implemente um sistema de rotação de IP, algumas técnicas de evasão, tenha em conta o desempenho, e isso é apenas para citar alguns exemplos. Portanto, criar um web scraper não é apenas caro, mas também demorado. Sem mencionar que a manutenção da infraestrutura gera ainda mais custos.

A segunda desvantagem do navegador headless em Python tem a ver com o desempenho. Embora o Python seja uma excelente linguagem e seja muito intuitivo, não é especificamente conhecido pela sua velocidade. Ao contrário do Java, por exemplo (que também tem um pacote Selenium), o Python é tanto tipado dinamicamente como interpretado. Estas duas características tornam-no muito mais lento quando comparado com outras linguagens. Agora que temos uma compreensão geral, vamos ser específicos. Aqui estão as 5 principais alternativas ao Selenium e ao navegador headless em Python:

#1: API de Web Scraping

Se quiser resolver a primeira desvantagem que identificámos, então precisa de procurar fornecedores de scraping de terceiros. E a Web Scraping API apresenta um conjunto completo de ferramentas de scraping. Além disso, o nosso serviço está repleto de funcionalidades como:

  • Sistema de rotação de IP para proxies de datacenter e residenciais
  • Modo Stealth
  • Solucionadores de Captcha

Só estas três funcionalidades tornam praticamente impossível que um alvo detecte o nosso scraper e o bloqueie. E depois há as funcionalidades de scraping. Com a API de Web Scraping, pode extrair dados com base em seletores, alternar entre tipos de dispositivos, tirar capturas de ecrã e muito mais. Pode encontrar uma lista completa de funcionalidades aqui.

#2: Puppeteer

O Puppeteer é o equivalente ao Selenium para JavaScript. É uma das bibliotecas mais utilizadas para automação web. Ao contrário do Selenium, o estado padrão do Puppeteer é headless. Por isso, não precisa realmente de adicionar código extra para o tornar headless. O que é ainda mais interessante é que existe também uma implementação da API do Puppeteer para Python. Pode consultar este blogue, onde aprofundo a criação de um web scraper com o Puppeteer.

#3: Playwright

O Playwright é outra ferramenta de automação web desenvolvida por colaboradores da Microsoft. É popular principalmente porque oferece suporte a várias linguagens e plataformas. O seu lema é, na verdade, «Qualquer navegador, qualquer plataforma». A sua API pode ser acedida em qualquer sistema operativo e com qualquer uma das seguintes linguagens:

Estas são as principais alternativas a um navegador headless em Python. Mas também existem outras ferramentas disponíveis. O ZombieJS ou o HtmlUnit são apenas mais duas de uma longa lista. Acho que a escolha de uma tecnologia é tanto uma questão de desempenho como de preferência pessoal. Por isso, encorajo-o a testá-las todas e a escolher a sua favorita.

Conclusões

Usar um navegador headless em Python tem os seus prós e contras. Por um lado, pode criar uma solução personalizada à qual pode sempre adicionar mais funcionalidades. Por outro lado, o desenvolvimento e a manutenção podem ser bastante dispendiosos. E há também a questão da discrição. Se precisar de uma solução profissional, acho que é melhor optar por um fornecedor externo. Caso contrário, para fins de aprendizagem, encorajo-o sempre a experimentar a tecnologia.

Sobre o autor
Mihnea-Octavian Manolache, Desenvolvedor Full Stack @ WebScrapingAPI
Mihnea-Octavian ManolacheDesenvolvedor Full Stack

Mihnea-Octavian Manolache é engenheiro Full Stack e DevOps na WebScrapingAPI, onde desenvolve funcionalidades do produto e mantém a infraestrutura que garante o bom funcionamento da plataforma.

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.