O guia definitivo para criar um raspador da Web com o Pyppeteer

Mihnea-Octavian Manolache em 28 de fevereiro de 2023

imagem do blogue

Quando se trata de Python e automação web, o Selenium era praticamente a escolha certa. Pelo menos até agora. Por causa do sucesso do Puppeteer na comunidade JavaScript, os desenvolvedores Python começaram a olhar mais e mais para ele. E foi assim que o Pyppeteer surgiu. Mas o que é exatamente o Pyppeteer? E porque é que o devemos escolher em vez do Selenium? É confiável o suficiente para construir uma solução complexa usando-o? A todas essas perguntas e muitas outras, responderemos no artigo de hoje. O meu objetivo para hoje é que, se lerem este material, saiam com, pelo menos:

  • Uma definição do Pyppeteer e dos seus casos de utilização
  • Compreensão de como o Pyppeteer se compara ao Selenium
  • Uma implementação real de um web scraper usando Pyppeteer

Por isso, prepare-se, porque hoje vamos falar e pôr as mãos na massa!

O que é realmente o Pyppeteer e como o pode utilizar?

Se está a ler isto, é provável que já esteja familiarizado com o que são scripts Web em geral. E provavelmente já ouviu falar do Puppeteer ou do Selenium, dependendo da sua linguagem de programação favorita. Mas o Pyppeteer é de facto mais recente na cena do web scraping. Bem, para resumir, o Pyppeteer é muito mais parecido com o Puppeteer do que com o Selenium.

O Puppeteer é uma biblioteca Node.js que facilita o controlo de uma versão sem cabeça do Chrome através do protocolo DevTools. Pyppeteer é uma porta Python do Puppeteer. Assim como o Puppeteer original, o Pyppeteer é uma biblioteca, escrita em Python, que basicamente automatiza um navegador. Em outras palavras, Pyppeteer é uma implementação em Python da API do Puppeteer, que permite usar os recursos do Puppeteer num ambiente Python. A principal diferença entre os dois é a linguagem utilizada.

Terminologia do Pyppeteer que deve conhecer

Antes de avançarmos, acho que devemos discutir alguns termos comumente usados no contexto do Pyppeteer:

  • Sem cabeça: Significa iniciar um browser sem uma interface gráfica do utilizador (GUI). Por outras palavras, está a ser executado "nos bastidores" e não é possível vê-lo no ecrã. É normalmente utilizado para reduzir a utilização de recursos durante a recolha de dados.
  • Com cabeça: Por outro lado, um browser "headful" é um browser que está a funcionar com uma GUI. É o oposto de um browser sem cabeça e é frequentemente utilizado para testar, depurar ou interagir manualmente com páginas Web.
  • Contexto do navegador: Este é um estado partilhado entre todas as páginas de um browser. É normalmente utilizado para definir definições de todo o navegador, como cookies, cabeçalhos HTTP e geolocalização.
  • DOM: O Modelo de Objeto de Documento (DOM) é uma interface de programação para documentos HTML e XML. Ele representa a estrutura de uma página da Web em um formato semelhante a uma árvore, com nós que representam elementos. O Pyppeteer permite-lhe interagir com os elementos de uma página através da manipulação do DOM.
  • Elementos: Os blocos de construção de uma página Web. São definidos através de etiquetas, atributos e valores.

É claro que há mais do que isso e aprenderá mais ao longo do caminho. Mas eu queria que ficasse com uma ideia do que se trata, para termos um começo sólido. Estou convencido de que o conhecimento destes termos o ajudará a compreender melhor a essência deste artigo.

Porquê utilizar o Pyppeteer no seu projeto de raspagem?

Penso que há dois aspectos nesta questão. O primeiro é porque é que o Pyppeteer é uma boa escolha para web scraping em geral. O segundo é por que usar o Pyppeteer em vez do Selenium. Em geral, algumas das vantagens do Pyppeteer são

  • Avaliando JavaScript: O Pyppeteer fornece uma função `page.evaluate()`. Ela permite executar código JavaScript dentro do contexto da página.
  • Controlo de rede: O Pyppeteer fornece um método `page.on()`. Isso permite que você escute eventos de rede, como requisições e respostas, que acontecem numa página.
  • Rastreamento e Registo: O Pyppeteer permite-lhe rastrear a atividade do browser e registar as mensagens do browser a partir de uma página. Isso facilita a depuração, o rastreamento e a compreensão do que um site está fazendo.

