BLS CAPTCHA 显示图像网格,用户必须在其中选择或重新排序图像。本指南涵盖网格布局、响应格式以及如何正确提交解决方案。
BLS 网格挑战类型
图片排序
用户必须按特定顺序排列图像(例如,升序数字、字母顺序)。
图像选择
用户必须单击与描述匹配的特定图像(例如,“选择所有带有文本的图像”)。
模式匹配
用户必须识别哪些图像与呈现的图案或样本相匹配。
网格布局映射
# grid_mapping.py
# BLS grids typically use 3x3 or 4x4 layouts
# Each cell maps to an index:
# 3x3 grid:
# [0] [1] [2]
# [3] [4] [5]
# [6] [7] [8]
# 4x4 grid:
# [0] [1] [2] [3]
# [4] [5] [6] [7]
# [8] [9] [10] [11]
# [12] [13] [14] [15]
def grid_position(index, cols=3):
"""Convert flat index to row, column."""
return index // cols, index % cols
def index_from_position(row, col, cols=3):
"""Convert row, column to flat index."""
return row * cols + col
# Example: For a 3x3 grid, position (1, 2) = index 5
print(grid_position(5, cols=3)) # (1, 2)
print(index_from_position(1, 2)) # 5
解决 BLS 网格验证码问题
# solve_bls_grid.py
import requests
import time
import os
import json
def solve_bls_grid(sitekey, pageurl, instructions=None):
"""Solve a BLS grid CAPTCHA and get response indices."""
api_key = os.environ["CAPTCHAAI_API_KEY"]
payload = {
"key": api_key,
"method": "bls",
"sitekey": sitekey,
"pageurl": pageurl,
"json": 1,
}
if instructions:
payload["instructions"] = instructions
resp = requests.post(
"https://ocr.captchaai.com/in.php",
data=payload,
timeout=30,
)
result = resp.json()
if result.get("status") != 1:
raise RuntimeError(f"Submit failed: {result.get('request')}")
task_id = result["request"]
time.sleep(10)
for _ in range(30):
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key,
"action": "get",
"id": task_id,
"json": 1,
}, timeout=15)
data = resp.json()
if data.get("status") == 1:
return data["request"]
if data["request"] != "CAPCHA_NOT_READY":
raise RuntimeError(data["request"])
time.sleep(5)
raise TimeoutError("BLS grid solve timeout")
解析网格响应
# parse_response.py
import json
def parse_grid_response(solution):
"""Parse CaptchaAI BLS response into actionable grid data."""
# Solution may be JSON or comma-separated indices
if isinstance(solution, str):
try:
parsed = json.loads(solution)
return parsed
except json.JSONDecodeError:
pass
# Try comma-separated indices
if "," in solution:
return [int(x.strip()) for x in solution.split(",")]
# Single value
return [solution]
return solution
def format_for_submission(indices, grid_size=9):
"""Format indices for form submission."""
# Some sites expect a bitmask
bitmask = ["0"] * grid_size
for idx in indices:
if isinstance(idx, int) and 0 <= idx < grid_size:
bitmask[idx] = "1"
return {
"indices": indices,
"bitmask": "".join(bitmask),
"count": len(indices),
}
使用 Selenium 注入网格解决方案
# inject_grid.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
def click_grid_cells(driver, indices):
"""Click specific grid cells based on solution indices."""
wait = WebDriverWait(driver, 10)
# Find all grid cells
cells = wait.until(
EC.presence_of_all_elements_located(
(By.CSS_SELECTOR, ".captcha-grid .cell, .bls-grid img, .grid-item")
)
)
for idx in indices:
if isinstance(idx, int) and idx < len(cells):
cells[idx].click()
time.sleep(0.3) # Brief delay between clicks
def set_order_sequence(driver, ordered_indices):
"""Click grid cells in the correct order for ordering challenges."""
wait = WebDriverWait(driver, 10)
cells = wait.until(
EC.presence_of_all_elements_located(
(By.CSS_SELECTOR, ".captcha-grid .cell, .bls-grid img")
)
)
for idx in ordered_indices:
if isinstance(idx, int) and idx < len(cells):
cells[idx].click()
time.sleep(0.5) # Ordering needs pauses between clicks
def inject_hidden_response(driver, solution_value):
"""Set the solution in a hidden input field."""
driver.execute_script("""
var inputs = document.querySelectorAll(
'input[name*="captcha"], input[name*="response"], #captcha-answer'
);
for (var i = 0; i < inputs.length; i++) {
inputs[i].value = arguments[0];
}
""", str(solution_value))
完整的 BLS 网格流程
# full_flow.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def handle_bls_grid(driver, pageurl):
"""Complete BLS grid CAPTCHA handling."""
wait = WebDriverWait(driver, 15)
# Wait for CAPTCHA to load
captcha = wait.until(
EC.presence_of_element_located(
(By.CSS_SELECTOR, "[data-sitekey], .bls-captcha")
)
)
sitekey = captcha.get_attribute("data-sitekey")
# Get instructions
instructions = None
try:
inst = driver.find_element(By.CSS_SELECTOR, ".captcha-instructions")
instructions = inst.text.strip()
except Exception:
pass
# Solve via CaptchaAI
solution = solve_bls_grid(sitekey, pageurl, instructions)
parsed = parse_grid_response(solution)
# Determine response method
grid_cells = driver.find_elements(
By.CSS_SELECTOR, ".captcha-grid .cell, .bls-grid img"
)
if grid_cells:
# Click-based response
if isinstance(parsed, list) and all(isinstance(x, int) for x in parsed):
click_grid_cells(driver, parsed)
else:
inject_hidden_response(driver, solution)
else:
# Hidden input response
inject_hidden_response(driver, solution)
# Submit
submit = driver.find_element(
By.CSS_SELECTOR, "button[type='submit'], .submit-btn, #verify"
)
submit.click()
return True
故障排除
| 问题 | 原因 | 处理方式 |
|---|---|---|
| 点击错误的单元格 | 网格单元选择器不匹配 | 检查网格 HTML 并更新 CSS 选择器 |
| 订单被拒绝 | 点击速度太快 | 在点击之间添加 300-500 毫秒的延迟 |
| 解决方案格式不匹配 | 站点需要位掩码,已获得索引 | 使用format_for_submission()进行转换 |
| 网格未满载 | 图片加载缓慢 | 等待所有网格图像加载后再求解 |
常问问题
CaptchaAI如何知道网格布局?
CaptchaAI 从 BLS 服务器接收验证码质询并远程解决。您提供 sitekey 和 pageurl; API 处理网格分析。
如果我提交后网格发生变化怎么办?
一些 BLS 表格会在第一个挑战通过后显示第二个挑战。通过在提交后检查新的验证码元素来处理此问题。
我可以重复使用 BLS 网格解决方案吗?
不会。每个解决方案都与特定的挑战赛相关。始终解决新鲜事。
相关指南
- BLS CAPTCHA 参数深入探讨
- GeeTest 与 BLS 比较
应对 BLS 网格挑战 -以 CaptchaAI 开头.