Créer un outil de comparaison des prix des pharmacies signifie collecter des données sur les prix à partir de plusieurs portails de pharmacies, bases de données sur les prix des médicaments et formulaires d'assurance. Beaucoup de ces sources protègent leurs pages de tarification avec des CAPTCHA – en particulier reCAPTCHA v2 sur les formulaires de recherche et les pages de résultats. Voici comment les gérer.
Où les CAPTCHA apparaissent dans les portails de pharmacie
| Type de page | CAPTCHA commun | Déclencheur |
|---|---|---|
| Formulaire de recherche de médicaments | reCAPTCHA v2 | Chaque requête de recherche |
| Page de résultats des prix | Cloudflare Turnstile | Accès automatisé suspecté |
| Localisateur de pharmacie | reCAPTCHA v2 | Requêtes basées sur la localisation |
| Recherche de coupons | Image CAPTCHA | Avant d'afficher les codes de réduction |
| Formulaire d'assurance | reCAPTCHA v2 | ConnexionPortes /search |
Flux de travail de base
import requests
import time
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
def solve_recaptcha(site_key, page_url):
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": "YOUR_API_KEY",
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"json": 1
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": "YOUR_API_KEY",
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return data["request"]
raise TimeoutError("Solve timed out")
def search_drug_prices(drug_name, zipcode):
search_url = "https://pharmacy.example.com/search"
# Load the search page to get the site key
page = session.get(search_url)
# Extract reCAPTCHA site key
import re
match = re.search(r'data-sitekey="([^"]+)"', page.text)
site_key = match.group(1)
# Solve the CAPTCHA
token = solve_recaptcha(site_key, search_url)
# Submit the search with token
results = session.post(search_url, data={
"drug": drug_name,
"zip": zipcode,
"g-recaptcha-response": token
})
return parse_prices(results.text)
Comparaison multi-pharmacie
Comparez les prix sur plusieurs sources :
PHARMACY_SOURCES = [
{
"name": "PharmacyA",
"url": "https://pharmacya.example.com/pricing",
"captcha_type": "recaptcha_v2"
},
{
"name": "PharmacyB",
"url": "https://pharmacyb.example.com/drugs",
"captcha_type": "turnstile"
},
{
"name": "PharmacyC",
"url": "https://pharmacyc.example.com/search",
"captcha_type": "image"
}
]
def compare_drug_price(drug_name, zipcode):
results = []
for source in PHARMACY_SOURCES:
try:
prices = fetch_prices(
source["url"],
source["captcha_type"],
drug_name,
zipcode
)
results.append({
"source": source["name"],
"prices": prices,
"status": "success"
})
except Exception as e:
results.append({
"source": source["name"],
"error": str(e),
"status": "failed"
})
return sorted(results, key=lambda r: r.get("prices", {}).get("lowest", float("inf")))
Gestion de différents types de CAPTCHA
Les portails de pharmacie utilisent différents fournisseurs de CAPTCHA :
def fetch_prices(url, captcha_type, drug_name, zipcode):
page = session.get(url)
if captcha_type == "recaptcha_v2":
import re
match = re.search(r'data-sitekey="([^"]+)"', page.text)
token = solve_recaptcha(match.group(1), url)
field_name = "g-recaptcha-response"
elif captcha_type == "turnstile":
import re
match = re.search(r'data-sitekey="(0x[^"]+)"', page.text)
token = solve_turnstile(match.group(1), url)
field_name = "cf-turnstile-response"
elif captcha_type == "image":
img_data = extract_captcha_image(page.text)
token = solve_image_captcha(img_data)
field_name = "captcha"
return session.post(url, data={
"drug": drug_name,
"zip": zipcode,
field_name: token
})
Gestion de session pour les recherches répétées
La comparaison des prix des médicaments nécessite plusieurs recherches. Gérez les sessions pour minimiser les rencontres CAPTCHA :
class PharmacySession:
def __init__(self, base_url):
self.session = requests.Session()
self.base_url = base_url
self.searches_since_captcha = 0
def search(self, drug_name, zipcode):
result = self.session.post(f"{self.base_url}/search", data={
"drug": drug_name,
"zip": zipcode
})
if self.is_captcha_page(result.text):
token = self.solve_page_captcha(result.text)
result = self.session.post(f"{self.base_url}/search", data={
"drug": drug_name,
"zip": zipcode,
"g-recaptcha-response": token
})
self.searches_since_captcha = 0
else:
self.searches_since_captcha += 1
return result
def is_captcha_page(self, html):
return "g-recaptcha" in html or "cf-turnstile" in html
def solve_page_captcha(self, html):
import re
match = re.search(r'data-sitekey="([^"]+)"', html)
return solve_recaptcha(match.group(1), self.base_url)
Implémentation JavaScript
async function comparePharmacyPrices(drugName, zipCode, sources) {
const results = await Promise.all(
sources.map(async (source) => {
try {
const price = await fetchDrugPrice(source, drugName, zipCode);
return { source: source.name, price, status: 'success' };
} catch (error) {
return { source: source.name, error: error.message, status: 'failed' };
}
})
);
return results
.filter(r => r.status === 'success')
.sort((a, b) => a.price - b.price);
}
async function fetchDrugPrice(source, drugName, zipCode) {
// Solve CAPTCHA for this source
const token = await solveCaptcha(source.siteKey, source.url);
const response = await fetch(source.url, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
drug: drugName,
zip: zipCode,
'g-recaptcha-response': token
})
});
return parsePrice(await response.text());
}
Considérations relatives à la limitation du débit
Les portails pharmaceutiques surveillent de près les modèles d’accès :
| Stratégie | Mise en œuvre |
|---|---|
| Demandes d'espace | 5 à 10 secondes entre les recherches |
| Rotation des sessions | Nouvelle session toutes les 20 à 30 requêtes |
| Varier les modèles de recherche | Ne recherchez pas le même médicament à plusieurs reprises |
| Utiliser des proxys résidentiels | Les adresses IP des centres de données déclenchent davantage de CAPTCHA |
Dépannage
| Problème | Parce que | Corriger |
|---|---|---|
| CAPTCHA à chaque recherche | La session ne persiste pas les cookies | Utilisez requests.Session() et conservez les cookies |
| Les prix ne se chargent pas après CAPTCHA | Jeton CSRF manquant | Extraire et inclure les champs de formulaire masqués |
| Le site se bloque après de nombreuses recherches | Limitation du débit | Ajouter des délais entre les demandes |
| Prix différents de ceux du navigateur | Cookies ou en-têtes de session manquants | Faire correspondre exactement les en-têtes du navigateur |
FAQ
Combien de sources pharmaceutiques puis-je comparer simultanément ?
CaptchaAI gère la résolution parallèle. Vous pouvez résoudre simultanément les CAPTCHA de plusieurs portails de pharmacie. La limite pratique dépend de votre solde CaptchaAI et des limites de taux de chaque portail.
Les portails de pharmacie changent-ils fréquemment leurs types CAPTCHA ?
Certains portails mettent régulièrement à jour leur implémentation CAPTCHA. Surveillez les modifications en vérifiant si votre extraction trouve toujours la clé du site. CaptchaAI prend en charge tous les principaux types de CAPTCHA, donc changer de fournisseur ne nécessite pas de modifier votre approche de résolution.
Y a-t-il une différence entre les portails de tarification des médicaments de marque et des médicaments génériques ?
La gestion du CAPTCHA est similaire. Les bases de données de médicaments génériques peuvent utiliser des CAPTCHA d'image plus simples, tandis que les portails de pharmacies de marque ont tendance à utiliser reCAPTCHA v2 ou Turnstile.
Articles connexes
- Comment résoudre le rappel Recaptcha V2 à l'aide de l'API
- Gestion du tourniquet Recaptcha V2 sur le même site
- Mécanisme de rappel Recaptcha V2
Prochaines étapes
Créez votre outil de comparaison de prix en pharmacie -récupérez votre clé API CaptchaAIet gérez les CAPTCHA dans toutes les sources pharmaceutiques.