Hướng Dẫn API

SOCKS5 Proxy + CaptchaAI: Hướng dẫn thiết lập và cấu hình

Câu trả lời ngắn: cấu hình SOCKS5 ở HTTP client hoặc trình duyệt để lấy trang, còn request tới CaptchaAI đi thẳng — trừ khi bạn cần token giải từ đúng IP, lúc đó thêm proxyproxytype=SOCKS5 vào in.php. Nhầm hai đường đi này là lý do phổ biến nhất khiến token hợp lệ mà form vẫn bị từ chối.

Bài này đi qua bốn tình huống thực tế khi làm QA hoặc thu thập dữ liệu web (scraping): requests, aiohttp, Selenium có xác thực proxy, và Puppeteer. Ví dụ dùng reCAPTCHA v2; khuôn mẫu tương tự áp dụng cho Cloudflare Turnstile.


Hai đường đi của request: trang đích và CaptchaAI

Luồng chuẩn gồm bốn bước:

  1. Gọi trang đích qua SOCKS5 để lấy HTML và sitekey.
  2. Gửi task tới in.php — mặc định không qua proxy.
  3. Polling res.php cho đến khi có token.
  4. Submit form qua đúng proxy đã dùng ở bước 1.

Bước 4 là nơi phần lớn tích hợp hỏng: tải trang qua proxy Singapore rồi submit từ IP Frankfurt thì token đúng cũng vô ích.


SOCKS5 khác proxy HTTP ở đâu

Proxy HTTP đọc và đôi khi viết lại request; SOCKS5 chỉ chuyển tiếp byte ở tầng TCP/UDP:

Tiêu chí Proxy HTTP/HTTPS Proxy SOCKS5
Giao thức hỗ trợ Chỉ HTTP/HTTPS Mọi luồng TCP/UDP
Can thiệp header Có thể thêm X-Forwarded-For Không sửa đổi
Dấu vết trong request Rõ hơn (header rò rỉ) Ít hơn
Tốc độ Nhanh Chậm hơn không đáng kể
Xác thực Basic/Digest Username/password
Phân giải DNS Phía client Phía máy chủ proxy (socks5h)
Hỗ trợ WebSocket Hạn chế Đầy đủ

Hai dòng đáng quan tâm nhất là DNSWebSocket. Widget CAPTCHA hiện đại hay mở WebSocket, thứ proxy HTTP xử lý nửa vời. Còn socks5:// phân giải tên miền trên máy bạn, socks5h:// đẩy sang proxy — chữ h cuối là chỗ sai âm thầm nhất.


Thiết lập trong Python

requests + PySocks

Cài phần mở rộng SOCKS cho requests trước:

pip install requests[socks] pysocks

Đoạn dưới gom cả bốn bước: lấy trang qua proxy, trích sitekey, gửi task, polling res.php, submit token.

import requests
import time

SOCKS5_HOST = "proxy.example.com"
SOCKS5_PORT = 1080
SOCKS5_USER = "proxyuser"
SOCKS5_PASS = "proxypass"

CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"

# SOCKS5 proxy configuration
proxies = {
    "http": f"socks5h://{SOCKS5_USER}:{SOCKS5_PASS}@{SOCKS5_HOST}:{SOCKS5_PORT}",
    "https": f"socks5h://{SOCKS5_USER}:{SOCKS5_PASS}@{SOCKS5_HOST}:{SOCKS5_PORT}",
}
# socks5h = DNS resolved by proxy server (recommended)
# socks5  = DNS resolved locally

def fetch_through_socks(url):
    """Fetch URL through SOCKS5 proxy."""
    return requests.get(
        url,
        proxies=proxies,
        headers={
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36"
        },
        timeout=30,
    )

def solve_captcha(site_url, sitekey):
    """Solve CAPTCHA via CaptchaAI (direct, no proxy needed)."""
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": site_url,
        "json": 1,
    })
    data = resp.json()
    if data["status"] != 1:
        raise Exception(f"Submit: {data['request']}")

    task_id = data["request"]

    for _ in range(60):
        time.sleep(5)
        resp = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY,
            "action": "get",
            "id": task_id,
            "json": 1,
        })
        data = resp.json()
        if data["request"] == "CAPCHA_NOT_READY":
            continue
        if data["status"] == 1:
            return data["request"]
        raise Exception(f"Solve: {data['request']}")

    raise TimeoutError("Timeout")

# Full workflow
resp = fetch_through_socks("https://staging.example.com/qa-form")

import re
match = re.search(r'data-sitekey="([^"]+)"', resp.text)
if match:
    token = solve_captcha("https://staging.example.com/qa-form", match.group(1))
    # Submit with token through same proxy
    resp = requests.post(
        "https://target.com/submit",
        data={"g-recaptcha-response": token},
        proxies=proxies,
    )

Vòng polling giới hạn 60 lần × 5 giây, tối đa 300 giây — đủ cho reCAPTCHA v2; với Turnstile có thể siết ngắn hơn.

aiohttp cho luồng bất đồng bộ

Khi chạy nhiều phiên song song, aiohttp_socks cắm connector SOCKS5 vào session:

