Le scraping de données médicales est une tâche qui nécessite une approche particulière dans le choix des proxies. Les portails médicaux, les bases de données d'essais cliniques et les ressources pharmaceutiques utilisent des systèmes de protection avancés contre la collecte automatisée de données. Dans cet article, nous allons examiner comment configurer correctement des proxies pour un scraping sécurisé des informations médicales, éviter les blocages et collecter efficacement les données nécessaires.
Pourquoi les sites médicaux bloquent le scraping
Les portails médicaux et les bases de données sont particulièrement sensibles à la collecte automatisée d'informations pour plusieurs raisons. Tout d'abord, beaucoup d'entre eux fonctionnent sur une base commerciale et vendent l'accès aux données via des abonnements payants. Le scraping automatique peut violer les conditions d'utilisation et les accords de licence.
Deuxièmement, les données médicales contiennent souvent des informations confidentielles protégées par la loi (HIPAA aux États-Unis, RGPD en Europe). Les propriétaires des ressources doivent contrôler l'accès à ces données et prévenir leur diffusion non autorisée. C'est pourquoi ils utilisent des systèmes de protection avancés :
- Rate limiting — limitation du nombre de requêtes depuis une adresse IP dans un délai donné (généralement 10-50 requêtes par minute)
- Fingerprinting — analyse des caractéristiques du navigateur, des en-têtes HTTP, de l'ordre de chargement des ressources
- CAPTCHA — systèmes comme reCAPTCHA v3 qui se déclenchent lors d'une activité suspecte
- Blocages IP — blocage temporaire ou permanent des adresses IP des centres de données
- Cloudflare et similaires — protection contre les bots au niveau du CDN
La troisième raison est la charge sur les serveurs. Les bases de données médicales contiennent souvent des millions d'enregistrements, et un scraping massif peut créer une charge significative sur l'infrastructure. C'est pourquoi les administrateurs luttent activement contre la collecte automatisée de données, en surveillant les modèles de comportement caractéristiques des bots : intervalles identiques entre les requêtes, parcours linéaire des pages, absence de JavaScript et de cookies.
Important : Avant de commencer à scraper des données médicales, assurez-vous d'étudier les conditions d'utilisation du site et la législation applicable. Certaines données peuvent être protégées par des droits d'auteur ou contenir des informations personnelles sur les patients. Assurez-vous que votre activité est légale et ne viole pas les droits des tiers.
Quel type de proxy choisir pour les données médicales
Le choix du type de proxy est crucial pour un scraping réussi des données médicales. Différentes sources nécessitent des approches différentes. Examinons les principaux types de proxies et leur applicabilité :
| Type de proxy | Avantages | Inconvénients | Quand utiliser |
|---|---|---|---|
| Proxies de centre de données | Haute vitesse (100+ Mbit/s), faible coût, connexion stable | Facilement détectables, souvent bloqués sur des sites protégés | Bases de données ouvertes sans protection stricte (PubMed, OMS) |
| Proxies résidentiels | IP réelles d'utilisateurs domestiques, faible risque de blocage, passent Cloudflare | Coût plus élevé, vitesse variable, peuvent être instables | Bases commerciales protégées (Elsevier, Springer), sites avec Cloudflare |
| Proxies mobiles | Confiance maximale (IP des opérateurs mobiles), pratiquement pas bloqués | Les plus chers, géographie limitée, peuvent être plus lents | Ressources particulièrement protégées, quand les proxies résidentiels ne fonctionnent pas |
| Proxies ISP | Vitesse des centres de données + confiance des résidents, IP statiques | Coût moyen, disponibilité limitée | Scraping à long terme depuis une IP, quand la stabilité est nécessaire |
Pour la plupart des tâches de scraping de données médicales, il est recommandé d'utiliser des proxies résidentiels. Ils offrent le meilleur équilibre entre coût et efficacité. Les proxies de centre de données ne conviennent qu'aux sources ouvertes sans protection. Les proxies mobiles doivent être utilisés en dernier recours, lorsque les autres types ne fonctionnent pas.
Recommandations pour des sources spécifiques
- PubMed, PubMed Central — les proxies de centre de données suffisent, mais avec une limitation de vitesse à 3 requêtes par seconde
- ClinicalTrials.gov — proxies de centre de données, il existe une API officielle
- Elsevier, Springer, Wiley — les proxies résidentiels sont obligatoires, utilisent un fingerprinting avancé
- DrugBank, RxList — proxies résidentiels, protection active contre le scraping
- Bases de données FDA, EMA — les proxies de centre de données conviennent, mais avec une vitesse de scraping lente
Principales sources de données médicales et leur protection
Les données médicales sont réparties sur de nombreuses sources, chacune ayant sa propre spécificité et niveau de protection. Comprendre ces particularités aidera à configurer correctement la stratégie de scraping.
Bases de données publiques gouvernementales
PubMed/PubMed Central — la plus grande base de publications médicales, contenant plus de 35 millions d'enregistrements. La Bibliothèque médicale nationale des États-Unis (NLM) fournit une API officielle E-utilities, qui est le moyen préféré d'accéder aux données. Le scraping direct de l'interface web est possible, mais limité à 3 requêtes par seconde depuis une seule IP. Dépasser cette limite entraîne un blocage temporaire de 24 heures.
ClinicalTrials.gov — base de données des essais cliniques, contenant des informations sur plus de 400 000 études dans 220 pays. Elle fournit également une API pour l'accès programmatique. L'interface web est protégée par un rate limiting — maximum 100 requêtes en 5 minutes depuis une seule IP. Une protection de base contre les bots est utilisée, mais sans Cloudflare.
Base de données des médicaments de la FDA — base de données des médicaments approuvés par la FDA. Accès ouvert via l'interface web et l'API openFDA. Limitations : 240 requêtes par minute pour les utilisateurs anonymes, 1000 requêtes par minute avec une clé API. Les blocages sont rares, mais peuvent survenir lors d'un scraping agressif.
Éditeurs scientifiques commerciaux
Elsevier (ScienceDirect) — l'un des plus grands éditeurs de littérature scientifique. Utilise une protection multi-niveaux : Cloudflare, fingerprinting du navigateur, analyse du comportement utilisateur. Détecte les modèles de téléchargement automatique : accès séquentiel aux articles, absence de JavaScript, User-Agent atypiques. Lors de la détection du scraping, bloque l'IP au niveau du compte et peut bloquer l'ensemble de l'institution. L'utilisation de proxies résidentiels avec rotation et émulation complète du navigateur est obligatoire.
Springer Nature — protection similaire, surveille également la vitesse de défilement des pages et les mouvements de la souris. Utilise l'apprentissage automatique pour détecter les bots. Il est recommandé de scraper pas plus de 10-15 articles par heure depuis une seule IP, avec des délais randomisés entre les requêtes.
Wiley Online Library — protection moins agressive, mais nécessite tout de même l'utilisation de proxies. Autorise environ 50 requêtes par heure depuis une seule IP sans blocage. Utilise des cookies de session pour suivre l'activité.
Bases de données pharmaceutiques
DrugBank — base de données complète des médicaments. La version gratuite est limitée à l'interface web, la version commerciale fournit une API et des exports de données. La version web est protégée par Cloudflare et un rate limiting — maximum 20 requêtes par minute. Détecte l'automatisation par l'absence de cookies et de JavaScript.
RxList, Drugs.com — annuaires populaires de médicaments pour les consommateurs. Utilisent Cloudflare et luttent activement contre le scraping. Bloquent les IP des centres de données presque instantanément. Des proxies résidentiels et une vitesse de scraping lente (5-10 pages par minute) sont nécessaires.
Configuration de la rotation IP pour un scraping à long terme
Une bonne rotation des adresses IP est un facteur clé pour un scraping réussi des données médicales. Il existe deux approches principales : la rotation au niveau des requêtes et la rotation par temps.
Rotation au niveau des requêtes
Avec cette approche, chaque requête est envoyée via une nouvelle adresse IP. Cela réduit au maximum le risque de blocage, mais peut poser des problèmes avec les sites qui suivent les sessions via des cookies. Convient pour le scraping de listes et de catalogues où il n'est pas nécessaire de maintenir l'état de la session.
La plupart des fournisseurs de proxies résidentiels offrent une rotation automatique via un point de terminaison spécial. Par exemple, lors de l'utilisation d'un point de terminaison de proxy rotatif, chaque nouvelle connexion TCP obtient une nouvelle IP. Cela fonctionne automatiquement avec des bibliothèques comme requests en Python, car par défaut, une nouvelle connexion est créée pour chaque requête.
Rotation par temps (sessions collantes)
Les sessions collantes permettent d'utiliser une adresse IP pendant une période déterminée (généralement 5-30 minutes), après quoi un changement automatique se produit. Cela est utile pour les sites nécessitant une authentification ou suivant l'état de la session via des cookies. Vous pouvez scraper plusieurs pages depuis une IP, imitant le comportement d'un utilisateur réel, puis l'IP change automatiquement.
Pour les sites médicaux, il est recommandé d'utiliser des sessions collantes d'une durée de 10-15 minutes. Pendant ce temps, vous pouvez scraper 10-20 pages (selon les délais), après quoi l'IP change et vous commencez une "nouvelle session". Cela semble naturel et réduit le risque de détection.
Taille du pool d'adresses IP
Pour un scraping à long terme, la taille du pool d'adresses IP disponibles est importante. Si vous utilisez le même ensemble de 100 IP pendant une semaine, le site peut remarquer un modèle et bloquer toutes ces adresses. Les proxies résidentiels offrent généralement accès à des millions d'IP, ce qui exclut pratiquement la réutilisation de la même adresse.
Lors de l'utilisation de proxies de centre de données, il est recommandé d'avoir un pool d'au moins 500-1000 IP pour un scraping de volume moyen (10 000-50 000 pages par mois). Pour un scraping à grande échelle (des centaines de milliers de pages), il est préférable d'utiliser des proxies résidentiels avec leurs énormes pools d'IP.
Conseils de rotation pour différentes sources :
- PubMed — rotation non obligatoire, 1 IP suffit en respectant le rate limit
- Éditeurs commerciaux — sessions collantes de 10-15 minutes, nouvelle IP toutes les 15-20 pages
- Bases de données pharmaceutiques — rotation à chaque requête ou sessions collantes de 5 minutes
- Sites avec Cloudflare — sessions collantes obligatoires, rotation au niveau des requêtes ne fonctionne pas
Exemples de code en Python pour le scraping avec des proxies
Examinons des exemples pratiques de configuration de proxies pour le scraping de données médicales en utilisant des bibliothèques Python populaires. Commençons par un exemple de base et compliquons-le progressivement.
Configuration de base avec la bibliothèque requests
import requests
from time import sleep
import random
# Configuration du proxy (remplacez par vos données)
PROXY_HOST = "proxy.example.com"
PROXY_PORT = "8080"
PROXY_USER = "username"
PROXY_PASS = "password"
proxies = {
'http': f'http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}',
'https': f'http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}'
}
# En-têtes pour imiter un vrai navigateur
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'fr-FR,fr;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'DNT': '1',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1'
}
# Exemple de requête à PubMed
url = "https://pubmed.ncbi.nlm.nih.gov/?term=diabetes"
try:
response = requests.get(url, proxies=proxies, headers=headers, timeout=30)
print(f"Code de statut : {response.status_code}")
print(f"Longueur du contenu : {len(response.content)}")
# Ajout d'un délai entre les requêtes (obligatoire pour PubMed)
sleep(random.uniform(1.0, 3.0))
except requests.exceptions.RequestException as e:
print(f"Erreur : {e}")
Configuration avancée avec rotation et logique de répétition
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from time import sleep
import random
class ProxyRotator:
def __init__(self, proxy_list):
"""
proxy_list: liste de dictionnaires avec des proxies
[{'http': 'http://user:pass@host:port', 'https': '...'}, ...]
"""
self.proxy_list = proxy_list
self.current_index = 0
def get_next_proxy(self):
"""Obtenir le prochain proxy de la liste"""
proxy = self.proxy_list[self.current_index]
self.current_index = (self.current_index + 1) % len(self.proxy_list)
return proxy
def create_session_with_retries():
"""Créer une session avec des répétitions automatiques en cas d'erreurs"""
session = requests.Session()
# Configuration des répétitions automatiques
retry_strategy = Retry(
total=3, # maximum 3 tentatives
backoff_factor=1, # délai entre les tentatives : 1, 2, 4 secondes
status_forcelist=[429, 500, 502, 503, 504], # codes pour répétition
allowed_methods=["GET", "POST"]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)
return session
def scrape_with_rotation(urls, proxy_rotator):
"""Scraping d'une liste d'URL avec rotation des proxies"""
session = create_session_with_retries()
results = []
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'fr-FR,fr;q=0.9',
}
for url in urls:
# Obtenir un nouveau proxy pour chaque requête
proxy = proxy_rotator.get_next_proxy()
try:
response = session.get(
url,
proxies=proxy,
headers=headers,
timeout=30
)
if response.status_code == 200:
results.append({
'url': url,
'status': 'success',
'content_length': len(response.content)
})
print(f"✓ Succès : {url}")
else:
results.append({
'url': url,
'status': 'failed',
'error': f"Code de statut : {response.status_code}"
})
print(f"✗ Échec : {url} (Statut : {response.status_code})")
except requests.exceptions.RequestException as e:
results.append({
'url': url,
'status': 'error',
'error': str(e)
})
print(f"✗ Erreur : {url} ({e})")
# Délai aléatoire entre les requêtes (important !)
sleep(random.uniform(2.0, 5.0))
return results
# Exemple d'utilisation
proxy_list = [
{
'http': 'http://user1:pass1@proxy1.example.com:8080',
'https': 'http://user1:pass1@proxy1.example.com:8080'
},
{
'http': 'http://user2:pass2@proxy2.example.com:8080',
'https': 'http://user2:pass2@proxy2.example.com:8080'
}
]
rotator = ProxyRotator(proxy_list)
urls_to_scrape = [
"https://pubmed.ncbi.nlm.nih.gov/?term=diabetes",
"https://pubmed.ncbi.nlm.nih.gov/?term=cancer",
"https://pubmed.ncbi.nlm.nih.gov/?term=covid"
]
results = scrape_with_rotation(urls_to_scrape, rotator)
Utilisation de Selenium pour les sites avec JavaScript
De nombreux sites médicaux modernes utilisent JavaScript pour charger du contenu. Dans de tels cas, un navigateur sans interface graphique est nécessaire :
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
def create_proxy_driver(proxy_host, proxy_port, proxy_user, proxy_pass):
"""Créer un Chrome WebDriver avec un proxy"""
chrome_options = Options()
# Mode sans tête (sans interface graphique)
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
# Configuration du proxy
chrome_options.add_argument(f'--proxy-server=http://{proxy_host}:{proxy_port}')
# Désactiver l'automatisation (important pour contourner la détection)
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
# User-Agent
chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
driver = webdriver.Chrome(options=chrome_options)
# Pour les proxies avec authentification, il faut utiliser une extension
# ou configurer via capabilities (option plus complexe)
return driver
def scrape_with_selenium(url, driver):
"""Scraping d'une page en attendant le chargement de JavaScript"""
driver.get(url)
# Attendre le chargement de l'élément (par exemple, les résultats de recherche)
try:
wait = WebDriverWait(driver, 10)
results = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "results-article"))
)
# Extraction des données
articles = driver.find_elements(By.CLASS_NAME, "results-article")
data = []
for article in articles:
try:
title = article.find_element(By.CLASS_NAME, "docsum-title").text
authors = article.find_element(By.CLASS_NAME, "docsum-authors").text
data.append({
'title': title,
'authors': authors
})
except:
continue
return data
except Exception as e:
print(f"Erreur en attendant les éléments : {e}")
return []
# Exemple d'utilisation
proxy_host = "proxy.example.com"
proxy_port = "8080"
proxy_user = "username"
proxy_pass = "password"
driver = create_proxy_driver(proxy_host, proxy_port, proxy_user, proxy_pass)
try:
url = "https://pubmed.ncbi.nlm.nih.gov/?term=diabetes"
results = scrape_with_selenium(url, driver)
for result in results:
print(f"Titre : {result['title']}")
print(f"Auteurs : {result['authors']}\n")
finally:
driver.quit()
Contrôle de la vitesse des requêtes et contournement du rate limiting
Le rate limiting est l'une des principales protections des sites médicaux contre le scraping. Une configuration correcte de la vitesse des requêtes est cruciale pour un scraping à long terme sans blocages.
Détermination d'une vitesse sécurisée
La première étape consiste à déterminer les limites d'un site spécifique. Cela peut être fait expérimentalement, en augmentant progressivement la vitesse des requêtes jusqu'à l'apparition d'erreurs 429 (Trop de requêtes) ou de blocages. Pour la plupart des sites médicaux, les valeurs sécurisées sont :
- PubMed — maximum 3 requêtes par seconde (recommandation officielle)
- ClinicalTrials.gov — 20 requêtes par minute sont sécurisées, jusqu'à 100 en 5 minutes sont acceptables
- Éditeurs commerciaux — 10-15 requêtes par heure depuis une seule IP
- Bases de données pharmaceutiques — 5-10 requêtes par minute
Implémentation d'un rate limiter en Python
import time
from collections import deque
class RateLimiter:
def __init__(self, max_calls, period):
"""
max_calls: nombre maximum d'appels
period: période de temps en secondes
Par exemple : RateLimiter(3, 1) = 3 requêtes par seconde
"""
self.max_calls = max_calls
self.period = period
self.calls = deque()
def __call__(self, func):
"""Décorateur pour limiter la vitesse d'appel de la fonction"""
def wrapper(*args, **kwargs):
now = time.time()
# Supprimer les anciens appels en dehors de la période
while self.calls and self.calls[0] < now - self.period:
self.calls.popleft()
# Si la limite est atteinte, attendre
if len(self.calls) >= self.max_calls:
sleep_time = self.period - (now - self.calls[0])
if sleep_time > 0:
print(f"Limite de vitesse atteinte, attente de {sleep_time:.2f}s")
time.sleep(sleep_time)
# Nettoyer après l'attente
self.calls.clear()
# Enregistrer le temps d'appel
self.calls.append(time.time())
# Exécuter la fonction
return func(*args, **kwargs)
return wrapper
# Exemple d'utilisation
@RateLimiter(max_calls=3, period=1) # 3 requêtes par seconde
def fetch_pubmed_page(url):
response = requests.get(url, headers=headers, proxies=proxies)
return response
# Maintenant, la fonction respecte automatiquement la limite de vitesse
for i in range(10):
result = fetch_pubmed_page(f"https://pubmed.ncbi.nlm.nih.gov/?term=test&page={i}")
print(f"Page {i} récupérée")
Rate limiting adaptatif
Une approche plus avancée consiste à modifier la vitesse en fonction des réponses du serveur. Si nous recevons des erreurs 429 ou 503, nous réduisons automatiquement la vitesse :
import time
import random
class AdaptiveRateLimiter:
def __init__(self, initial_delay=1.0, max_delay=60.0):
self.current_delay = initial_delay
self.initial_delay = initial_delay
self.max_delay = max_delay
self.success_count = 0
def wait(self):
"""Attendre avant la prochaine requête"""
# Ajouter de l'aléatoire pour plus de naturel
actual_delay = self.current_delay * random.uniform(0.8, 1.2)
time.sleep(actual_delay)
def on_success(self):
"""Appelé lors d'une requête réussie"""
self.success_count += 1
# Après 10 requêtes réussies, nous accélérons un peu
if self.success_count >= 10:
self.current_delay = max(
self.initial_delay,
self.current_delay * 0.9
)
self.success_count = 0
def on_rate_limit(self):
"""Appelé lors de la réception d'erreurs 429 ou similaires"""
# Doubler le délai, mais pas plus que le maximum
self.current_delay = min(
self.current_delay * 2,
self.max_delay
)
self.success_count = 0
print(f"Limite de vitesse atteinte ! Augmentation du délai à {self.current_delay:.2f}s")
def on_error(self):
"""Appelé lors d'autres erreurs"""
# Augmenter légèrement le délai
self.current_delay = min(
self.current_delay * 1.5,
self.max_delay
)
self.success_count = 0
# Exemple d'utilisation
limiter = AdaptiveRateLimiter(initial_delay=2.0, max_delay=30.0)
for url in urls_to_scrape:
limiter.wait()
try:
response = requests.get(url, proxies=proxies, headers=headers)
if response.status_code == 200:
limiter.on_success()
# Traitement des données
elif response.status_code == 429:
limiter.on_rate_limit()
# Répéter plus tard
else:
limiter.on_error()
except requests.exceptions.RequestException:
limiter.on_error()
En-têtes corrects et User-Agent pour les sites médicaux
Les sites médicaux analysent les en-têtes HTTP pour détecter les bots. Des en-têtes incorrects ou manquants sont une cause fréquente de blocages même avec des proxies de qualité.
En-têtes obligatoires
L'ensemble minimal d'en-têtes qui doit être présent dans chaque requête :
headers = {
# User-Agent — un navigateur actuel est obligatoire
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
# Accept — types de contenu acceptés par le navigateur
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
# Accept-Language — langue de l'utilisateur
'Accept-Language': 'fr-FR,fr;q=0.9',
# Accept-Encoding — support de la compression
'Accept-Encoding': 'gzip, deflate, br',
# Connection — maintien de la connexion
'Connection': 'keep-alive',
# Upgrade-Insecure-Requests — passage automatique à HTTPS
'Upgrade-Insecure-Requests': '1',
# DNT — Do Not Track (optionnel, mais ajoute du réalisme)
'DNT': '1',
# En-têtes Sec-Fetch-* (importants pour les navigateurs modernes)
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
# Cache-Control
'Cache-Control': 'max-age=0'
}
Rotation du User-Agent
L'utilisation du même User-Agent peut être suspecte. Il est recommandé de faire une rotation entre plusieurs navigateurs actuels :
import random
USER_AGENTS = [
# Chrome sur Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
# Chrome sur Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
# Firefox sur Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
# Firefox sur Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0',
# Safari sur Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15',
# Edge sur Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0'
]
def get_random_headers():
"""Obtenir des en-têtes avec un User-Agent aléatoire"""
return {
'User-Agent': random.choice(USER_AGENTS),
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'fr-FR,fr;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'DNT': '1'
}
# Utilisation
for url in urls:
headers = get_random_headers()
response = requests.get(url, headers=headers, proxies=proxies)
Referer et Origin pour les formulaires
Lors de l'utilisation de formulaires de recherche ou de l'envoi de requêtes POST, ajoutez toujours les en-têtes Referer et Origin :
# Pour les requêtes POST au formulaire de recherche
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'fr-FR,fr;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': 'https://example.com',
'Referer': 'https://example.com/search',
'Connection': 'keep-alive'
}
# Requête POST avec les données du formulaire
data = {
'query': 'diabetes',
'page': '1'
}
response = requests.post(
'https://example.com/search',
headers=headers,
data=data,
proxies=proxies
)
Problèmes typiques et leurs solutions
Lors du scraping de données médicales, des problèmes spécifiques peuvent survenir. Examinons les plus fréquents et comment les résoudre.
Problème : Cloudflare bloque toutes les requêtes
Symptômes : Vous recevez une page avec le texte "Vérification de votre navigateur" ou une erreur 403 Forbidden mentionnant Cloudflare.
Solution :
- Utilisez des proxies résidentiels au lieu de centres de données — Cloudflare bloque par défaut les IP des centres de données
- Passez à Selenium ou Puppeteer — les navigateurs sans tête passent mieux les vérifications de Cloudflare
- Utilisez la bibliothèque cloudscraper pour Python — elle contourne automatiquement la protection de base de Cloudflare
- Activez les cookies et JavaScript — Cloudflare vérifie leur présence
- Ajoutez du fingerprinting TLS — utilisez curl_cffi pour imiter un vrai navigateur au niveau TLS
Problème : J'obtiens une erreur 429 Trop de requêtes
Symptômes : Après plusieurs requêtes réussies, le serveur commence à renvoyer 429.
Solution :
- Augmentez le délai entre les requêtes — essayez de commencer avec 3-5 secondes
- Activez la rotation IP — chaque requête via une nouvelle IP supprime le rate limiting
- Vérifiez l'en-tête Retry-After dans la réponse 429 — il indique combien de secondes il faut attendre
- Utilisez un délai exponentiel lors des répétitions — 1s, 2s, 4s, 8s, etc.
Problème : Les proxies fonctionnent lentement ou tombent souvent
Symptômes : Erreurs de délai d'attente, chargement très long des pages, interruptions de connexion.
Solution :
- Augmentez le délai d'attente dans les requêtes à 30-60 secondes — les proxies résidentiels peuvent être plus lents
- Utilisez des proxies géographiquement proches — si vous scrapez un site européen, utilisez des IP européennes
- Vérifiez la qualité du fournisseur de proxies — les proxies bon marché sont souvent instables
- Ajoutez une logique de répétition — répétez automatiquement la requête en cas d'erreur de connexion
- Utilisez le pooling de connexions — réutilisez les connexions TCP via requests.Session()
Problème : Le site nécessite une authentification ou un abonnement
Symptômes : L'accès aux textes complets des articles est limité, une connexion est requise.
Solution :
- Utilisez l'accès institutionnel — de nombreuses universités et hôpitaux ont des abonnements
- Vérifiez la disponibilité de versions en accès libre — de nombreux articles sont disponibles gratuitement via des dépôts
- Utilisez une API au lieu du scraping — certains éditeurs fournissent des API pour les chercheurs
- Scrapez uniquement les métadonnées (titres, auteurs, résumés) — elles sont généralement accessibles gratuitement
Problème : Le contenu JavaScript ne se charge pas
Symptômes : Aucune donnée nécessaire dans le HTML, seuls des spinners de chargement ou des conteneurs vides sont visibles.
Solution :
- Passez à Selenium/Puppeteer — ils exécutent JavaScript
- Trouvez un point de terminaison API — ouvrez DevTools dans le navigateur, onglet Réseau, et trouvez les requêtes XHR avec des données
- Utilisez requests-html — bibliothèque avec...