في معظم الحالات لن تحتاج إلى استخراج رابط anchor أو bframe؛ إذ يكفي CaptchaAI مفتاح الموقع (sitekey) وعنوان الصفحة (pageurl) لحل reCAPTCHA v2. لكنّ فهم بنية الإطارين يصبح أداة تشخيص مهمة في ثلاث حالات:
- رفض الرمز رغم صحّة الإعداد الظاهري.
- وجود أكثر من نسخة reCAPTCHA في الصفحة نفسها.
- تحميل مفتاح الموقع ديناميكياً بعد رسم الصفحة.
يشرح هذا الدليل بنية الإطارين، ومعنى معلماتهما، ومتى تستخرجها فعلاً.
كيف يركّب reCAPTCHA إطارَي anchor وbframe
يُعرض reCAPTCHA داخل إطارَي iframe متداخلين يحملان معلمات مشفّرة تحتاجها بعض سير عمل الأتمتة المتقدمة:
- إطار anchor: يحمل مربع الاختيار «I'm not a robot» والتحليل المبدئي للمخاطر، وهو ظاهر منذ تحميل الصفحة.
- إطار bframe: يحمل شبكة تحدي الصور، ولا يُحمَّل إلا عند النقر على مربع الاختيار.
Target page (example.com/login)
└── <iframe src="https://www.google.com/recaptcha/api2/anchor?...">
│ ← Anchor iframe: "I'm not a robot" checkbox
│
└── <iframe src="https://www.google.com/recaptcha/api2/bframe?...">
← Bframe iframe: Image challenge grid (loads when clicked)
إطار anchor: مربع الاختيار والتحليل المبدئي
يظهر رابط anchor كالتالي، حاملاً مفتاح الموقع والأصل والإصدار:
https://www.google.com/recaptcha/api2/anchor?
ar=1
&k=6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp ← site key
&co=aHR0cHM6Ly9leGFtcGxlLmNvbTo0NDM. ← encoded origin
&hl=en ← language
&v=jF2Zb_rr_5sv8dMHoGIn-XxY ← reCAPTCHA version
&size=normal ← widget size
&cb=89fu2pf0swif ← callback ID
إطار bframe: شبكة تحدي الصور
أما رابط إطار bframe فأبسط، ويقتصر على اللغة والإصدار ومفتاح الموقع:
https://www.google.com/recaptcha/api2/bframe?
hl=en
&v=jF2Zb_rr_5sv8dMHoGIn-XxY
&k=6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp
معلمات رابط anchor وما الذي يعنيه كلٌّ منها
| المعلمة | الاسم | الوصف |
|---|---|---|
k |
مفتاح الموقع | مفتاح موقع reCAPTCHA |
co |
الأصل المشفّر | الأصل المشفّر بترميز Base64 (البروتوكول + النطاق + المنفذ) |
v |
الإصدار | تجزئة إصدار حزمة reCAPTCHA JavaScript |
hl |
اللغة | رمز لغة التحدي |
size |
الحجم | normal أو compact أو invisible |
cb |
رد النداء | معرّف دالة رد النداء الفريد |
theme |
السمة | light أو dark |
ar |
نسبة العرض | علامة نسبة العرض إلى الارتفاع |
فك تشفير المعلمة co لاستخراج الأصل
تحمل المعلمة co الأصل مشفّراً بـ base64، ويكفي فكّه لمعرفة نطاق تهيئة reCAPTCHA:
import base64
co_value = "aHR0cHM6Ly9leGFtcGxlLmNvbTo0NDM."
# Remove trailing period (padding artifact)
decoded = base64.b64decode(co_value.rstrip(".") + "==").decode()
print(decoded) # "https://example.com:443"
يكشف هذا النطاق الأصلي الذي ضُبط عليه reCAPTCHA، وهي نقطة مهمة عند تشخيص رفض الرموز.
طرق استخراج رابطَي anchor وbframe
تختلف الطريقة بحسب ظهور reCAPTCHA في شيفرة الصفحة الأولية أم حقنه ديناميكياً بعد التحميل.
الاستخراج من مصدر الصفحة باستخدام Python
حين يظهر إطار anchor في مصدر HTML، تقرأ معلماته بـ BeautifulSoup:
import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, parse_qs
import re
import base64
def extract_recaptcha_iframes(url):
"""Extract reCAPTCHA anchor and bframe iframe URLs and parameters."""
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",
}
response = requests.get(url, headers=headers, timeout=15)
soup = BeautifulSoup(response.text, "html.parser")
result = {
"anchor_url": None,
"bframe_url": None,
"site_key": None,
"origin": None,
"version": None,
"language": None,
}
# Find anchor iframe
anchor_iframe = soup.find("iframe", src=re.compile(r"recaptcha.*anchor"))
if anchor_iframe:
anchor_url = anchor_iframe.get("src", "")
result["anchor_url"] = anchor_url
# Parse parameters
parsed = urlparse(anchor_url)
params = parse_qs(parsed.query)
result["site_key"] = params.get("k", [None])[0]
result["version"] = params.get("v", [None])[0]
result["language"] = params.get("hl", [None])[0]
# Decode origin
co = params.get("co", [None])[0]
if co:
try:
padded = co.rstrip(".") + "=="
result["origin"] = base64.b64decode(padded).decode()
except Exception:
result["origin"] = co
# Find bframe iframe (may not be in source — loaded dynamically)
bframe_iframe = soup.find("iframe", src=re.compile(r"recaptcha.*bframe"))
if bframe_iframe:
result["bframe_url"] = bframe_iframe.get("src", "")
# Construct bframe URL from anchor parameters if not found
if not result["bframe_url"] and result["site_key"] and result["version"]:
result["bframe_url"] = (
f"https://www.google.com/recaptcha/api2/bframe?"
f"hl={result['language'] or 'en'}"
f"&v={result['version']}"
f"&k={result['site_key']}"
)
return result
iframes = extract_recaptcha_iframes("https://example.com/login")
print(f"Site key: {iframes['site_key']}")
print(f"Origin: {iframes['origin']}")
print(f"Anchor URL: {iframes['anchor_url']}")
الاستخراج باستخدام Node.js
المنطق نفسه في Node.js، مع axios وcheerio لقراءة سمة src:
const axios = require("axios");
const cheerio = require("cheerio");
const { URL } = require("url");
async function extractRecaptchaIframes(pageUrl) {
const { data: html } = await axios.get(pageUrl, {
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
},
timeout: 15000,
});
const $ = cheerio.load(html);
const result = {
anchorUrl: null,
bframeUrl: null,
siteKey: null,
origin: null,
version: null,
};
// Find anchor iframe
const anchorIframe = $("iframe[src*='recaptcha'][src*='anchor']");
if (anchorIframe.length) {
const src = anchorIframe.attr("src");
result.anchorUrl = src;
const url = new URL(src);
result.siteKey = url.searchParams.get("k");
result.version = url.searchParams.get("v");
// Decode origin
const co = url.searchParams.get("co");
if (co) {
try {
result.origin = Buffer.from(
co.replace(/\.$/, ""), "base64"
).toString();
} catch {}
}
}
// Construct bframe URL
if (result.siteKey && result.version) {
result.bframeUrl =
`https://www.google.com/recaptcha/api2/bframe?` +
`hl=en&v=${result.version}&k=${result.siteKey}`;
}
return result;
}
extractRecaptchaIframes("https://example.com/login").then(console.log);
الاستخراج من الصفحات الديناميكية باستخدام Selenium
حين يُحقن reCAPTCHA بعد رسم الصفحة، يلزمك متصفح فعلي مثل Selenium:
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
def extract_iframes_selenium(url):
"""Extract reCAPTCHA iframe URLs from a dynamically loaded page."""
driver = webdriver.Chrome()
driver.get(url)
time.sleep(3) # Wait for reCAPTCHA to load
result = {"anchor_url": None, "bframe_url": None}
# Find all iframes
iframes = driver.find_elements(By.TAG_NAME, "iframe")
for iframe in iframes:
src = iframe.get_attribute("src") or ""
if "recaptcha" in src and "anchor" in src:
result["anchor_url"] = src
elif "recaptcha" in src and "bframe" in src:
result["bframe_url"] = src
driver.quit()
return result
متى تحتاج فعلاً إلى رابطَي anchor وbframe؟
لا تحتاج معظم سير العمل إلى هذه الروابط لأن CaptchaAI API تطلب sitekey وpageurl فقط، لكنّ أربع حالات تجعل استخراجها مفيداً:
- التأكد من مفتاح الموقع الصحيح.
- تحديد إصدار reCAPTCHA.
- مطابقة الأصل في التطبيقات صارمة النطاق.
- تشخيص حالات فشل الحل.
تخيّل أداة أتمتة لبوابة حجوزات في السعودية تعرض reCAPTCHA v2 بنسختين في الصفحة: واحدة للنموذج العربي وأخرى للإنجليزي. هنا يميّز رابط anchor مفتاح الموقع الصحيح لكل نسخة قبل الإرسال.
1. التأكد من مفتاح الموقع الصحيح
عندما تحتوي الصفحة على عدة نسخ من reCAPTCHA أو يُحمَّل المفتاح ديناميكياً:
# Extract sitekey from anchor URL when it's not in the page HTML
iframes = extract_recaptcha_iframes(url)
sitekey = iframes["site_key"] # Reliably present in the iframe URL
2. تحديد إصدار reCAPTCHA
يكشف مسار الرابط النوع الدقيق قبل اختيار الحل:
# The anchor URL reveals the exact reCAPTCHA version
if "/api2/anchor" in anchor_url:
recaptcha_type = "v2"
elif "/enterprise/anchor" in anchor_url:
recaptcha_type = "enterprise"
3. مطابقة الأصل في التطبيقات صارمة النطاق
مرّر الأصل المفكوك بوصفه pageurl حين يفرض الموقع تطابق النطاق:
# Decode the origin from the co parameter
origin = decode_co_parameter(iframes["co"])
# Use this origin as the pageurl for the solver
4. تشخيص حالات فشل الحل
عند رفض الرموز، تكشف مقارنة معلمات anchor مع طلب الحل أي تعارض في مفتاح الموقع أو النطاق:
def debug_solve_params(anchor_url, solver_pageurl, solver_sitekey):
"""Compare anchor params with solver request to find mismatches."""
parsed = urlparse(anchor_url)
params = parse_qs(parsed.query)
issues = []
# Check sitekey
anchor_key = params.get("k", [None])[0]
if anchor_key != solver_sitekey:
issues.append(f"Sitekey mismatch: anchor={anchor_key}, solver={solver_sitekey}")
# Check origin
co = params.get("co", [None])[0]
if co:
origin = base64.b64decode(co.rstrip(".") + "==").decode()
solver_parsed = urlparse(solver_pageurl)
solver_origin = f"{solver_parsed.scheme}://{solver_parsed.netloc}"
if origin != solver_origin:
issues.append(f"Origin mismatch: anchor={origin}, solver={solver_origin}")
return issues if issues else ["No mismatches found"]
الطريقة القياسية والموصى بها للحل
تجاوز استخراج الإطارات واحصل على الرمز مباشرةً عبر CaptchaAI بمفتاح الموقع وعنوان الصفحة فقط:
import requests
import time
API_KEY = "YOUR_API_KEY"
# All you need: sitekey + pageurl
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": "6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp",
"pageurl": "https://example.com/login",
"json": 1,
})
task_id = submit.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}).json()
if result.get("status") == 1:
token = result["request"]
print(f"Token: {token[:50]}...")
break
- يكفي هذا المسار في معظم التكاملات.
- لا يلزم استخراج anchor أو bframe إلا حين يفشل الحل بسبب مشكلات في مفتاح الموقع أو النطاق.
الأسئلة الشائعة
هل يشترط CaptchaAI تمرير رابطَي anchor وbframe لحل reCAPTCHA؟
لا. تحتاج الخدمة إلى sitekey وpageurl فقط، وتتولّى داخلياً التفاعل مع الإطارين. استخراج الروابط مفيد للتشخيص لا للحل.
ما الفرق العملي بين إطار anchor وإطار bframe؟
الفارق في التوقيت ومحتوى كل إطار:
- anchor: ظاهر منذ تحميل الصفحة، ويضم مربع الاختيار "I'm not a robot" ومفتاح الموقع في رابطه.
- bframe: يُنشَأ لاحقاً بواسطة JavaScript عند النقر وظهور تحدي الصور، ولهذا لا تجده في شيفرة HTML الأولية وتحتاج إلى Selenium أو Puppeteer لالتقاط رابطه.
كيف أحصل على مفتاح الموقع عندما لا يظهر في شيفرة HTML؟
اقرأه من رابط anchor مباشرةً؛ فالمعلمة k موجودة فيه دائماً حتى عند تحميل المفتاح ديناميكياً. استخدم دالة extract_recaptcha_iframes أعلاه ثم مرّر القيمة بوصفها sitekey.
هل تختلف روابط reCAPTCHA Enterprise عن reCAPTCHA v2؟
نعم في المسار. يحمل reCAPTCHA v2 المسار /api2/anchor، بينما يستخدم Enterprise المسار /enterprise/anchor؛ وعليه يعتمد مثال تحديد الإصدار. وكلا النوعين مدعوم للحل عبر CaptchaAI.
الخلاصة
- يعتمد reCAPTCHA على إطارَي iframe: anchor لمربع الاختيار وbframe لتحدي الصور.
- يحمل رابط anchor مفتاح الموقع والأصل المشفّر وتجزئة الإصدار.
- للحل القياسي عبر CaptchaAI يكفيك
sitekeyوpageurlدون أي استخراج. - تبقى تقنيات الاستخراج أداتك عند تشخيص فشل التحقق من النطاق أو انتزاع المفاتيح من صفحات ديناميكية.
مقالات ذات صلة
- حل رد النداء في reCAPTCHA v2 عبر الـ API
- التعامل مع reCAPTCHA v2 وTurnstile في الموقع نفسه
- آلية رد النداء في reCAPTCHA v2