import aiohttp
import aiohttp_socks
import asyncio

async def fetch_async(url):
    connector = aiohttp_socks.ProxyConnector.from_url(
        f"socks5://{SOCKS5_USER}:{SOCKS5_PASS}@{SOCKS5_HOST}:{SOCKS5_PORT}"
    )

    async with aiohttp.ClientSession(connector=connector) as session:
        async with session.get(url) as resp:
            return await resp.text()

asyncio.run(fetch_async("https://staging.example.com/qa-form"))

Số phiên song song nên bám theo số thread trong gói bạn dùng: BASIC ($15/tháng, 5 thread) cho phép 5 CAPTCHA giải cùng lúc, nên mở 50 coroutine chỉ khiến task xếp hàng chờ.


Selenium: chỗ xác thực proxy gây khó

Chrome không nhận username/password SOCKS5 qua cờ dòng lệnh. Vì vậy đoạn dưới có hai hàm: một cho proxy mở, một dùng Selenium Wire khi proxy cần xác thực.

from selenium import webdriver
from selenium.webdriver.common.by import By

def create_socks5_driver(host, port, username=None, password=None):
    options = webdriver.ChromeOptions()

    # SOCKS5 proxy (no auth via command line)
    options.add_argument(f"--proxy-server=socks5://{host}:{port}")

    # DNS through proxy
    options.add_argument("--host-resolver-rules=MAP * ~NOTFOUND, EXCLUDE 127.0.0.1")

    options.add_argument("")
    options.add_argument("--window-size=1920,1080")

    driver = webdriver.Chrome(options=options)
    return driver

# For authenticated SOCKS5, use seleniumwire
from seleniumwire import webdriver as sw_webdriver

def create_auth_socks5_driver():
    options = {
        "proxy": {
            "http": f"socks5h://{SOCKS5_USER}:{SOCKS5_PASS}@{SOCKS5_HOST}:{SOCKS5_PORT}",
            "https": f"socks5h://{SOCKS5_USER}:{SOCKS5_PASS}@{SOCKS5_HOST}:{SOCKS5_PORT}",
        }
    }

    chrome_options = sw_webdriver.ChromeOptions()
    chrome_options.add_argument("")

    return sw_webdriver.Chrome(
        seleniumwire_options=options,
        options=chrome_options,
    )

# Usage
driver = create_auth_socks5_driver()
driver.get("https://staging.example.com/qa-form")
time.sleep(3)

sitekey = driver.execute_script(
    "return document.querySelector('[data-sitekey]')?.getAttribute('data-sitekey')"
)

if sitekey:
    token = solve_captcha("https://staging.example.com/qa-form", sitekey)
    driver.execute_script(f"""
        document.querySelector('#g-recaptcha-response').value = '{token}';
    """)
    driver.find_element(By.CSS_SELECTOR, "form").submit()

driver.quit()

Nếu nhà cung cấp cho whitelist IP máy chủ, hãy chọn cách đó — bỏ hẳn được Selenium Wire.


Node.js với socks-proxy-agent

SocksProxyAgent gắn vào cả httpAgenthttpsAgent của axios. Chú ý comment trong code: request tới CaptchaAI cố ý không qua agent này.

const { SocksProxyAgent } = require("socks-proxy-agent");
const axios = require("axios");

const CAPTCHAAI_KEY = "YOUR_API_KEY";

const socksAgent = new SocksProxyAgent(
  "socks5h://proxyuser:[email protected]:1080"
);

async function fetchViaSocks(url) {
  return axios.get(url, {
    httpsAgent: socksAgent,
    httpAgent: socksAgent,
    headers: {
      "User-Agent":
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/126.0.0.0",
    },
  });
}

async function solveCaptcha(siteUrl, sitekey) {
  // CaptchaAI calls don't go through SOCKS proxy
  const submit = await axios.post(
    "https://ocr.captchaai.com/in.php",
    null,
    {
      params: {
        key: CAPTCHAAI_KEY,
        method: "userrecaptcha",
        googlekey: sitekey,
        pageurl: siteUrl,
        json: 1,
      },
    }
  );

  const taskId = submit.data.request;

  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));

    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: CAPTCHAAI_KEY, action: "get", id: taskId, json: 1 },
    });

    if (result.data.request === "CAPCHA_NOT_READY") continue;
    if (result.data.status === 1) return result.data.request;
  }

  throw new Error("Timeout");
}

Puppeteer

Puppeteer nhận proxy qua tham số khởi chạy, xác thực đi qua page.authenticate():

const puppeteer = require("puppeteer");

async function launchWithSocks5() {
  const browser = await puppeteer.launch({
    args: [
      "--proxy-server=socks5://proxy.example.com:1080",
      "--no-sandbox",
      "--window-size=1920,1080",
    ],
  });

  const page = await browser.newPage();

  // Authenticate if needed
  await page.authenticate({
    username: "proxyuser",
    password: "proxypass",
  });

  await page.goto("https://staging.example.com/qa-form", { waitUntil: "networkidle0" });

  const sitekey = await page.evaluate(() =>
    document.querySelector("[data-sitekey]")?.getAttribute("data-sitekey")
  );

  if (sitekey) {
    const token = await solveCaptcha(page.url(), sitekey);
    await page.evaluate((t) => {
      document.querySelector("#g-recaptcha-response").value = t;
    }, token);
  }

  await browser.close();
}

