Il parsing dei dati medici è un compito che richiede un approccio particolare nella scelta dei proxy. I portali medici, i database di studi clinici e le risorse farmaceutiche utilizzano sistemi avanzati di protezione contro la raccolta automatizzata di dati. In questo articolo esamineremo come configurare correttamente i proxy per un parsing sicuro delle informazioni mediche, evitare i blocchi e raccogliere i dati necessari in modo efficace.
Perché i siti medici bloccano il parsing
I portali medici e i database sono particolarmente sensibili alla raccolta automatizzata di informazioni per diverse ragioni. In primo luogo, molti di essi operano su base commerciale e vendono l'accesso ai dati tramite abbonamenti a pagamento. Il parsing automatico può violare i termini di utilizzo e i contratti di licenza.
In secondo luogo, i dati medici contengono spesso informazioni riservate protette dalla legge (HIPAA negli Stati Uniti, GDPR in Europa). I proprietari delle risorse sono obbligati a controllare l'accesso a tali dati e prevenire la loro diffusione non autorizzata. Pertanto, utilizzano sistemi di protezione avanzati:
- Rate limiting — limitazione del numero di richieste da un singolo indirizzo IP in un'unità di tempo (di solito 10-50 richieste al minuto)
- Fingerprinting — analisi delle caratteristiche del browser, delle intestazioni HTTP, dell'ordine di caricamento delle risorse
- CAPTCHA — sistemi come reCAPTCHA v3, che si attivano in caso di attività sospette
- Blocco IP — blocco temporaneo o permanente degli indirizzi IP dei data center
- Cloudflare e simili — protezione contro i bot a livello CDN
La terza ragione è il carico sui server. I database medici contengono spesso milioni di record, e il parsing di massa può creare un carico significativo sull'infrastruttura. Pertanto, gli amministratori combattono attivamente la raccolta automatizzata di dati, monitorando i modelli di comportamento tipici dei bot: intervalli identici tra le richieste, navigazione lineare delle pagine, assenza di JavaScript e cookie.
Importante: Prima di iniziare il parsing dei dati medici, assicurati di studiare i termini di utilizzo del sito e la legislazione applicabile. Alcuni dati possono essere protetti da copyright o contenere informazioni personali sui pazienti. Assicurati che la tua attività sia legale e non violi i diritti di terzi.
Quale tipo di proxy scegliere per i dati medici
La scelta del tipo di proxy è fondamentale per un parsing di successo dei dati medici. Diverse fonti richiedono approcci diversi. Esaminiamo i principali tipi di proxy e la loro applicabilità:
| Tipo di proxy | Vantaggi | Svantaggi | Quando utilizzare |
|---|---|---|---|
| Proxy dei data center | Alta velocità (100+ Mbps), basso costo, connessione stabile | Facilmente rilevabili, spesso bloccati su siti protetti | Database aperti senza protezione rigorosa (PubMed, WHO) |
| Proxy residenziali | IP reali di utenti domestici, basso rischio di blocco, superano Cloudflare | Costo più elevato, velocità variabile, possono essere instabili | Database commerciali protetti (Elsevier, Springer), siti con Cloudflare |
| Proxy mobili | Massimo livello di fiducia (IP degli operatori mobili), praticamente non bloccati | I più costosi, geografia limitata, possono essere più lenti | Risorse particolarmente protette, quando i proxy residenziali non funzionano |
| Proxy ISP | Velocità dei data center + fiducia dei residenziali, IP statici | Costo medio, disponibilità limitata | Parsing a lungo termine da un IP, quando è necessaria stabilità |
Per la maggior parte delle attività di parsing dei dati medici, si raccomanda di utilizzare proxy residenziali. Offrono un equilibrio ottimale tra costo ed efficienza. I proxy dei data center sono adatti solo per fonti aperte senza protezione. I proxy mobili dovrebbero essere utilizzati solo in casi estremi, quando altri tipi non funzionano.
Raccomandazioni per la scelta per fonti specifiche
- PubMed, PubMed Central — i proxy dei data center sono sufficienti, ma con limitazione della velocità a 3 richieste al secondo
- ClinicalTrials.gov — proxy dei data center, c'è un'API ufficiale
- Elsevier, Springer, Wiley — i proxy residenziali sono obbligatori, utilizzano fingerprinting avanzato
- DrugBank, RxList — proxy residenziali, protezione attiva contro il parsing
- Database FDA, EMA — i proxy dei data center sono adatti, ma con velocità di parsing lenta
Principali fonti di dati medici e la loro protezione
I dati medici sono distribuiti su molte fonti, ciascuna con la propria specificità e livello di protezione. Comprendere queste caratteristiche aiuterà a configurare correttamente la strategia di parsing.
Database pubblici governativi
PubMed/PubMed Central — il più grande database di pubblicazioni mediche, contiene oltre 35 milioni di record. La Biblioteca Nazionale di Medicina degli Stati Uniti (NLM) fornisce un'API ufficiale E-utilities, che è il modo preferito per accedere ai dati. Il parsing diretto dell'interfaccia web è possibile, ma limitato a 3 richieste al secondo da un singolo IP. Superare il limite porta a un blocco temporaneo di 24 ore.
ClinicalTrials.gov — database di studi clinici, contiene informazioni su oltre 400.000 studi in 220 paesi. Fornisce anche un'API per l'accesso programmato. L'interfaccia web è protetta da rate limiting — massimo 100 richieste in 5 minuti da un singolo IP. Utilizza una protezione di base contro i bot, ma senza Cloudflare.
FDA Drugs Database — database dei farmaci approvati dalla FDA. Accesso aperto tramite interfaccia web e API openFDA. Limitazioni: 240 richieste al minuto per utenti anonimi, 1000 richieste al minuto con chiave API. I blocchi sono rari, ma possibili con un parsing aggressivo.
Editori scientifici commerciali
Elsevier (ScienceDirect) — uno dei maggiori editori di letteratura scientifica. Utilizza una protezione multilivello: Cloudflare, fingerprinting del browser, analisi del comportamento dell'utente. Rileva modelli di download automatico: accesso sequenziale agli articoli, assenza di JavaScript, User-Agent non tipici. Quando viene rilevato il parsing, blocca l'IP a livello di account e può bloccare l'intero istituto. È obbligatorio utilizzare proxy residenziali con rotazione e completa emulazione del browser.
Springer Nature — protezione simile, monitora anche la velocità di scorrimento delle pagine e il movimento del mouse. Utilizza il machine learning per la rilevazione dei bot. Si raccomanda di eseguire il parsing di non più di 10-15 articoli all'ora da un singolo IP, con ritardi randomizzati tra le richieste.
Wiley Online Library — protezione meno aggressiva, ma richiede comunque l'uso di proxy. Consente circa 50 richieste all'ora da un singolo IP senza blocco. Utilizza cookie di sessione per monitorare l'attività.
Database farmaceutici
DrugBank — database completo di farmaci. La versione gratuita è limitata all'interfaccia web, mentre la versione commerciale fornisce API e download di dati. La versione web è protetta da Cloudflare e rate limiting — massimo 20 richieste al minuto. Rileva l'automazione per assenza di cookie e JavaScript.
RxList, Drugs.com — guide popolari sui farmaci per i consumatori. Utilizzano Cloudflare e combattono attivamente il parsing. Bloccano gli IP dei data center praticamente istantaneamente. Sono necessari proxy residenziali e una velocità di parsing lenta (5-10 pagine al minuto).
Configurazione della rotazione IP per il parsing a lungo termine
La corretta rotazione degli indirizzi IP è un fattore chiave per il successo del parsing dei dati medici. Ci sono due approcci principali: rotazione a livello di richieste e rotazione temporale.
Rotazione a livello di richieste
Con questo approccio, ogni richiesta viene inviata tramite un nuovo indirizzo IP. Questo riduce al minimo il rischio di blocco, ma può causare problemi con i siti che monitorano le sessioni tramite cookie. È adatto per il parsing di elenchi e cataloghi, dove non è necessario mantenere lo stato della sessione.
La maggior parte dei fornitori di proxy residenziali offre rotazione automatica tramite un endpoint speciale. Ad esempio, utilizzando un endpoint di proxy rotante, ogni nuova connessione TCP riceve un nuovo IP. Questo funziona automaticamente con librerie come requests in Python, poiché per impostazione predefinita viene creata una nuova connessione per ogni richiesta.
Rotazione temporale (sticky sessions)
Le sticky sessions consentono di utilizzare un indirizzo IP per un periodo di tempo specifico (di solito 5-30 minuti), dopo di che avviene il cambio automatico. Questo è utile per i siti che richiedono autenticazione o monitorano lo stato della sessione tramite cookie. Puoi eseguire il parsing di più pagine da un singolo IP, imitando il comportamento di un utente reale, e poi l'IP cambia automaticamente.
Per i siti medici, si raccomanda di utilizzare sticky sessions della durata di 10-15 minuti. Durante questo tempo, puoi eseguire il parsing di 10-20 pagine (a seconda dei ritardi), dopo di che l'IP cambia e inizi una "nuova sessione". Questo appare naturale e riduce il rischio di rilevamento.
Dimensione del pool di indirizzi IP
Per il parsing a lungo termine, è importante la dimensione del pool di indirizzi IP disponibili. Se utilizzi lo stesso insieme di 100 IP per una settimana, il sito potrebbe notare un modello e bloccare tutti questi indirizzi. I proxy residenziali di solito forniscono accesso a milioni di IP, il che praticamente esclude il riutilizzo dello stesso indirizzo.
Quando si utilizzano proxy dei data center, si consiglia di avere un pool di almeno 500-1000 IP per il parsing di un volume medio (10.000-50.000 pagine al mese). Per il parsing su larga scala (centinaia di migliaia di pagine), è meglio utilizzare proxy residenziali con i loro enormi pool di IP.
Consiglio sulla rotazione per diverse fonti:
- PubMed — la rotazione non è obbligatoria, basta 1 IP rispettando il rate limit
- Editori commerciali — sticky sessions di 10-15 minuti, nuovo IP ogni 15-20 pagine
- Database farmaceutici — rotazione per ogni richiesta o sticky sessions di 5 minuti
- Siti con Cloudflare — sticky sessions obbligatorie, rotazione a livello di richieste non funziona
Esempi di codice in Python per il parsing con proxy
Esaminiamo esempi pratici di configurazione dei proxy per il parsing dei dati medici utilizzando librerie Python popolari. Iniziamo con un esempio di base e lo complessiamo gradualmente.
Configurazione di base con la libreria requests
import requests
from time import sleep
import random
# Configurazione del proxy (sostituisci con i tuoi dati)
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}'
}
# Intestazioni per imitare un browser reale
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': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'DNT': '1',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1'
}
# Esempio di richiesta a PubMed
url = "https://pubmed.ncbi.nlm.nih.gov/?term=diabetes"
try:
response = requests.get(url, proxies=proxies, headers=headers, timeout=30)
print(f"Codice di stato: {response.status_code}")
print(f"Lunghezza del contenuto: {len(response.content)}")
# Aggiungi un ritardo tra le richieste (obbligatorio per PubMed)
sleep(random.uniform(1.0, 3.0))
except requests.exceptions.RequestException as e:
print(f"Errore: {e}")
Configurazione avanzata con rotazione e retry logic
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: lista di dizionari con proxy
[{'http': 'http://user:pass@host:port', 'https': '...'}, ...]
"""
self.proxy_list = proxy_list
self.current_index = 0
def get_next_proxy(self):
"""Ottieni il prossimo proxy dalla lista"""
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():
"""Crea una sessione con ripetizioni automatiche in caso di errori"""
session = requests.Session()
# Configurazione delle ripetizioni automatiche
retry_strategy = Retry(
total=3, # massimo 3 tentativi
backoff_factor=1, # ritardo tra i tentativi: 1, 2, 4 secondi
status_forcelist=[429, 500, 502, 503, 504], # codici per ripetere
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):
"""Parsing di un elenco di URL con rotazione dei proxy"""
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': 'en-US,en;q=0.9',
}
for url in urls:
# Otteniamo un nuovo proxy per ogni richiesta
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"✓ Successo: {url}")
else:
results.append({
'url': url,
'status': 'failed',
'error': f"Codice di stato: {response.status_code}"
})
print(f"✗ Fallito: {url} (Stato: {response.status_code})")
except requests.exceptions.RequestException as e:
results.append({
'url': url,
'status': 'error',
'error': str(e)
})
print(f"✗ Errore: {url} ({e})")
# Ritardo casuale tra le richieste (importante!)
sleep(random.uniform(2.0, 5.0))
return results
# Esempio di utilizzo
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)
Utilizzo di Selenium per siti con JavaScript
Molti siti medici moderni utilizzano JavaScript per caricare contenuti. In questi casi è necessario un browser headless:
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):
"""Crea un Chrome WebDriver con proxy"""
chrome_options = Options()
# Modalità headless (senza GUI)
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
# Configurazione del proxy
chrome_options.add_argument(f'--proxy-server=http://{proxy_host}:{proxy_port}')
# Disabilita l'automazione (importante per bypassare il rilevamento)
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)
# Per proxy con autenticazione è necessario utilizzare un'estensione
# o configurare tramite capabilities (opzione più complessa)
return driver
def scrape_with_selenium(url, driver):
"""Parsing di una pagina con attesa per il caricamento di JavaScript"""
driver.get(url)
# Attesa per il caricamento di un elemento (ad esempio, risultati di ricerca)
try:
wait = WebDriverWait(driver, 10)
results = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "results-article"))
)
# Estrazione dei dati
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"Errore in attesa degli elementi: {e}")
return []
# Esempio di utilizzo
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"Titolo: {result['title']}")
print(f"Autori: {result['authors']}\n")
finally:
driver.quit()
Controllo della velocità delle richieste e bypass del rate limiting
Il rate limiting è una delle principali protezioni dei siti medici contro il parsing. Una corretta configurazione della velocità delle richieste è fondamentale per un parsing a lungo termine senza blocchi.
Determinazione della velocità sicura
Il primo passo è determinare i limiti di un sito specifico. Questo può essere fatto sperimentalmente, aumentando gradualmente la velocità delle richieste fino a quando non si verificano errori 429 (Too Many Requests) o blocchi. Per la maggior parte dei siti medici, i valori sicuri sono:
- PubMed — massimo 3 richieste al secondo (raccomandazione ufficiale)
- ClinicalTrials.gov — 20 richieste al minuto sono sicure, fino a 100 in 5 minuti sono accettabili
- Editori commerciali — 10-15 richieste all'ora da un singolo IP
- Database farmaceutici — 5-10 richieste al minuto
Implementazione di un rate limiter in Python
import time
from collections import deque
class RateLimiter:
def __init__(self, max_calls, period):
"""
max_calls: numero massimo di chiamate
period: periodo di tempo in secondi
Ad esempio: RateLimiter(3, 1) = 3 richieste al secondo
"""
self.max_calls = max_calls
self.period = period
self.calls = deque()
def __call__(self, func):
"""Decoratore per limitare la velocità di chiamata della funzione"""
def wrapper(*args, **kwargs):
now = time.time()
# Rimuoviamo le chiamate vecchie al di fuori del periodo
while self.calls and self.calls[0] < now - self.period:
self.calls.popleft()
# Se abbiamo raggiunto il limite, aspettiamo
if len(self.calls) >= self.max_calls:
sleep_time = self.period - (now - self.calls[0])
if sleep_time > 0:
print(f"Limite di velocità raggiunto, attesa {sleep_time:.2f}s")
time.sleep(sleep_time)
# Pulisci dopo l'attesa
self.calls.clear()
# Registriamo il tempo della chiamata
self.calls.append(time.time())
# Eseguiamo la funzione
return func(*args, **kwargs)
return wrapper
# Esempio di utilizzo
@RateLimiter(max_calls=3, period=1) # 3 richieste al secondo
def fetch_pubmed_page(url):
response = requests.get(url, headers=headers, proxies=proxies)
return response
# Ora la funzione rispetta automaticamente il rate limit
for i in range(10):
result = fetch_pubmed_page(f"https://pubmed.ncbi.nlm.nih.gov/?term=test&page={i}")
print(f"Pagina {i} recuperata")
Rate limiting adattivo
Un approccio più avanzato è modificare la velocità in base alle risposte del server. Se riceviamo errori 429 o 503, riduciamo automaticamente la velocità:
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):
"""Attesa prima della prossima richiesta"""
# Aggiungiamo casualità per naturalezza
actual_delay = self.current_delay * random.uniform(0.8, 1.2)
time.sleep(actual_delay)
def on_success(self):
"""Chiamato quando la richiesta ha successo"""
self.success_count += 1
# Dopo 10 richieste di successo, aumentiamo un po'
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):
"""Chiamato quando si riceve 429 o errori simili"""
# Dobbiamo raddoppiare il ritardo, ma non oltre il massimo
self.current_delay = min(
self.current_delay * 2,
self.max_delay
)
self.success_count = 0
print(f"Limite di velocità colpito! Aumento del ritardo a {self.current_delay:.2f}s")
def on_error(self):
"""Chiamato in caso di altri errori"""
# Aumentiamo un po' il ritardo
self.current_delay = min(
self.current_delay * 1.5,
self.max_delay
)
self.success_count = 0
# Esempio di utilizzo
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()
# Elaborazione dei dati
elif response.status_code == 429:
limiter.on_rate_limit()
# Ripetere più tardi
else:
limiter.on_error()
except requests.exceptions.RequestException:
limiter.on_error()
Intestazioni corrette e User-Agent per i siti medici
I siti medici analizzano le intestazioni HTTP per rilevare i bot. Intestazioni errate o mancanti sono una causa comune di blocchi anche quando si utilizzano proxy di alta qualità.
Intestazioni obbligatorie
Il set minimo di intestazioni che deve essere presente in ogni richiesta:
headers = {
# User-Agent — deve essere un browser attuale
'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 — tipi di contenuto accettati dal browser
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
# Accept-Language — lingua dell'utente
'Accept-Language': 'en-US,en;q=0.9',
# Accept-Encoding — supporto per la compressione
'Accept-Encoding': 'gzip, deflate, br',
# Connection — mantenimento della connessione
'Connection': 'keep-alive',
# Upgrade-Insecure-Requests — passaggio automatico a HTTPS
'Upgrade-Insecure-Requests': '1',
# DNT — Do Not Track (opzionale, ma aggiunge realismo)
'DNT': '1',
# Intestazioni Sec-Fetch-* (importanti per i browser moderni)
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
# Cache-Control
'Cache-Control': 'max-age=0'
}
Rotazione User-Agent
L'utilizzo dello stesso User-Agent può essere sospetto. Si raccomanda di ruotare tra diversi browser attuali:
import random
USER_AGENTS = [
# Chrome su 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 su 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 su Windows
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
# Firefox su Mac
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0',
# Safari su 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 su 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():
"""Ottieni intestazioni con User-Agent casuale"""
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': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'DNT': '1'
}
# Utilizzo
for url in urls:
headers = get_random_headers()
response = requests.get(url, headers=headers, proxies=proxies)
Referer e Origin per i moduli
Quando si lavora con moduli di ricerca o si inviano richieste POST, è fondamentale aggiungere le intestazioni Referer e Origin:
# Per richieste POST al modulo di ricerca
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': 'en-US,en;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'
}
# Richiesta POST con dati del modulo
data = {
'query': 'diabetes',
'page': '1'
}
response = requests.post(
'https://example.com/search',
headers=headers,
data=data,
proxies=proxies
)
Problemi comuni e loro soluzione
Durante il parsing dei dati medici possono sorgere problemi specifici. Esaminiamo i più comuni e i modi per risolverli.
Problema: Cloudflare blocca tutte le richieste
Sintomi: Ricevi una pagina con il testo "Controllo del browser" o un errore 403 Forbidden con riferimento a Cloudflare.
Soluzione:
- Utilizza proxy residenziali invece dei data center — Cloudflare blocca gli IP dei data center per impostazione predefinita
- Passa a Selenium o Puppeteer — i browser headless superano meglio i controlli di Cloudflare
- Utilizza la libreria cloudscraper per Python — bypassa automaticamente la protezione di base di Cloudflare
- Attiva i cookie e JavaScript — Cloudflare verifica la loro presenza
- Aggiungi fingerprinting TLS — utilizza curl_cffi per imitare un vero browser a livello TLS
Problema: Ricevo errore 429 Too Many Requests
Sintomi: Dopo alcune richieste riuscite, il server inizia a restituire 429.
Soluzione:
- Aumenta il ritardo tra le richieste — prova a partire da 3-5 secondi
- Attiva la rotazione IP — ogni richiesta tramite un nuovo IP rimuove il rate limiting
- Controlla l'intestazione Retry-After nella risposta 429 — indica quanti secondi è necessario attendere
- Utilizza un ritardo esponenziale nei ripetizioni — 1s, 2s, 4s, 8s, ecc.
Problema: I proxy funzionano lentamente o cadono frequentemente
Sintomi: Timeout errors, caricamento molto lento delle pagine, interruzioni della connessione.
Soluzione:
- Aumenta il timeout nelle richieste a 30-60 secondi — i proxy residenziali possono essere più lenti
- Utilizza proxy geograficamente vicini — se stai eseguendo il parsing di un sito europeo, utilizza IP europei
- Controlla la qualità del fornitore di proxy — i proxy economici sono spesso instabili
- Aggiungi retry logic — ripeti automaticamente la richiesta in caso di errore di connessione
- Utilizza connection pooling — riutilizza le connessioni TCP tramite requests.Session()
Problema: Il sito richiede autenticazione o abbonamento
Sintomi: L'accesso ai testi completi degli articoli è limitato, è necessario effettuare il login.
Soluzione:
- Utilizza l'accesso istituzionale — molte università e ospedali hanno abbonamenti
- Controlla la disponibilità di versioni Open Access — molti articoli sono disponibili gratuitamente tramite repository
- Utilizza API invece del parsing — alcuni editori forniscono API per i ricercatori
- Esegui il parsing solo dei metadati (titoli, autori, abstract) — di solito sono disponibili gratuitamente
Problema: Il contenuto JavaScript non viene caricato
Sintomi: Non ci sono dati necessari nell'HTML, si vedono solo spinner di caricamento o contenitori vuoti.
Soluzione:
- Passa a Selenium/Puppeteer — eseguono JavaScript
- Trova l'endpoint API — apri DevTools nel browser, scheda Network, e trova le richieste XHR con i dati
- Utilizza requests-html — libreria con supporto per il rendering JavaScript