Tutoriels

Notion API + CaptchaAI : saisie automatisée des données avec gestion des CAPTCHA

L'API de Notion vous permet de lire et d'écrire dans des bases de données par programmation, ce qui en fait une couche de gestion de tâches flexible pour les flux de travail d'automatisation. Lorsque ces flux de travail rencontrent des formulaires protégés par CAPTCHA,CaptchaAIgère la résolution. Ce guide montre comment utiliser une base de données Notion comme file d'attente de tâches CAPTCHA : stocker les URL et les clés de site, déclencher des résolutions et réécrire les résultats.

Scénario du monde réel

Votre équipe gère une base de données Notion d'URL de sites Web qui nécessitent une extraction périodique des données. Certaines de ces URL sont protégées par CAPTCHA. Un scénario :

  1. Lit les tâches en attente de Notion
  2. Résout les CAPTCHA via CaptchaAI
  3. Met à jour chaque enregistrement Notion avec le jeton et le statut

Conditions préalables

  • Notion d'intégration (Intégration interne viadéveloppeurs.notion.com)
  • Une base de données Notion partagée avec l'intégration
  • Clé API CaptchaAI
  • Python 3.8+ ou Node.js 18+

Configuration de la base de données Notion

Créez une base de données Notion avec ces propriétés :

Propriété Tapez Objectif
Nom Titre Identifiant de la tâche
URL URL Page cible avec CAPTCHA
Clé du site Texte enrichi Clé de site reCAPTCHA
Statut Sélectionnez En attente, en résolution, résolu, en échec
Jeton Texte enrichi Jeton CAPTCHA résolu
Résolu à Date Résoudre l'horodatage
Erreur Texte enrichi Message d'erreur en cas d'échec

Partagez la base de données avec votre intégration Notion.

Implémentation Python

# notion_captcha_worker.py
import os
import time
import requests

NOTION_TOKEN = os.environ.get("NOTION_TOKEN")
NOTION_DB_ID = os.environ.get("NOTION_DB_ID")
CAPTCHAAI_KEY = os.environ.get("CAPTCHAAI_KEY", "YOUR_API_KEY")

NOTION_HEADERS = {
    "Authorization": f"Bearer {NOTION_TOKEN}",
    "Content-Type": "application/json",
    "Notion-Version": "2022-06-28",
}

def get_pending_tasks():
    """Fetch tasks with Status = Pending from Notion."""
    url = f"https://api.notion.com/v1/databases/{NOTION_DB_ID}/query"
    payload = {
        "filter": {
            "property": "Status",
            "select": {"equals": "Pending"},
        }
    }
    resp = requests.post(url, headers=NOTION_HEADERS, json=payload)
    resp.raise_for_status()
    return resp.json()["results"]

def update_task(page_id, properties):
    """Update a Notion page with new property values."""
    url = f"https://api.notion.com/v1/pages/{page_id}"
    payload = {"properties": properties}
    resp = requests.patch(url, headers=NOTION_HEADERS, json=payload)
    resp.raise_for_status()

def set_status(page_id, status, token=None, error=None):
    """Update task status in Notion."""
    props = {"Status": {"select": {"name": status}}}

    if token:
        props["Token"] = {"rich_text": [{"text": {"content": token[:2000]}}]}
        props["Solved At"] = {"date": {"start": time.strftime("%Y-%m-%dT%H:%M:%S")}}

    if error:
        props["Error"] = {"rich_text": [{"text": {"content": error[:200]}}]}

    update_task(page_id, props)

def solve_captcha(sitekey, pageurl):
    """Submit to CaptchaAI and poll for result."""
    # Submit
    resp = requests.get("https://ocr.captchaai.com/in.php", params={
        "key": CAPTCHAAI_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": "1",
    })
    result = resp.json()

    if result.get("status") != 1:
        raise Exception(f"Submit failed: {result.get('request')}")

    task_id = result["request"]

    # Poll
    time.sleep(15)
    for _ in range(25):
        poll = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": CAPTCHAAI_KEY,
            "action": "get",
            "id": task_id,
            "json": "1",
        })
        poll_result = poll.json()

        if poll_result.get("status") == 1:
            return poll_result["request"]
        if poll_result.get("request") != "CAPCHA_NOT_READY":
            raise Exception(f"Solve failed: {poll_result.get('request')}")

        time.sleep(5)

    raise Exception("Polling timeout")

def extract_property(page, prop_name, prop_type="rich_text"):
    """Extract a property value from a Notion page."""
    prop = page["properties"].get(prop_name, {})
    if prop_type == "rich_text":
        texts = prop.get("rich_text", [])
        return texts[0]["plain_text"] if texts else ""
    elif prop_type == "url":
        return prop.get("url", "")
    return ""