Một profile trình duyệt chỉ nên gắn một proxy trong suốt vòng đời. Muốn đổi lối ra mạng, đóng browser và mở phiên mới.


Truyền proxy SOCKS5 vào chính CaptchaAI

Với một số trang, token cần sinh ra từ cùng dải IP với phiên của bạn. CaptchaAI nhận proxy kèm task để giải khớp IP:

def solve_with_proxy(site_url, sitekey, proxy_url):
    """Pass proxy to CaptchaAI for IP-matched solving."""
    # Format: type:host:port:user:pass
    proxy_param = f"socks5:{SOCKS5_HOST}:{SOCKS5_PORT}:{SOCKS5_USER}:{SOCKS5_PASS}"

    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": site_url,
        "proxy": proxy_param,
        "proxytype": "SOCKS5",
        "json": 1,
    })

    data = resp.json()
    if data["status"] != 1:
        raise Exception(f"Submit: {data['request']}")

    task_id = data["request"]

    for _ in range(60):
        time.sleep(5)
        resp = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY, "action": "get",
            "id": task_id, "json": 1,
        })
        data = resp.json()
        if data["request"] != "CAPCHA_NOT_READY":
            return data["request"]

    raise TimeoutError("Timeout")

Định dạng là type:host:port:user:pass, proxytype viết hoa. Chỉ bật khi thật sự cần: proxy của bạn thành điểm nghẽn cho cả bước giải.


Ví dụ thực tế: đội QA ở TP.HCM kiểm thử form đăng ký đa vùng

Một công ty outsourcing tại TP.HCM chạy test hồi quy cho form đăng ký của khách hàng, form này hiện reCAPTCHA v2 khác nhau tùy vùng:

  • Mỗi vùng kiểm thử là một endpoint SOCKS5 riêng, khai báo trong biến môi trường của CI.
  • Test lấy trang qua socks5h://, trích sitekey, gửi task, rồi submit qua cùng proxy.
  • Chạy 5 kịch bản song song trên BASIC ($15/tháng, 5 thread), ghi thời gian giải theo vùng vào log.
  • Log chỉ lưu ID task, vùng và thời gian — không lưu dữ liệu cá nhân trong form. Cách này cũng khớp tinh thần Nghị định 13/2023/NĐ-CP: ghi đủ để truy vết, không ghi thừa.

Các đội theo dõi giá trên Shopee, Lazada, Tiki dùng đúng khuôn này, với rate limit đặt ở phía bạn.


Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
Connection refused Sai host hoặc cổng Kiểm tra máy chủ SOCKS5 còn chạy và cổng 1080 mở
Rò rỉ DNS Dùng socks5:// thay vì socks5h:// Đổi sang socks5h:// để proxy phân giải DNS
Xác thực thất bại Sai thông tin đăng nhập Kiểm tra nhanh bằng curl --socks5-hostname
Kết nối chậm Proxy ở quá xa Chọn điểm ra gần khu vực kiểm thử hơn
WebSocket lỗi Máy chủ SOCKS5 không hỗ trợ UDP Dùng máy chủ SOCKS5 có hỗ trợ UDP
Token hợp lệ nhưng form bị từ chối IP submit khác IP tải trang Submit qua đúng proxy đã dùng ở bước lấy trang

Câu hỏi thường gặp

socks5socks5h khác nhau thế nào?

socks5h để máy chủ proxy phân giải DNS, socks5 phân giải trên máy bạn. Hầu hết trường hợp hãy dùng socks5h để resolver nội bộ không lộ ra ngoài.

CaptchaAI có nhận proxy SOCKS5 trong request gửi task không?

Có. Truyền proxytype=SOCKS5 cùng proxy=socks5:host:port:user:pass vào in.php. Mặc định cứ để request tới CaptchaAI đi thẳng cho nhanh.

Dùng proxy có bị tính thêm phí không?

Không. CaptchaAI tính giá theo thread (số CAPTCHA giải đồng thời), không tính theo từng lần giải và không phụ thu theo loại CAPTCHA. Chi phí proxy là khoản riêng.

Bao nhiêu thread là đủ cho crawler của tôi?

Lấy số phiên chạy song song thực tế làm mốc: 5 phiên vừa với BASIC ($15/tháng, 5 thread), còn crawler chạy 30–50 luồng thì ADVANCE ($90/tháng, 50 thread) hợp hơn. Mỗi thread giải không giới hạn số CAPTCHA trong tháng.

Selenium báo lỗi xác thực proxy dù thông tin đăng nhập đúng?

Chrome không nhận username/password SOCKS5 qua --proxy-server. Dùng Selenium Wire như ví dụ ở trên, hoặc nhờ nhà cung cấp whitelist IP máy chủ.


Đọc tiếp


Lấy API key tại captchaai.com và chạy ví dụ Python trong bài với proxy của bạn.

Os comentários estão desativados para este artigo.