Passer au contenu

Comment Web Scrape avec HTTPX et Python

Le Web scraping est le processus d’extraction automatique des données des sites Web. Il s'agit d'une technique courante utilisée pour collecter de grandes quantités de données à des fins d'analyse, d'apprentissage automatique et bien plus encore. En Python, il existe de nombreuses bibliothèques intéressantes qui facilitent le web scraping. Une option populaire est HTTPX.

HTTPX est un client HTTP puissant et moderne pour Python. Il a été créé par les développeurs derrière Requests et s'inspire beaucoup de Requests, tout en ajoutant également de nouvelles fonctionnalités telles que la prise en charge HTTP/2.

Dans ce guide complet, nous explorerons comment supprimer efficacement des sites Web en Python à l'aide de HTTPX.

Premiers pas avec HTTPX

Pour commencer, HTTPX peut être installé via pip :

pip install httpx

Alternativement, la poésie peut être utilisée :

poetry add httpx

Une fois installé, HTTPX peut être importé et utilisé :

import httpx

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

Cela fera une requête GET à example.com et imprimera le HTML de la page d'accueil.

HTTPX possède une API simple et prend en charge tous les verbes HTTP populaires tels que GET, POST, PUT, DELETE, HEAD, OPTIONS, etc.

Certaines fonctionnalités clés incluent:

  • Prise en charge HTTP/1.1 et HTTP/2
  • API asynchrone de style aiohttp
  • Regroupement de connexions et keepalive
  • Support de proxy
  • Configuration du délai d'attente
  • Persistance des cookies
  • API de style requêtes familière

Examinons ensuite quelques modèles d'utilisation courants.

Faire des requêtes avec HTTPX

Pour faire une requête GET, le httpx.get() méthode peut être utilisée :

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

De même, le httpx.post(), httpx.put(), httpx.delete(), etc. peuvent être utilisés pour d’autres verbes HTTP.

Des paramètres tels que les en-têtes, les cookies, le délai d'attente, etc. peuvent être transmis comme arguments de mot-clé :

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

La réponse contient des propriétés telles que status_code, headers, text, json(), Etc:

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

Vous pouvez également diffuser la réponse de manière incrémentielle en itérant sur l'objet de réponse.

Utiliser un client HTTPX

Pour la plupart des tâches de scraping, il est recommandé d'utiliser un fichier persistant httpx.Client exemple.

Le client gère des éléments tels que le regroupement de connexions, les sessions, les cookies, etc. sur plusieurs requêtes.

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

Ici, nous effectuons plusieurs requêtes en utilisant le même client, qui gère automatiquement la persistance des cookies.

Vous pouvez également configurer des options telles que les en-têtes, les proxys, l'authentification, etc. lors de la création du client :

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

Examinons maintenant les requêtes makings de manière asynchrone.

Requêtes asynchrones avec HTTPX

Pour effectuer des requêtes de manière asynchrone en Python, HTTPX fournit un AsyncClient:

import httpx

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

Nous utilisons async with pour initialiser le client, await sur la demande, et ferme automatiquement le client par la suite.

Pour récupérer plusieurs URL simultanément, nous pouvons utiliser 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() attend simultanément plusieurs coroutines et renvoie les résultats dans l'ordre des attendus.

Il existe également d'autres options comme asyncio.as_completed() pour les traiter au fur et à mesure qu'ils terminent :

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

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

Async IO permet de récupérer simultanément plusieurs pages à la fois, ce qui est utile pour accélérer le scraping.

Examinons ensuite la récupération des données des réponses HTML et JSON.

Supprimer les réponses HTML et JSON

Pour le scraping HTML, nous pouvons utiliser un analyseur comme Beautiful Soup pour extraire des données :

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

Ceci imprime le contenu de la table des matières de la page Wikipédia.

Pour les réponses JSON, HTTPX fournit un outil intégré .json() méthode:

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

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

La json= Le paramètre peut également être utilisé pour sérialiser les données JSON dans les requêtes.

Avec un analyseur, nous pouvons créer des scrapers pour extraire des données des API et des sites Web.

Gestion des problèmes et des erreurs

Lors du scraping, des problèmes tels que des erreurs de connexion, des délais d'attente, des limites de débit, etc. surviennent souvent.

HTTPX fournit des exceptions et des outils pour les gérer de manière appropriée.

Délais d'attente

Pour gérer les réponses lentes, vous pouvez spécifier un paramètre personnalisé timeout paramètre. La valeur par défaut est de 5 secondes.

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

Si ce chiffre est dépassé, un httpx.TimeoutException se produit:

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

Des délais d'attente plus longs peuvent être nécessaires pour certains sites ou pages.

Erreurs HTTP

Pour les erreurs HTTP comme 400, 500 etc., le response.raise_for_status() méthode peut être utilisée :

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

Cela déclenchera une exception sur tout code d'état 4xx ou 5xx.

Réessayer les demandes

Pour ajouter une logique de nouvelle tentative, des packages externes comme tenacity peut être utilisé:

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

Ici, nous réessayons jusqu'à 3 fois pour toute exception. Une logique de nouvelle tentative plus avancée peut également être définie.

Limites des demandes parallèles

Lorsque vous effectuez de nombreuses requêtes en parallèle, vous pouvez rencontrer des limites de connexion.

