Apify est une plateforme de scraping cloud qui exécute des acteurs basés sur Crawlee. Lorsque ces acteurs rencontrent un reCAPTCHA pendant la navigation ou l'extraction, il faut ajouter une étape de résolution propre au milieu du handler, sans transformer tout l'acteur en séquence fragile. CaptchaAI s'intègre bien à ce modèle.
Ce guide montre comment exposer la clé API dans l'input de l'acteur, détecter un CAPTCHA depuis Playwright, résoudre le token puis reprendre le flux normal de scraping.
Configuration de l'acteur
L'objectif de l'input schema est simple : rendre l'acteur réutilisable depuis l'interface Apify sans devoir modifier le code à chaque exécution.
Schéma d'entrée
{
"title": "CAPTCHA Scraper Input",
"type": "object",
"properties": {
"startUrls": {
"title": "Start URLs",
"type": "array",
"editor": "requestListSources"
},
"captchaaiApiKey": {
"title": "CaptchaAI API Key",
"type": "string",
"isSecret": true
},
"maxConcurrency": {
"title": "Max Concurrency",
"type": "integer",
"default": 3
}
},
"required": ["startUrls", "captchaaiApiKey"]
}
Code de l'acteur
const { Actor } = require('apify');
const { PlaywrightCrawler } = require('crawlee');
Actor.main(async () => {
const input = await Actor.getInput();
const { startUrls, captchaaiApiKey, maxConcurrency = 3 } = input;
const solver = new CaptchaAISolver(captchaaiApiKey);
const crawler = new PlaywrightCrawler({
maxConcurrency,
requestHandlerTimeoutSecs: 180,
async requestHandler({ request, page, log }) {
await page.goto(request.url, { waitUntil: 'networkidle' });
// Check for CAPTCHA
const sitekey = await page.evaluate(() => {
const el = document.querySelector('[data-sitekey]');
return el ? el.getAttribute('data-sitekey') : null;
});
if (sitekey) {
log.info(`Solving CAPTCHA on ${request.url}`);
const token = await solver.solve(sitekey, request.url);
// Inject and submit
await page.evaluate((t) => {
document.querySelector('[name="g-recaptcha-response"]').value = t;
const cb = document.querySelector('.g-recaptcha')?.getAttribute('data-callback');
if (cb && window[cb]) window[cb](t);
}, token);
await page.click('button[type="submit"]');
await page.waitForNavigation({ timeout: 15000 });
}
// Extract data
const title = await page.title();
const items = await page.$$eval('.item', els =>
els.map(el => ({
name: el.querySelector('.name')?.textContent?.trim(),
price: el.querySelector('.price')?.textContent?.trim(),
url: el.querySelector('a')?.href,
}))
);
// Push to Apify dataset
await Actor.pushData({
url: request.url,
title,
items,
scrapedAt: new Date().toISOString(),
});
log.info(`Scraped ${items.length} items from ${request.url}`);
},
});
await crawler.run(startUrls);
});
class CaptchaAISolver {
constructor(apiKey) {
this.apiKey = apiKey;
}
async solve(sitekey, pageurl) {
const params = new URLSearchParams({
key: this.apiKey,
method: 'userrecaptcha',
googlekey: sitekey,
pageurl: pageurl,
json: '1',
});
const submitResp = await fetch('https://ocr.captchaai.com/in.php', {
method: 'POST',
body: params,
});
const submitResult = await submitResp.json();
if (submitResult.status !== 1) {
throw new Error(`Submit: ${submitResult.request}`);
}
const taskId = submitResult.request;
await new Promise(r => setTimeout(r, 15000));
for (let i = 0; i < 24; i++) {
const pollResp = await fetch(
`https://ocr.captchaai.com/res.php?key=${this.apiKey}&action=get&id=${taskId}&json=1`
);
const result = await pollResp.json();
if (result.status === 1) return result.request;
if (result.request !== 'CAPCHA_NOT_READY') {
throw new Error(`Solve: ${result.request}`);
}
await new Promise(r => setTimeout(r, 5000));
}
throw new Error('Timeout');
}
}
Variables d'environnement sur Apify
Si vous ne voulez pas fournir la clé API à chaque run, stockez-la dans les variables d'environnement de l'acteur :
- Ouvrez les paramètres de l'acteur puis Environment variables.
- Ajoutez
CAPTCHAAI_API_KEYet marquez-la comme secrète. - Récupérez-la ensuite dans le code via
process.env.CAPTCHAAI_API_KEY.
// Alternative: use env var instead of input
const apiKey = input.captchaaiApiKey || process.env.CAPTCHAAI_API_KEY;
Proxys Apify et CaptchaAI
Pour la plupart des cas, laissez Apify gérer les proxys de scraping et utilisez CaptchaAI uniquement pour la résolution. Cela simplifie l'architecture et évite de multiplier les coûts inutilement.
const crawler = new PlaywrightCrawler({
proxyConfiguration: await Actor.createProxyConfiguration({
groups: ['RESIDENTIAL'],
}),
// ... rest of config
});
FAQ
Puis-je utiliser CaptchaAI avec l'offre gratuite d'Apify ?
Oui. CaptchaAI est un appel API externe, donc il fonctionne quel que soit le plan Apify. Vos couts combinent simplement la consommation compute d'Apify et la résolution cote CaptchaAI.
Dois-je utiliser des proxys Apify ou le paramètre proxy de CaptchaAI ?
Dans la plupart des projets, utilisez les proxys Apify pour les requêtes de scraping et laissez CaptchaAI résoudre sans proxy dédié. C'est souvent l'option la plus simple et la plus rentable.
Comment gérer les délais d'attente des acteurs Apify avec la résolution de CAPTCHA ?
Prévoyez au moins 180 secondes pour requestHandlerTimeoutSecs. Entre le chargement de page, la soumission du challenge et le polling, un timeout trop court casse vite l'acteur.
Guides connexes
- Intégration Crawlee + CaptchaAI
- Construire un framework de scraping personnalise
Si Apify exécute déjà votre pipeline, obtenez une clé CaptchaAI et ajoutez la résolution CAPTCHA comme une étape normale de l'acteur plutôt qu'un traitement d'exception.