Comparado com o Selenium, é bastante semelhante, na medida em que ambos são utilizados para automatizar um navegador Web. No entanto, existem algumas diferenças e vantagens chave que o Pyppeteer tem sobre o Selenium:

  • Simplicidade: O Pyppeteer tem uma API mais simples e mais consistente do que o Selenium, o que o torna mais fácil de usar para iniciantes. A API do Pyppeteer é construída em cima do protocolo DevTools, que é próximo ao navegador, e é fácil de aprender e usar.
  • Desempenho: O Pyppeteer pode ser mais rápido do que o Selenium porque é construído sobre o protocolo DevTools. O protocolo foi concebido para a depuração de páginas Web e é muito mais rápido do que o Selenium WebDriver.
  • Melhor controlo da rede: O Pyppeteer permite um maior controlo sobre as definições de rede do browser, como a interceção de pedidos e o bloqueio de pedidos/respostas. Isso facilita o teste e o diagnóstico de problemas relacionados à rede.

E, claro, há também uma questão de escolha. Veja-se o meu caso, por exemplo. No dia a dia, codifico em JavaScript. E estou bastante familiarizado com o Puppeteer. Mas, por outro lado, a minha linguagem de programação favorita é Python. Por isso, se eu tivesse de construir um Scraper com uma tecnologia conhecida numa linguagem que prefiro, provavelmente escolheria o Pyppeteer.

E com isso dito, acho que já cobrimos os aspectos "falados" deste artigo. Está na altura de começar com alguma codificação real.

Como criar um raspador da Web com o Pyppeteer

Antes de começarmos a codificar, deixa-me apresentar-te a documentação oficial do Pyppeteer. Eu sou um defensor do uso da documentação oficial sempre que alguém se sente preso. Isso é antes de fazer perguntas na comunidade (como no Stackoverflow). Eu geralmente acho que a maioria das respostas podem ser encontradas se você ler a documentação primeiro. Por isso, encara isto como um pedido simpático da minha parte. Sempre que tiveres um problema, consulta a documentação, depois procura respostas e faz perguntas apenas como último recurso.

#1: Configurar o ambiente

Antes de mais nada, como programador Python, provavelmente estás familiarizado com ambientes virtuais. Então, a primeira coisa que precisamos fazer é criar um ambiente virtual para o nosso projeto. Esta é geralmente a sequência de comandos que eu uso:

# Criar um novo diretório e navegar para ele

~ " mkdir py_project && cd py_project

# Criar o ambiente virtual

~ " python3 -m venv env

# Ativar o ambiente virtual

~ " source env/bin/activate

Com relação ao ambiente virtual, já está tudo pronto. É hora de seguir em frente e instalar o Pyppeteer. Já que tem o seu terminal aberto, basta digitar:

# Instalar o pacote usando pip

~ " python3 -m pip install pyppeteer

# Abrir o projeto no seu IDE

~ " code .

#2: Criar um raspador Pyppeteer simples

O último comando abre o Visual Studio Code ou sua IDE preferida. Então, agora que você está no 'ambiente de desenvolvimento', vamos criar um novo arquivo `.py` que conterá nosso código. Eu vou chamar meu arquivo de `scraper.py`. Note que o Pyppeteer suporta nativamente execução assíncrona. Então vamos importar tanto o `asyncio` quanto o `pyppeteer` para o nosso arquivo:

importar asyncio
from pyppeteer import launch

Com isto feito, podemos avançar para código mais complicado. Em geral, não sou o maior defensor da programação funcional. No entanto, penso que dividir o código em pequenas partes permite uma melhor aprendizagem. Por isso, vamos envolver o nosso código numa função:

async def scrape(url):

browser = await launch()

page = await browser.newPage()

await page.goto(url)

content = await page.content()

await browser.close()



return content

imagem do blogue

Esta função recebe um URL como entrada e inicia um navegador sem cabeça usando pyppeteer. Em seguida, navega até o URL fornecido, recupera o conteúdo da página e fecha o navegador. O valor que retorna é nada mais do que o HTML coletado da página. Pode utilizar esta função para extrair praticamente qualquer sítio Web. Para usar a função, você a chamaria em um loop de eventos `asyncio`, como este:

