Der Aufbau eines Tools zum Vergleich von Apothekenpreisen erfordert das Sammeln von Preisdaten aus mehreren Apothekenportalen, Arzneimittelpreisdatenbanken und Versicherungsformularen. Viele dieser Quellen schützen ihre Preisseiten mit CAPTCHAs – insbesondere reCAPTCHA v2 auf Suchformularen und Ergebnisseiten. Hier erfahren Sie, wie Sie damit umgehen.
Wo CAPTCHAs in Apothekenportalen erscheinen
| Seitentyp | Gemeinsames CAPTCHA | Auslöser |
|---|---|---|
| Formular zur Drogensuche | reCAPTCHA v2 | Jede Suchanfrage |
| Preisergebnisseite | Cloudflare Turnstile | Verdacht auf automatisierten Zugriff |
| Apothekensuche | reCAPTCHA v2 | Standortbezogene Abfragen |
| Gutscheinsuche | Bild-CAPTCHA | Bevor Rabattcodes angezeigt werden |
| Versicherungsformular | reCAPTCHA v2 | Login/search Tore |
Grundlegender Arbeitsablauf
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)
Vergleich mehrerer Apotheken
Vergleichen Sie die Preise aus mehreren Quellen:
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")))
Umgang mit verschiedenen CAPTCHA-Typen
Apothekenportale nutzen verschiedene CAPTCHA-Anbieter:
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
})
Sitzungsverwaltung für wiederholte Suchen
Für den Arzneimittelpreisvergleich sind mehrere Suchanfragen erforderlich. Verwalten Sie Sitzungen, um CAPTCHA-Begegnungen zu minimieren:
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)
JavaScript-Implementierung
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());
}
Überlegungen zur Ratenbegrenzung
Apothekenportale überwachen die Zugriffsmuster genau:
| Strategie | Umsetzung |
|---|---|
| Platzanfragen | 5–10 Sekunden zwischen den Suchvorgängen |
| Sitzungen rotieren | Neue Sitzung alle 20–30 Abfragen |
| Variieren Sie Suchmuster | Suchen Sie nicht wiederholt nach demselben Medikament |
| Verwenden Sie Proxys für Privathaushalte | Rechenzentrums-IPs lösen mehr CAPTCHAs aus |
Fehlerbehebung
| Problem | Ursache | Lösung |
|---|---|---|
| Zu viele CAPTCHAs in kurzer Zeit | Abrufrate oder Parallelität ist für die Quelle zu aggressiv | Drossele Intervalle, halte Sessions stabil und prüfe die Qualität deiner Proxys |
| Daten fehlen trotz gelöster CAPTCHA | Der Parser liest eine alte oder unvollständige Ansicht aus | Extrahiere Daten erst nach erfolgreicher Token-Anwendung in derselben Sitzung |
| Kosten steigen stärker als erwartet | Zu viele Wiederholungen oder unnötige Seitenaufrufe lösen zusätzliche Challenges aus | Löse nur kritische Schritte und protokolliere Wiederholungen pro Quelle |
Verwandte Leitfäden
- Versicherungsangebotsvergleich mit CAPTCHA-Automatisierung
- Gesundheitsdaten-Scraping mit CAPTCHA-Verwaltung
- Retail-Inventar-Monitoring mit CAPTCHA