Bộ giải captcha Selenium bằng Python: ví dụ chạy được (2026)
Selenium chạy một trình duyệt thật, nên trang được render và các script chạy như khi có người dùng. Bước duy nhất nó không làm được là giải widget PopularCaptcha. Hướng dẫn này bổ sung bước đó: đọc sitekey từ trang đã render, lấy token bằng một lệnh gọi API, ghi token vào form, và gửi.
Nó bao quát widget PopularCaptcha, loại mà Scarnox giải hiện nay theo kiểu proxyless. Bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ và thử script trên một form thử nghiệm trước.
Selenium cần làm gì
Luồng có bốn phần:
- Tải trang và chờ widget được render.
- Đọc thuộc tính
data-sitekeytừ widget. - Lấy token từ API và đặt vào form.
- Gửi form trước khi token hết hạn.
Bước thứ ba là bước duy nhất chạm tới captcha. Mọi thứ khác là công việc Selenium bình thường.
Cài đặt gói
pip install selenium requests
Selenium 4.6 trở lên tự tìm ChromeDriver phù hợp, nên bạn không cần tải driver bằng tay.
Script đầy đủ
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
API_KEY = "scarnox_YOURAPIKEY"
API_URL = "https://api.scarnox.com/api/tasks/create"
PAGE_URL = "https://example.com/signup"
def solve(sitekey: str, page_url: str, invisible: bool = False) -> str:
body = {
"captcha_type": "PopularCaptchaTaskProxyless",
"site_key": sitekey,
"site_url": page_url,
}
if invisible:
body["is_invisible"] = True
r = requests.post(
API_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json=body,
timeout=185, # chặn cho đến khi token sẵn sàng
)
data = r.json()
if data.get("errorId") != 0:
raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
return data["solution"]["token"]
INJECT_TOKEN_JS = """
const token = arguments[0];
let field = document.querySelector('[name="h-captcha-response"]');
if (!field) {
field = document.createElement("textarea");
field.name = "h-captcha-response";
field.style.display = "none";
document.querySelector("form").appendChild(field);
}
field.value = token;
let extra = document.querySelector('[name="g-recaptcha-response"]');
if (!extra) {
extra = document.createElement("textarea");
extra.name = "g-recaptcha-response";
extra.style.display = "none";
document.querySelector("form").appendChild(extra);
}
extra.value = token;
"""
def main() -> None:
driver = webdriver.Chrome()
try:
driver.get(PAGE_URL)
widget = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "[data-sitekey]"))
)
sitekey = widget.get_attribute("data-sitekey")
invisible = widget.get_attribute("data-size") == "invisible"
token = solve(sitekey, driver.current_url, invisible=invisible)
# Điền các trường khác trước, rồi chèn token ngay trước khi gửi,
# vì token hết hạn sau khoảng hai phút.
driver.find_element(By.NAME, "email").send_keys("you@example.com")
driver.execute_script(INJECT_TOKEN_JS, token)
driver.find_element(By.CSS_SELECTOR, "form button[type=submit]").click()
WebDriverWait(driver, 15).until(EC.url_changes(PAGE_URL))
print("Submitted. Now at:", driver.current_url)
finally:
driver.quit()
if __name__ == "__main__":
main()
Script không cần proxy cho lần giải PopularCaptcha proxyless. Bỏ trường proxy và để trang thấy kết nối bình thường của bạn.
Thứ tự thao tác là phần hay sai nhất. Điền phần còn lại của form trước, rồi giải, rồi chèn, rồi click. Nếu bạn giải trước khi nhập vào các trường khác, một trang chậm hoặc form chậm có thể đẩy việc gửi vượt quá thời gian sống của token. Giữ khoảng cách giữa lần giải và lần click càng ngắn càng tốt, và kiểm tra trang kết quả có lỗi hay không trước khi cho rằng captcha đã qua.
Vì sao token được chèn bằng JavaScript
Hầu hết widget PopularCaptcha ghi token vào một textarea ẩn tên h-captcha-response khi một người giải chúng. Vì Selenium không có người, script tự ghi trường tương tự. Đoạn INJECT_TOKEN_JS làm hai việc:
- Nó tái sử dụng textarea nếu widget đã tạo ra một cái.
- Nó tạo textarea nếu trang chưa có, và gắn nó vào form.
Nó cũng điền g-recaptcha-response, vì nhiều trang đọc tên đó để tương thích.
Widget vô hình
Widget vô hình không có ô đánh dấu. Nó chạy ngầm và thường được kích hoạt khi gửi form. Script kiểm tra data-size="invisible" và gửi is_invisible: true khi thấy nó. Một số trang cũng gắn một callback JavaScript vào widget. Nếu form vẫn đứng yên sau khi bạn chèn token, hãy tìm thuộc tính data-callback và gọi hàm đó với token. Bài viết về captcha vô hình bao quát trường hợp này.
Dùng trong kiểm thử
Selenium cũng là công cụ thường dùng cho kiểm thử end-to-end. Nếu trang staging của bạn hiển thị captcha, cùng code này cho phép một bài kiểm thử vượt qua nó. Hãy giữ môi trường kiểm thử tách biệt với production, và đừng chạy trên các trang bạn không sở hữu. Thiết lập cho bộ kiểm thử nằm trong captcha trong kiểm thử tự động.
Các vấn đề thường gặp
- Widget không bao giờ xuất hiện. Tăng thời gian chờ, hoặc kiểm tra widget có nằm trong iframe không. Nếu có, chuyển sang frame trước bằng
driver.switch_to.frame(...). - Form được gửi nhưng trang từ chối token. Kiểm tra bạn đã gửi token tới trang nơi widget được hiển thị.
driver.current_urlphải khớp URL thật của trang, bao gồm mọi chuỗi truy vấn. - Token hết hạn. Đưa lệnh
solvegần bước gửi hơn. Token tồn tại khoảng hai phút. - Lỗi timeout từ API. Dùng timeout khoảng 185 giây, như trong script. Logic retry được bao quát trong xử lý lỗi khi giải captcha.
Giá
Bạn trả tiền theo mỗi lần giải thành công. Lần giải thất bại không bị tính phí. Xem giá hiện tại và bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ.