Salta al contenuto

Come eseguire il web scraping con HTTPX e Python

Il web scraping è il processo di estrazione automatica dei dati dai siti Web. È una tecnica comune utilizzata per raccogliere grandi quantità di dati per analisi, apprendimento automatico e altro ancora. In Python ci sono molte ottime librerie che semplificano il web scraping. Un'opzione popolare è HTTPX.

HTTPX è un client HTTP potente e moderno per Python. È stato creato dagli sviluppatori dietro Requests e trae molta ispirazione da Requests, aggiungendo anche nuove funzionalità come il supporto HTTP/2.

In questa guida completa, esploreremo come eseguire lo scraping efficace dei siti Web in Python utilizzando HTTPX.

Iniziare con HTTPX

Per iniziare, HTTPX può essere installato tramite pip:

pip install httpx

In alternativa, la Poesia può essere utilizzata:

poetry add httpx

Una volta installato, HTTPX può essere importato e utilizzato:

import httpx

response = httpx.get(‘https://example.com‘)
print(response.text)

Ciò effettuerà una richiesta GET a example.com e stamperà l'HTML della home page.

HTTPX ha un'API semplice e supporta tutti i verbi HTTP più diffusi come GET, POST, PUT, DELETE, HEAD, OPTIONS, ecc.

Alcune caratteristiche chiave includono:

  • Supporto HTTP/1.1 e HTTP/2
  • API asincrona in stile aihttp
  • Pooling delle connessioni e keepalive
  • Supporto proxy
  • Configurazione del timeout
  • Persistenza dei cookie
  • API familiare in stile richieste

Successivamente diamo un'occhiata ad alcuni modelli di utilizzo comuni.

Effettuare richieste con HTTPX

Per effettuare una richiesta GET, il httpx.get() è possibile utilizzare il metodo:

response = httpx.get(‘https://example.com‘)

Analogamente, httpx.post(), httpx.put(), httpx.delete(), ecc. possono essere utilizzati per altri verbi HTTP.

Parametri come intestazioni, cookie, timeout, ecc. possono essere passati come argomenti di parole chiave:

response = httpx.get(
  ‘https://httpbin.org/headers‘,
  headers = {
    ‘User-Agent‘: ‘MyBot 1.0‘
  },
  timeout = 10.0
)

La risposta contiene proprietà come status_code, headers, text, json()etc:

print(response.status_code)
print(response.headers)
print(response.text)
json = response.json()

È inoltre possibile eseguire lo streaming della risposta in modo incrementale eseguendo l'iterazione sull'oggetto risposta.

Utilizzando un client HTTPX

Per la maggior parte delle attività di scraping, si consiglia di utilizzare un file persistent httpx.Client esempio.

Il client gestisce elementi come pool di connessioni, sessioni, cookie, ecc. su più richieste.

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

Qui effettuiamo più richieste utilizzando lo stesso client, che gestisce automaticamente la persistenza dei cookie.

Puoi anche configurare opzioni come intestazioni, proxy, autenticazione, ecc. durante la creazione del client:

client = httpx.Client(
  headers = {
    ‘User-Agent‘: ‘MyBot 1.0‘,
    ‘Authorization‘: ‘Bearer xxx‘   
  },
  proxies = ‘http://192.168.1.1:8181/‘,
  auth = (‘username‘, ‘password‘)
)

Ora esaminiamo le richieste di creazione in modo asincrono.

Richieste asincrone con HTTPX

Per effettuare richieste in modo asincrono in Python, HTTPX fornisce un file AsyncClient:

import httpx

async with httpx.AsyncClient() as client:
  response = await client.get(‘https://example.com‘) 

Usiamo async with per inizializzare il client, await sulla richiesta e chiudere automaticamente il client in seguito.

Per raschiare più URL contemporaneamente, possiamo utilizzare 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() attende contemporaneamente più coroutine e restituisce i risultati nell'ordine degli waitable.

Ci sono anche altre opzioni come asyncio.as_completed() per elaborarli man mano che vengono completati:

tasks = [get_url(url) for url in urls]

async def main():
  for result in asyncio.as_completed(tasks):
    print(await result)

Async IO consente di recuperare contemporaneamente più pagine contemporaneamente, il che è utile per accelerare lo scraping.

Successivamente diamo un'occhiata allo scraping dei dati dalle risposte HTML e JSON.

Scraping di risposte HTML e JSON

Per lo scraping HTML, possiamo utilizzare un parser come Beautiful Soup per estrarre i dati:

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

Questo stampa il contenuto del sommario della pagina Wikipedia.

Per le risposte JSON, HTTPX fornisce un file built-in .json() Metodo:

response = httpx.get(‘https://api.github.com/repos/encode/httpx‘)

json = response.json()
print(json[‘description‘])

I json= Il parametro può essere utilizzato anche per serializzare i dati JSON nelle richieste.

Insieme a un parser, possiamo costruire scraper per estrarre dati da API e siti web.

Gestione di problemi ed errori

Durante lo scraping, si verificano spesso problemi come errori di connessione, timeout, limiti di velocità, ecc.

HTTPX fornisce eccezioni e strumenti per gestirle in modo appropriato.

timeout

Per gestire le risposte lente, è possibile specificare un file custom timeout parametro. Il valore predefinito è 5 secondi.

response = httpx.get(‘https://example.com‘, timeout=10.0) 

Se questo viene superato, a httpx.TimeoutException si verifica:

try:
  response = httpx.get(‘https://example.com‘, timeout=0.001)
except httpx.TimeoutException:
  print(‘Request timed out‘)

Potrebbero essere necessari timeout più lunghi per determinati siti o pagine.

Errori HTTP

Per errori HTTP come 400, 500 ecc. il response.raise_for_status() è possibile utilizzare il metodo:

try:
  response = httpx.get(‘https://httpbin.org/status/500‘)
  response.raise_for_status()
except httpx.HTTPStatusError:
  print(‘HTTP Error occurred‘)  

Ciò genererà un'eccezione su qualsiasi codice di stato 4xx o 5xx.

Nuovo tentativo di richieste

Per aggiungere la logica dei tentativi, pacchetti esterni come tenacity può essere utilizzato:

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

Qui riproviamo fino a 3 volte per qualsiasi eccezione. È inoltre possibile definire una logica di ripetizione più avanzata.

Limiti delle richieste parallele

Quando si effettuano molte richieste in parallelo, è possibile che si verifichino limiti di connessione.

I limits il parametro può essere utilizzato per configurare opzioni come il numero massimo di connessioni:

client = httpx.AsyncClient(
  limits = httpx.Limits(max_connections=20)
)

L'ottimizzazione di questo parametro in base al sito di destinazione può aiutare a evitare limiti.

Gestendo questi problemi comuni, è possibile costruire raschiatori più resistenti.

Raschiare le migliori pratiche

Ecco alcuni suggerimenti per creare web scraper efficaci con HTTPX:

  • Utilizza un client HTTPX – I client forniscono pool di connessione, persistenza dei cookie e altri vantaggi.

  • Raschiare educatamente – Limitare i tassi di richiesta per evitare server sovraccarichi. Utilizza ritardi e limitazioni casuali.

  • Gestire gli errori – Utilizzare blocchi try/eccetto, controlli di stato e tentativi per gestire i problemi.

  • Utilizza I/O asincrono – Raschiare le pagine contemporaneamente per migliorare la velocità. Ma limita la concorrenza per evitare divieti.

  • Randomizza gli agenti utente – Ruota le stringhe dello user agent casuale per apparire più umano.

  • Usa i proxy – Ruota diversi proxy/IP per distribuire le richieste.

  • Cache e persistenza dei dati – Salvare i dati raschiati in file/database per evitare la nuova raschiatura.

Seguendo le migliori pratiche come queste, è possibile costruire raschiatori più robusti e manutenibili.

Tecniche avanzate di raschiatura

Diamo un'occhiata ad alcune funzionalità di scraping più avanzate di HTTPX.

Raschiare le pagine di autenticazione

Per analizzare le pagine autenticate, HTTPX supporta più tipi di autenticazione come l'autenticazione Basic, Digest e Bearer:

client = httpx.Client(
  auth = (‘username‘, ‘password‘)
)

response = client.get(‘https://api.example.com/users/me‘)

Le credenziali di autenticazione vengono mantenute automaticamente tra le richieste.

Gestione dei cookie

I cookies parametro può essere utilizzato per inviare cookie personalizzati:

client = httpx.Client(
  cookies = {
    ‘sessionId‘: ‘xxxx‘
  }
)

response = client.get(‘https://example.com/dashboard‘) 

E i cookie impostati dal server vengono automaticamente persistenti nel client.

Risposte in streaming

Per risposte di grandi dimensioni, puoi trasmetterle in streaming in modo incrementale eseguendo l'iterazione dell'oggetto risposta:

response = client.get(‘https://example.com/bigfile‘)
for chunk in response:
  process(chunk) 

Ciò evita di dover caricare l'intera risposta in memoria.

Supporto proxy

Per instradare le richieste attraverso un server proxy, il file proxies il parametro può essere utilizzato:

proxy = ‘http://192.168.0.1:8888‘ 

client = httpx.Client(proxies = {‘http‘: proxy, ‘https‘: proxy})

La rotazione di proxy diversi aiuta a distribuire le richieste da IP diversi.

Intestazioni personalizzate

Puoi falsificare o randomizzare le intestazioni delle richieste come gli user agent:

client = httpx.Client(headers = {
  ‘User-Agent‘: ‘MyBot 1.0‘ 
})

Questo imita le intestazioni di un browser reale.

Attraverso queste funzionalità più avanzate, è possibile creare scraper robusti utilizzando HTTPX e Python.

Raschiatori di esempio

Diamo ora un'occhiata ad alcuni esempi di scraper creati con HTTPX.

Raschiatore API Reddit

Ecco uno scraper di base per l'API 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})")

Questo recupera i dati sui post più importanti dal subreddit Python. L'API restituisce JSON che possiamo analizzare.

Potremmo estendere questo scraper per estrarre dati da più subreddit, archiviare i risultati in un database, ecc.

Raschietto per articoli di notizie

Ecco un semplice raschietto di notizie che estrae articoli da un sito:

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

Questo trova tutto .article elementi, estrae i campi titolo e contenuto e stampa gli articoli.

Ancora una volta questo potrebbe essere espanso per raccogliere campi aggiuntivi, analizzare date, archiviare in un database, ecc.

Risultati della ricerca Raschietto

Ed ecco un esempio di scraper per i risultati di ricerca di 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()

Questo cerca su Google una determinata query, analizza i collegamenti/titoli dei risultati e li stampa.

Anche in questo caso potrebbero essere apportati molti miglioramenti come l'estrazione dei conteggi dei risultati di ricerca, campi aggiuntivi, lo scraping delle pagine dei risultati, il rilevamento dei captcha, ecc.

Questi esempi dimostrano modelli di scraping comuni con HTTPX. Le stesse tecniche possono essere applicate per creare scraper per molti siti Web e API.

Sommario

Per riassumere, HTTPX fornisce un potente client HTTP per la creazione di web scraper Python. Ecco alcuni punti chiave:

  • HTTPX dispone di un'API semplice in stile request per effettuare richieste.

  • Il supporto asincrono consente di effettuare richieste contemporaneamente.

  • Gestione efficace degli errori con timeout, tentativi e controlli di stato.

  • Crea facilmente pagine HTML con le API Beautiful Soup e JSON.

  • I client persistenti forniscono pool di connessioni, sessioni e gestione dei cookie.

  • Tecniche avanzate come proxy, intestazioni e autenticazione consentono raschiatori sofisticati.

  • Segui le best practice come l'utilizzo di limitazioni, ritardi casuali e user-agent.

HTTPX semplifica l'avvio dello scraping con Python. Con una solida gestione degli errori e una concorrenza asincrona, è possibile sviluppare scraper scalabili.

Prova HTTPX nel tuo prossimo progetto di web scraping Python!

Tag:

Partecipa alla conversazione

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati con *