La limits Le paramètre peut être utilisé pour configurer des options telles que le nombre maximal de connexions :

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

Le réglage de ce paramètre en fonction du site cible peut aider à éviter les limites.

En résolvant ces problèmes courants, des grattoirs plus résilients peuvent être construits.

Meilleures pratiques de scraping

Voici quelques conseils pour créer des web scrapers efficaces avec HTTPX :

  • Utiliser un client HTTPX – Les clients offrent un regroupement de connexions, la persistance des cookies et d’autres avantages.

  • Grattez poliment – Limitez les taux de requêtes pour éviter de surcharger les serveurs. Utilisez des délais aléatoires et des limitations.

  • Gérer les erreurs – Utilisez les blocs try/sauf, les vérifications d’état et les nouvelles tentatives pour gérer les problèmes.

  • Utiliser les E/S asynchrones – Grattez les pages simultanément pour améliorer la vitesse. Mais limitez la simultanéité pour éviter les interdictions.

  • Randomiser les agents utilisateurs – Faites pivoter les chaînes d’agent utilisateur aléatoires pour paraître plus humaines.

  • Utiliser des procurations – Faites pivoter différents proxys/IP pour distribuer les demandes.

  • Mettre en cache et conserver les données – Enregistrez les données récupérées dans des fichiers/bases de données pour éviter de les regratter.

En suivant les meilleures pratiques comme celles-ci, des grattoirs plus robustes et plus faciles à entretenir peuvent être construits.

Techniques avancées de grattage

Examinons quelques capacités de scraping plus avancées de HTTPX.

Supprimer les pages d'authentification

Pour supprimer les pages authentifiées, HTTPX prend en charge plusieurs types d'authentification tels que l'authentification de base, Digest et Bearer :

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

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

Les informations d’authentification sont automatiquement conservées dans les demandes.

Gestion des cookies

La cookies Le paramètre peut être utilisé pour envoyer des cookies personnalisés :

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

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

Et les cookies définis par le serveur sont automatiquement conservés dans le client.

Réponses en continu

Pour les réponses volumineuses, vous pouvez les diffuser de manière incrémentielle en itérant l'objet de réponse :

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

Cela évite d'avoir à charger l'intégralité de la réponse en mémoire.

Support proxy

Pour acheminer les requêtes via un serveur proxy, le proxies Le paramètre peut être utilisé :

proxy = ‘http://192.168.0.1:8888‘ 

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

La rotation de différents proxys permet de répartir les requêtes provenant de différentes adresses IP.

En-têtes personnalisés

Vous pouvez usurper ou randomiser les en-têtes de requête comme les agents utilisateurs :

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

Cela imite les en-têtes d'un vrai navigateur.

Grâce à ces fonctionnalités plus avancées, des scrapers robustes peuvent être créés à l'aide de HTTPX et Python.

Exemples de grattoirs

Examinons maintenant quelques exemples de scrapers construits avec HTTPX.

Grattoir d'API Reddit

Voici un scraper de base pour 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})")

Cela récupère les données sur les principales publications du subreddit Python. L'API renvoie du JSON que nous pouvons analyser.

Nous pourrions étendre ce scraper pour extraire les données de plusieurs subreddits, stocker les résultats dans une base de données, etc.

Grattoir d'articles de presse

Voici un simple grattoir d'actualités qui extrait les articles d'un 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() 

Cela trouve tout .article éléments, extrait les champs de titre et de contenu et imprime les articles.

Encore une fois, cela pourrait être étendu pour extraire des champs supplémentaires, analyser des dates, stocker dans une base de données, etc.

Résultats de la recherche Grattoir

Et voici un exemple de scraper pour les résultats de recherche 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()

Cela recherche sur Google une requête donnée, analyse les liens/titres des résultats et les imprime.

Encore une fois, de nombreuses améliorations pourraient être apportées, comme l'extraction du nombre de résultats de recherche, des champs supplémentaires, le scraping des pages de résultats, la détection des captchas, etc.

Ces exemples illustrent des modèles de scraping courants avec HTTPX. Les mêmes techniques peuvent être appliquées pour créer des scrapers pour de nombreux sites Web et API.

Résumé

Pour résumer, HTTPX fournit un puissant client HTTP pour créer des web scrapers Python. Voici quelques points clés :

  • HTTPX dispose d'une API simple de type requêtes pour effectuer des requêtes.

  • La prise en charge asynchrone permet de faire des demandes simultanément.

  • Gestion robuste des erreurs avec délais d'attente, tentatives et vérifications d'état.

  • Grattez facilement les pages HTML avec les API Beautiful Soup et JSON.

  • Les clients persistants assurent le regroupement de connexions, les sessions et la gestion des cookies.

  • Des techniques avancées telles que les proxys, les en-têtes et l'authentification permettent des scrapers sophistiqués.

  • Suivez les meilleures pratiques telles que l’utilisation de la limitation, des retards aléatoires et des agents utilisateurs.

HTTPX facilite le démarrage du scraping avec Python. Grâce à une gestion robuste des erreurs et à une concurrence asynchrone, des scrapers évolutifs peuvent être développés.

Essayez HTTPX sur votre prochain projet de web scraping Python !

Mots clés:

Prendre part à la conversation

Votre adresse email n'apparaitra pas. Les champs obligatoires sont marqués *