async def main():

content = await scrape('https://www.example.com')

print(content)

loop = asyncio.get_event_loop()

loop.run_until_complete(main())

#3: Adicionar mais funcionalidades

Até agora, temos um raspador a funcionar. Mas isso é praticamente tudo o que temos. Se quiseres construir um raspador web mais avançado com o Pyppeteer, terás de adicionar mais funcionalidades ao id. Alerta de spoiler: vamos mergulhar no mundo da programação orientada a objectos. Mas primeiro, vamos traçar os nossos objectivos. O que é que queremos que o nosso scraper seja capaz de fazer?

  1. Inicializar o navegador com alguns valores personalizados
  2. Navegar e extrair conteúdos de uma página Web
  3. Escrever texto num campo de entrada
  4. Extrair o valor de um único elemento
  5. Extrair valor de vários elementos

3.1. Opções personalizadas

Então vamos criar uma nova classe `Scraper` por enquanto e adicionaremos seus métodos depois:

class Scraper:

def __init__(self, launch_options: dict) -> None:

self.options = launch_options['options']

self.viewPort = launch_options['viewPort'] if 'viewPort' in launch_options else None

pass

O único argumento que estamos usando para nosso Scraper é um dicionário `launch_options`. Como você pode ver, ele contém duas chaves dentro dele. Uma chave define as opções de lançamento do Pyppeteer. A segunda opção é `None` ou um dicionário que contém a `width` e `height` do `viewPort`. Esta última é utilizada neste método.

3.2. Navegar para uma página

Se olhar para a função que utilizámos anteriormente, verá que cobrimos tanto a navegação como a extração de dados brutos de um URL específico. A única coisa que precisamos de fazer é ajustar e transformar a função num método para o nosso Scraper:

async def goto(self, url: str) -> None:

self.browser = await launch(options=self.options)

self.page = await self.browser.newPage()

await self.page.setViewport(self.viewPort) if self.viewPort != None else print('[i] Using default viewport')

await self.page.goto(url)

Este método é bastante simples. Primeiro, ele inicia um novo navegador, com as opções personalizadas que definimos anteriormente. Em seguida, ele cria uma nova página e, se o nosso dicionário `launch_options` tiver `viewPort`, então ele define o viewPort da página. Caso contrário, ele registra uma mensagem simples. Por último, mas não menos importante, ele nos leva ao destino.

3.3. Extrair dados brutos de uma página

Novamente, temos o método em nossa função `scraper` inicial. Nós apenas aguardaremos o `page.content()` carregar e retornar seu valor:

async def get_full_content(self) -> str:

content = await self.page.content()

return content

3.4. Escrever texto num campo de entrada

Para escrever algo em um campo de entrada usando o Pyppeteer, você precisará de duas coisas. Primeiro, localizar o elemento. Segundo, adicionar algum valor a ele. Felizmente, o Pyppeteer tem métodos para essas duas ações:

async def type_value(self, seletor: str, value: str) -> None:

element = await self.page.querySelector(seletor)

await element.type(value)

3.5. Extrair valor da página

Lembre-se que queremos poder extrair o valor de um único elemento ou valores de vários elementos. Poderíamos usar um único método para ambos. Mas eu geralmente gosto das coisas separadas. Então, por enquanto, vou adicionar mais dois métodos:

async def extract_one(self, seletor) -> str:

element = await self.page.querySelector(seletor)

text = await element.getProperty("textContent")

return await text.jsonValue()

Aqui, estamos localizando o elemento utilizando o método `querySelector`. Em seguida, aguardamos o `textContent` e retornamos seu `jsonValue()`. Por outro lado, quando quisermos selecionar muitos elementos, utilizaremos `querySelector`:

async def extract_many(self, seletor) -> list:

result = []

elements = await self.page.querySelectorAll(seletor)

for element in elements:

text = await element.getProperty("textContent")

result.append(await text.jsonValue())

return result

Este método funciona de forma semelhante ao `extract_one`. A única diferença é o seu valor de retorno. Desta vez estamos retornando uma lista de todo o texto dentro dos elementos selecionados. E acho que com isso, atingimos todos os nossos objetivos.

#4: Torná-lo furtivo

