Web scraping é o processo de extração automática de dados de sites. É uma técnica comum usada para coletar grandes quantidades de dados para análise, aprendizado de máquina e muito mais. Em Python, existem muitas bibliotecas excelentes que facilitam o web scraping. Uma opção popular é HTTPX.
HTTPX é um cliente HTTP poderoso e moderno para Python. Ele foi criado pelos desenvolvedores por trás do Requests e se inspira muito no Requests, ao mesmo tempo que adiciona novas funcionalidades como suporte HTTP/2.
Neste guia abrangente, exploraremos como raspar sites de maneira eficaz em Python usando HTTPX.
Introdução ao HTTPX
Para começar, o HTTPX pode ser instalado via pip:
pip install httpx
Alternativamente, Poesia pode ser usada:
poetry add httpx
Depois de instalado, o HTTPX pode ser importado e usado:
import httpx
response = httpx.get(‘https://example.com‘)
print(response.text)
Isso fará uma solicitação GET para example.com e imprimirá o HTML da página inicial.
HTTPX tem uma API simples e suporta todos os verbos HTTP populares como GET, POST, PUT, DELETE, HEAD, OPTIONS, etc.
Alguns recursos principais incluem:
- Suporte HTTP/1.1 e HTTP/2
- API assíncrona estilo aiohttp
- Pool de conexões e manutenção de atividade
- Suporte de proxy
- Configuração de tempo limite
- Persistência de cookies
- API familiar de estilo de solicitações
A seguir, vejamos alguns padrões de uso comuns.
Fazendo solicitações com HTTPX
Para fazer uma solicitação GET, o httpx.get()
método pode ser usado:
response = httpx.get(‘https://example.com‘)
Do mesmo modo, httpx.post()
, httpx.put()
, httpx.delete()
, etc. podem ser usados para outros verbos HTTP.
Parâmetros como cabeçalhos, cookies, tempo limite, etc. podem ser passados como argumentos de palavras-chave:
response = httpx.get(
‘https://httpbin.org/headers‘,
headers = {
‘User-Agent‘: ‘MyBot 1.0‘
},
timeout = 10.0
)
A resposta contém propriedades como status_code
, headers
, text
, json()
, Etc.:
print(response.status_code)
print(response.headers)
print(response.text)
json = response.json()
Você também pode transmitir a resposta de forma incremental iterando o objeto de resposta.
Usando um cliente HTTPX
Para a maioria das tarefas de raspagem, é recomendado usar um persistente httpx.Client
instância.
O cliente lida com coisas como pool de conexões, sessões, cookies, etc. em várias solicitações.
import httpx
client = httpx.Client()
response = client.get(‘https://example.com‘)
print(response.text)
response = client.get(‘https://httpbin.org/cookies/set?name=foo‘)
print(response.text)
response = client.get(‘https://httpbin.org/cookies‘)
print(response.json())
Aqui fazemos várias solicitações usando o mesmo cliente, que trata automaticamente da persistência de cookies.
Você também pode configurar opções como cabeçalhos, proxies, autenticação, etc. ao criar o cliente:
client = httpx.Client(
headers = {
‘User-Agent‘: ‘MyBot 1.0‘,
‘Authorization‘: ‘Bearer xxx‘
},
proxies = ‘http://192.168.1.1:8181/‘,
auth = (‘username‘, ‘password‘)
)
Agora vamos dar uma olhada nas solicitações de criação de forma assíncrona.
Solicitações assíncronas com HTTPX
Para fazer solicitações de forma assíncrona em Python, HTTPX fornece um AsyncClient
:
import httpx
async with httpx.AsyncClient() as client:
response = await client.get(‘https://example.com‘)
Usamos async with
para inicializar o cliente, await
na solicitação e feche automaticamente o cliente posteriormente.
Para extrair vários URLs simultaneamente, podemos usar asyncio.gather()
:
import httpx
import asyncio
async def get_url(url):
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.text
urls = [‘https://example.com‘, ‘https://httpbin.org‘, ‘https://python.org‘]
async def main():
responses = await asyncio.gather(*[get_url(url) for url in urls])
print(responses)
asyncio.run(main())
asyncio.gather()
aguarda simultaneamente várias corrotinas e retorna resultados na ordem dos aguardáveis.
Existem também outras opções como asyncio.as_completed()
para processá-los à medida que forem concluídos:
tasks = [get_url(url) for url in urls]
async def main():
for result in asyncio.as_completed(tasks):
print(await result)
O Async IO permite a busca simultânea de várias páginas ao mesmo tempo, o que é útil para acelerar a extração.
A seguir, veremos a extração de dados de respostas HTML e JSON.
Raspar respostas HTML e JSON
Para raspagem de HTML, podemos usar um analisador como Beautiful Soup para extrair dados:
from bs4 import BeautifulSoup
response = httpx.get(‘https://en.wikipedia.org/wiki/Python_(programming_language)‘)
soup = BeautifulSoup(response.text, ‘html.parser‘)
for link in soup.select(‘.toctext‘):
print(link.text.strip())
Isso imprime o conteúdo do índice da página da Wikipedia.
Para respostas JSON, o HTTPX fornece um recurso integrado .json()
método:
response = httpx.get(‘https://api.github.com/repos/encode/httpx‘)
json = response.json()
print(json[‘description‘])
A json=
O parâmetro também pode ser usado para serializar dados JSON em solicitações.
Junto com um analisador, podemos construir scrapers para extrair dados de APIs e sites.
Lidando com problemas e erros
Durante a raspagem, muitas vezes surgem problemas como erros de conexão, tempos limite, limites de taxa, etc.
HTTPX fornece exceções e ferramentas para tratá-las adequadamente.
Tempos limite
Para lidar com respostas lentas, você pode especificar um personalizado timeout
parâmetro. O padrão é 5 segundos.
response = httpx.get(‘https://example.com‘, timeout=10.0)
Se este valor for excedido, um httpx.TimeoutException
ocorre:
try:
response = httpx.get(‘https://example.com‘, timeout=0.001)
except httpx.TimeoutException:
print(‘Request timed out‘)
Tempos limite mais longos podem ser necessários para determinados sites ou páginas.
Erros HTTP
Para erros HTTP como 400, 500 etc. response.raise_for_status()
método pode ser usado:
try:
response = httpx.get(‘https://httpbin.org/status/500‘)
response.raise_for_status()
except httpx.HTTPStatusError:
print(‘HTTP Error occurred‘)
Isso gerará uma exceção em qualquer código de status 4xx ou 5xx.
Tentando novamente solicitações
Para adicionar lógica de nova tentativa, pacotes externos como tenacity
pode ser usado:
from tenacity import retry, stop_after_attempt
@retry(stop=stop_after_attempt(3))
def make_request():
response = httpx.get(‘https://example.com‘)
response.raise_for_status()
return response.json()
data = make_request()
Aqui tentamos novamente até 3 vezes em qualquer exceção. Lógica de nova tentativa mais avançada também pode ser definida.
Limites de solicitações paralelas
Ao fazer muitas solicitações em paralelo, você poderá encontrar limites de conexão.
A limits
parâmetro pode ser usado para configurar opções como conexões máximas:
client = httpx.AsyncClient(
limits = httpx.Limits(max_connections=20)
)
Ajustar esse parâmetro com base no site de destino pode ajudar a evitar limites.
Ao lidar com esses problemas comuns, raspadores mais resilientes podem ser construídos.
Práticas recomendadas de raspagem
Aqui estão algumas dicas para criar web scrapers eficazes com HTTPX:
Use um cliente HTTPX – Os clientes fornecem pooling de conexões, persistência de cookies e outros benefícios.
Raspe educadamente – Limite as taxas de solicitação para evitar sobrecarregar os servidores. Use atrasos aleatórios e limitação.
Lidar com erros – Use blocos try/except, verificações de status e novas tentativas para lidar com problemas.
Usar IO assíncrono – Raspe páginas simultaneamente para melhorar a velocidade. Mas limite a simultaneidade para evitar proibições.
Randomizar agentes de usuário – Gire strings aleatórias de agente de usuário para parecer mais humano.
Usar Proxies – Gire diferentes proxies/IPs para distribuir solicitações.
Cache e Persistência de Dados – Salve os dados copiados em arquivos/bancos de dados para evitar nova raspagem.
Seguindo práticas recomendadas como essas, raspadores mais robustos e de fácil manutenção podem ser construídos.
Técnicas Avançadas de Raspagem
Vejamos alguns recursos de raspagem mais avançados do HTTPX.
Raspando páginas de autenticação
Para extrair páginas autenticadas, o HTTPX oferece suporte a vários tipos de autenticação, como autenticação Básica, Digest e Bearer:
client = httpx.Client(
auth = (‘username‘, ‘password‘)
)
response = client.get(‘https://api.example.com/users/me‘)
As credenciais de autenticação são persistidas automaticamente nas solicitações.
Manuseio de Cookies
A cookies
parâmetro pode ser usado para enviar cookies personalizados:
client = httpx.Client(
cookies = {
‘sessionId‘: ‘xxxx‘
}
)
response = client.get(‘https://example.com/dashboard‘)
E os cookies definidos pelo servidor são automaticamente persistidos no cliente.
Respostas de streaming
Para respostas grandes, você pode transmiti-las de forma incremental iterando o objeto de resposta:
response = client.get(‘https://example.com/bigfile‘)
for chunk in response:
process(chunk)
Isso evita ter que carregar toda a resposta na memória.
Suporte Proxy
Para rotear solicitações através de um servidor proxy, o proxies
parâmetro pode ser usado:
proxy = ‘http://192.168.0.1:8888‘
client = httpx.Client(proxies = {‘http‘: proxy, ‘https‘: proxy})
A rotação de diferentes proxies ajuda a distribuir solicitações de diferentes IPs.
Cabeçalhos personalizados
Você pode falsificar ou randomizar cabeçalhos de solicitação como agentes de usuário:
client = httpx.Client(headers = {
‘User-Agent‘: ‘MyBot 1.0‘
})
Isso imita os cabeçalhos de um navegador real.
Por meio desses recursos mais avançados, raspadores robustos podem ser construídos usando HTTPX e Python.
Exemplo de raspadores
Vejamos agora alguns exemplos de scrapers construídos com HTTPX.
Raspador de API do Reddit
Aqui está um raspador básico para a API do Reddit:
import httpx
client = httpx.Client()
subreddit = ‘python‘
listing = ‘hot‘
limit = 10
response = client.get(f‘https://www.reddit.com/r/{subreddit}/{listing}.json?limit={limit}‘)
data = response.json()[‘data‘]
for post in data[‘children‘]:
title = post[‘data‘][‘title‘]
score = post[‘data‘][‘score‘]
print(f"{title} (Score: {score})")
Isso busca dados nas principais postagens do subreddit Python. A API retorna JSON que podemos analisar.
Poderíamos estender esse raspador para extrair dados de vários subreddits, armazenar resultados em um banco de dados, etc.
Raspador de artigos de notícias
Aqui está um raspador de notícias simples que extrai artigos de um site:
from bs4 import BeautifulSoup
import httpx
client = httpx.Client()
response = client.get("https://example.com/news")
soup = BeautifulSoup(response.text, ‘html.parser‘)
for article in soup.select(‘.article‘):
title = article.select_one(‘.article-title‘).text
content = article.select_one(‘.article-content‘).text
print(title)
print(content)
print()
Isto encontra tudo .article
elementos, extrai os campos de título e conteúdo e imprime os artigos.
Novamente, isso poderia ser expandido para extrair campos adicionais, analisar datas, armazenar em um banco de dados, etc.
Raspador de resultados de pesquisa
E aqui está um exemplo de raspador para resultados de pesquisa do Google:
import httpx
query = "httpx python"
url = f"https://www.google.com/search?q={query}"
client = httpx.Client()
response = client.get(url)
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, ‘html.parser‘)
for result in soup.select(‘.tF2Cxc‘):
title = result.select_one(‘.DKV0Md‘).text
link = result.select_one(‘.yuRUbf a‘)[‘href‘]
print(title)
print(link)
print()
Isso pesquisa uma determinada consulta no Google, analisa os links/títulos dos resultados e os imprime.
Novamente, muitas melhorias poderiam ser feitas, como extração de contagens de resultados de pesquisa, campos adicionais, extração de páginas de resultados, detecção de captchas, etc.
Esses exemplos demonstram padrões comuns de raspagem com HTTPX. As mesmas técnicas podem ser aplicadas para construir scrapers para muitos sites e APIs.
Resumo
Para resumir, HTTPX fornece um cliente HTTP poderoso para construir web scrapers em Python. Aqui estão alguns pontos-chave:
HTTPX tem uma API simples no estilo de solicitações para fazer solicitações.
O suporte assíncrono permite fazer solicitações simultaneamente.
Tratamento robusto de erros com tempos limite, novas tentativas e verificações de status.
Raspe páginas HTML com APIs Beautiful Soup e JSON facilmente.
Clientes persistentes fornecem pooling de conexões, sessões e manipulação de cookies.
Técnicas avançadas como proxies, cabeçalhos e autenticação permitem scrapers sofisticados.
Siga as práticas recomendadas, como uso de otimização, atrasos aleatórios e agentes de usuário.
HTTPX facilita o início da raspagem com Python. Com tratamento robusto de erros e simultaneidade assíncrona, raspadores escalonáveis podem ser desenvolvidos.
Experimente o HTTPX em seu próximo projeto de web scraping em Python!