Web scraping com Playwright

Todos nós sabemos bem que os modelos de inteligência artificial (IA), principalmente algoritmos de machine learning, precisam ser treinados. E, quando falamos de treinamento de bons modelos, estamos falando de milhares, milhões ou bilhões de dados. Portanto, conforme os modelos de machine learning continuam a crescer em complexidade, a necessidade de dados de treinamento precisos e confiáveis nunca foi tão urgente. Uma maneira eficaz de obter esses dados é por meio de web scraping.
Web scraping consiste no processo de extração automática de informações de sites usando ferramentas especializadas.
Saber realizar web scraping é uma habilidade essencial para qualquer desenvolvedor que trabalhe na área de machine learning, processamento de linguagem natural (NLP) e em vários outros campos. Ao extrair informações relevantes de sites, podemos criar conjuntos de dados personalizados para nossos modelos aprenderem. Isso não apenas ajuda a melhorar a precisão dos modelos, mas também permite automatizar tarefas que, de outra forma, exigiriam intervenção manual. Neste post, exploraremos o mundo do web scraping usando Playwright.
O que é Playwright?
Playwright é uma ferramenta de código aberto para automatizar navegações da web, desenvolvida pela Microsoft (será que foi para obter dados para treinar suas IAs?). Ele fornece uma API de alto nível para interagir com páginas da web e é muito popular na comunidade de desenvolvedores. A chave para sua popularidade está em sua facilidade de uso aliada à capacidade de extrair conteúdos até de páginas complicadas.
Playwright permite que os desenvolvedores automatizem tarefas como navegação e interação com elementos. E, o que é melhor: com o Playwright, você pode escrever códigos que simulam as interações de usuários, como envios de formulários. Essa capacidade o torna ideal para tarefas como coleta de dados.
Playwright em ação com Python
# Para pip
pip install pytest-playwright
# Para conda
conda config --add channels conda-forge
conda config --add channels microsoft
conda install pytest-playwright
playwright install
primeiros passos
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("https://www.google.com")
print(page.title())
page.screenshot(path="google_homepage.png")
browser.close()
No trecho acima, primeiro criamos uma instância do navegador (linha 2). Com a instância do navegador criada, você pode navegar para um site usando o método page.goto(). É aqui que as coisas ficam interessantes. O Playwright fornece uma API intuitiva para interagir com páginas da web. No nosso exemplo, estamos usando sua API para imprimir o título da página (linha 5, Google) e também para tirar um screenshot (linha 6) dela (abaixo).

Exemplinho de extração de dados

Agora é hora de extrair alguns dados! O Playwright fornece vários métodos para acessar elementos das páginas de interesse. Métodos como query_selector_all() e query_selector() são ideais para seleções a partir de classes/ids CSS. Já o método locator() pode ser usado com XPaths para obtenção de dados em elementos mais complexos.
Usaremos a sessão de best sellers do site da Amazon como exemplo para obter os dados de vários produtos usando query_selector_all(). Veja nossa função abaixo:
from playwright.sync_api import sync_playwright
def extrai_produtos(url):
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto(url)
produtos = page.query_selector_all('.s-card-container > .a-spacing-base')
dados = []
for prod in produtos:
nome_el = prod.query_selector('.a-size-base-plus')
nome = nome_el.inner_text() if nome_el else None
preco_el = prod.query_selector('.a-price[data-a-size="xl"] > span:first-of-type')
preco = preco_el.inner_text() if preco_el else None
avaliacao_el = prod.query_selector('.a-icon-alt')
avaliacao = avaliacao_el.inner_text() if avaliacao_el else None
dados.append({"nome do produto": nome, "preço": preco, "avaliação": avaliacao})
browser.close()
return dados
produtos = extrai_produtos("https://www.amazon.com/b?node=17938598011")
print(produtos)
Nesta função, primeiro acessamos a página de interesse, como feito no exemplo anterior (linhas 5-7). Depois, usamos o método query_selector_all() para obter os produtos a partir de suas classes CSS (linha 8). Note que estamos procurando todos os elementos com a classe s-card-container que possuem a classe a-spacing-base. Por fim, usamos um loop (linhas 10-16) para extrair várias informações (nome do produto, preço e avaliação) usando os seletores específicos (linhas 11, 13, 15) de cada uma delas. Salvamos tudo numa lista (linha 17).
[{'nome do produto': 'Neutrogena Makeup Remover Wipes, Daily Facial Cleanser Towelettes, Gently Cleanse and Remove Oil & Makeup, Alcohol-Free Makeup Wipes, 2 x 25 ct', 'preço': '$9.97', 'avaliação': '4.8 out of 5 stars'}, {'nome do produto': 'REVLON One-Step Volumizer Hair Dryer and Styler, for Less Frizz, More Shine, and Reduced Heat Damage for Salon Style Round Brush for Blowout, Black (Amazon Exclusive)', 'preço': '$32.94', 'avaliação': '4.5 out of 5 stars'}, {'nome do produto': 'BENGOO G9000 Stereo Gaming Headset for PS4 PC Xbox One PS5 Controller, Noise Cancelling Over Ear Headphones with Mic, LED Light, 7.1 Surround Sound, Soft Memory Earmuffs for Nintendo Xbox Series X|S', 'preço': '$19.99', 'avaliação': '4.3 out of 5 stars'},..
Exemplinho com extração assíncrona
import asyncio
from playwright.async_api import async_playwright
async def extrai_produtos_async(url):
async with async_playwright() as p:
browser = await p.firefox.launch(headless=True)
page = await browser.new_page()
await page.goto(url)
await page.wait_for_timeout(5000)
produtos = await page.query_selector_all('.s-card-container > .a-spacing-base')
dados = []
for prod in produtos:
nome_el = await prod.query_selector('.a-size-base-plus')
nome = await nome_el.inner_text() if nome_el else None
preco_el = await prod.query_selector('.a-price[data-a-size="xl"] > span:first-of-type')
preco = await preco_el.inner_text() if preco_el else None
avaliacao_el = await prod.query_selector('.a-icon-alt')
avaliacao = await avaliacao_el.inner_text() if avaliacao_el else None
dados.append({"nome do produto": nome, "preço": preco, "avaliação": avaliacao})
await browser.close()
return dados
# Executa função
produtos = asyncio.run(extrai_produtos_async("https://www.amazon.com/b?node=17938598011"))
print(produtos)
Essa versão assíncrona é muito útil para lidar com páginas com conteúdo dinâmico ou quando precisamos dimensionar nosso código para lidar com muitas páginas.
Super fácil, não é? Para conhecer outros métodos, confira a documentação oficial.