def main():
    tasks = get_pending_tasks()
    print(f"Found {len(tasks)} pending tasks")

    for task in tasks:
        page_id = task["id"]
        sitekey = extract_property(task, "Sitekey")
        pageurl = extract_property(task, "URL", "url")

        if not sitekey or not pageurl:
            set_status(page_id, "Failed", error="Missing sitekey or URL")
            continue

        print(f"Solving: {pageurl}")
        set_status(page_id, "Solving")

        try:
            token = solve_captcha(sitekey, pageurl)
            set_status(page_id, "Solved", token=token)
            print(f"  Solved successfully")
        except Exception as e:
            set_status(page_id, "Failed", error=str(e))
            print(f"  Failed: {e}")

        time.sleep(1)  # Rate limit for Notion API

    print("All tasks processed")

if __name__ == "__main__":
    main()

Implémentation JavaScript

// notion_captcha_worker.js
const { Client } = require('@notionhq/client');
const axios = require('axios');

const notion = new Client({ auth: process.env.NOTION_TOKEN });
const DB_ID = process.env.NOTION_DB_ID;
const API_KEY = process.env.CAPTCHAAI_KEY || 'YOUR_API_KEY';

async function getPendingTasks() {
  const response = await notion.databases.query({
    database_id: DB_ID,
    filter: { property: 'Status', select: { equals: 'Pending' } },
  });
  return response.results;
}

async function updateTask(pageId, status, token, error) {
  const properties = {
    Status: { select: { name: status } },
  };
  if (token) {
    properties.Token = { rich_text: [{ text: { content: token.slice(0, 2000) } }] };
    properties['Solved At'] = { date: { start: new Date().toISOString() } };
  }
  if (error) {
    properties.Error = { rich_text: [{ text: { content: error.slice(0, 200) } }] };
  }
  await notion.pages.update({ page_id: pageId, properties });
}

async function solveCaptcha(sitekey, pageurl) {
  const submit = await axios.get('https://ocr.captchaai.com/in.php', {
    params: {
      key: API_KEY, method: 'userrecaptcha',
      googlekey: sitekey, pageurl, json: '1',
    },
  });
  if (submit.data.status !== 1) throw new Error(submit.data.request);

  await new Promise(r => setTimeout(r, 15000));

  for (let i = 0; i < 25; i++) {
    const poll = await axios.get('https://ocr.captchaai.com/res.php', {
      params: { key: API_KEY, action: 'get', id: submit.data.request, json: '1' },
    });
    if (poll.data.status === 1) return poll.data.request;
    if (poll.data.request !== 'CAPCHA_NOT_READY') throw new Error(poll.data.request);
    await new Promise(r => setTimeout(r, 5000));
  }
  throw new Error('Timeout');
}

async function main() {
  const tasks = await getPendingTasks();
  console.log(`Found ${tasks.length} pending tasks`);

  for (const task of tasks) {
    const sitekey = task.properties.Sitekey?.rich_text?.[0]?.plain_text;
    const pageurl = task.properties.URL?.url;

    if (!sitekey || !pageurl) {
      await updateTask(task.id, 'Failed', null, 'Missing sitekey or URL');
      continue;
    }

    console.log(`Solving: ${pageurl}`);
    await updateTask(task.id, 'Solving');

    try {
      const token = await solveCaptcha(sitekey, pageurl);
      await updateTask(task.id, 'Solved', token);
      console.log('  Solved');
    } catch (e) {
      await updateTask(task.id, 'Failed', null, e.message);
      console.log(`  Failed: ${e.message}`);
    }

    await new Promise(r => setTimeout(r, 1000));
  }
}

main().catch(console.error);

Dépannage

Problème Parce que Corriger
401 Unauthorized de Notion Intégration non connectée à la base de données Partagez la base de données avec votre intégration dans Notion
Les noms de propriétés ne correspondent pas Sensibilité à la casse Les noms de propriétés de notion sont sensibles à la casse – correspondent exactement
Jeton tronqué Notion rich_text limite de 2000 caractères Les jetons CAPTCHA contiennent généralement moins de 1 000 caractères ; cela ne devrait pas être un problème
Limite du taux de notion (429) Trop d'appels API Ajouter des délais d'une seconde entre les mises à jour de Notion

FAQ

Puis-je exécuter ceci en tant que tâche planifiée ?

Oui. Utilisez cron (Linux), le planificateur de tâches (Windows) ou un planificateur cloud (AWS EventBridge, Google Cloud Scheduler) pour exécuter le script selon un planning.

Comment configurer l'intégration de Notion ?

Aller ànotion.so/my-integrations, créez une nouvelle intégration interne, copiez le jeton secret et partagez votre base de données avec l'intégration.

Puis-je traiter d’autres types de CAPTCHA ?

Oui. Ajoutez une propriété « CAPTCHA Type » à la base de données Notion et modifiez la fonction de résolution pour utiliser la méthode CaptchaAI appropriée (turnstile, geetest, base64, etc.).

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

Transformez vos bases de données Notion en files d'attente automatisées de résolution de CAPTCHA -récupérez votre clé API CaptchaAI.

Guides associés :

Les commentaires sont désactivés pour cet article.