Na recolha de dados da Web, a furtividade pode ser descrita como a capacidade de não ser detectado. É claro que construir um raspador totalmente indetetável dá muito trabalho. Por exemplo, o modo Stealth da API de Web Scraping é mantido por uma equipa dedicada. E o esforço colocado nele faz com que a impressão digital do nosso raspador seja única em cada pedido.

Mas o meu objetivo geral para este tutorial é colocá-lo no caminho certo. E o caminho certo para um web scraper completo com Pyppeteer implica em adicionar alguma funcionalidade stealth a ele. Felizmente, assim como existe o `puppeteer-extra-plugin-stealth` no Node, existe um pacote para Python também. E ele é chamado intuitivamente de `pyppeteer-stealth`. Para adicioná-lo ao seu projeto, primeiro, instale-o usando pip:

~ " python3 -m pip install pyppeteer_stealth

Em seguida, importe-o para o seu projeto e adicione apenas uma linha de código extra:

async def goto(self, url: str) -> None:

self.browser = await launch(options=self.options)

self.page = await self.browser.newPage()

# Torná-lo furtivo

await stealth(self.page)

await self.page.setViewport(self.viewPort) if self.viewPort != None else print('[i] Using default viewport')

await self.page.goto(url)

E aqui está como se executa o scraper. Adicionei alguns comentários ao código para realçar o que cada passo está a fazer:

async def main():

# Define the launch options dictionary

launch_options = {

'options': {

'headless': False,

'autoClose': True

},

'viewPort': {

'width': 1600,

'height': 900

}

}

# Initialize a new scraper

scraper = Scraper(launch_options)

# Navigae to your target

await scraper.goto('https://russmaxdesign.github.io/accessible-forms/accessible-name-input01.html')

# Type `This is me` inside the input field

await scraper.type_value(

'#fish',

'This is me')

# Scrape the entire page

content = await scraper.get_full_content()

print(content)

# Scrape one single element

el = await scraper.extract_one('body > div:nth-child(14) > ul')

print(el)

# Scrape multiple elements

els = await scraper.extract_many('p')

print(els)

loop = asyncio.get_event_loop()

loop.run_until_complete(main())

Conclusão

Pyppeteer é uma ferramenta incrível para raspagem da web. Ele porta toda a API do Puppeteer para Python, tornando possível para a comunidade Python usar essa tecnologia sem aprender JavaScript. Além disso, eu não acho que ele seja um substituto para o Selenium, mas com certeza é uma boa alternativa a ele.

Espero que o artigo de hoje tenha acrescentado valor ao seu percurso de aprendizagem. E como gosto de desafiar os limites de todos, desafio-vos a acrescentar mais ao que aprenderam hoje. O scraper que construímos juntos é um ótimo ponto de partida e introduz um elemento chave na programação: OOP. Então, eu desafio você a adicionar mais métodos ao `Scraper` e torná-lo realmente incrível.

Notícias e actualizações

Mantenha-se atualizado com os mais recentes guias e notícias sobre raspagem da Web, subscrevendo a nossa newsletter.

We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.

Artigos relacionados

miniatura
GuiasAPI SERP Scraping - Guia de início

Recolha sem esforço dados em tempo real dos motores de busca utilizando a API SERP Scraping. Melhore a análise de mercado, SEO e pesquisa de tópicos com facilidade. Comece hoje mesmo!

WebscrapingAPI
avatar do autor
WebscrapingAPI
7 min. de leitura
miniatura
GuiasComo extrair dados de produtos da Amazon: Um guia abrangente de melhores práticas e ferramentas

Explore as complexidades da extração de dados de produtos da Amazon com nosso guia detalhado. De práticas recomendadas e ferramentas como a API Amazon Scraper a considerações legais, saiba como enfrentar desafios, contornar CAPTCHAs e extrair insights valiosos com eficiência.

Suciu Dan
avatar do autor
Suciu Dan
15 min. de leitura
miniatura
GuiasSaiba como contornar a deteção do Cloudflare com o melhor navegador Selenium

Saiba qual é o melhor browser para contornar os sistemas de deteção Cloudflare enquanto faz web scraping com o Selenium.

Mihnea-Octavian Manolache
avatar do autor
Mihnea-Octavian Manolache
9 min. de leitura