CAPSOLVER
Blog
Cách giải Captcha trên Maxun với tích hợp CapSolver

Cách giải Captcha trong Maxun với tích hợp CapSolver

Logo of CapSolver

Anh Tuan

Data Science Expert

21-Jan-2026

Trong trích xuất dữ liệu web, Maxun đang thu hút sự chú ý như một nền tảng mở mã nguồn, không cần lập trình, giúp các nhóm thu thập dữ liệu từ web dễ dàng hơn. Các quy trình dựa trên robot và SDK của nó cho phép cả lập trình viên và người dùng không chuyên xây dựng và duy trì các pipeline trích xuất dữ liệu mà không cần nỗ lực kỹ thuật lớn.

Tuy nhiên, nhiều trang web thực tế được bảo vệ bởi CAPTCHA, thường trở thành rào cản chính trong quá trình trích xuất dữ liệu. CapSolver hoạt động tốt cùng Maxun bằng cách xử lý các thách thức này ở cấp độ cơ sở hạ tầng. Với CapSolver, các robot Maxun có thể tiếp tục hoạt động trên các trang web có CAPTCHA một cách tin cậy hơn, kết hợp sự dễ sử dụng với khả năng trích xuất thực tế, sẵn sàng cho sản xuất.


Maxun là gì?

Maxun là một nền tảng trích xuất dữ liệu web mở mã nguồn, không cần lập trình, cho phép người dùng huấn luyện robot để trích xuất trang web mà không cần viết mã. Nó có giao diện trực quan để xây dựng robot, SDK mạnh mẽ để kiểm soát robot theo chương trình, và hỗ trợ triển khai trên đám mây và tự lưu trữ.

Tính năng chính của Maxun

  • Trình xây dựng robot không cần lập trình: Giao diện trực quan để huấn luyện robot trích xuất dữ liệu mà không cần lập trình
  • SDK mạnh mẽ: SDK TypeScript/Node.js để điều khiển robot theo chương trình
  • Nhiều chế độ trích xuất: Khả năng trích xuất, trích xuất, duyệt và tìm kiếm
  • Chọn phần tử thông minh: Phát hiện tự động các phần tử và tạo các lựa chọn thông minh
  • Đám mây & Tự lưu trữ: Triển khai trên Maxun Cloud hoặc cơ sở hạ tầng của bạn
  • Hỗ trợ proxy: Quản lý và quay proxy tích hợp
  • Chạy theo lịch trình: Tự động hóa việc chạy robot với lịch trình dựa trên cron

Các lớp SDK chính

Lớp Mô tả
Trích xuất Xây dựng các quy trình trích xuất dữ liệu có cấu trúc với LLM hoặc các lựa chọn CSS
Trích xuất trang web Chuyển trang web thành Markdown, HTML hoặc hình ảnh chụp màn hình sạch sẽ
Duyệt trang web Tự động phát hiện và trích xuất nhiều trang bằng sitemap và liên kết
Tìm kiếm Thực hiện tìm kiếm web và trích xuất nội dung từ kết quả (DuckDuckGo)

Điều gì làm cho Maxun khác biệt

Maxun cầu nối khoảng cách giữa sự đơn giản không cần lập trình và sự linh hoạt cho lập trình viên:

  • Giao diện trực quan + Mã hóa: Huấn luyện robot trực quan, sau đó điều khiển chúng theo chương trình qua SDK
  • Kiến trúc dựa trên robot: Mẫu trích xuất có thể tái sử dụng và chia sẻ
  • Tương thích TypeScript: Xây dựng cho các ứng dụng Node.js hiện đại
  • Mã nguồn mở: Minh bạch toàn diện và phát triển dựa trên cộng đồng

CapSolver là gì?

CapSolver là một dịch vụ giải CAPTCHA hàng đầu cung cấp các giải pháp dựa trên AI để vượt qua các thách thức CAPTCHA khác nhau. Với sự hỗ trợ cho nhiều loại CAPTCHA và thời gian phản hồi nhanh chóng, CapSolver tích hợp dễ dàng vào các quy trình tự động hóa.

Các loại CAPTCHA được hỗ trợ

CapSolver giúp các quy trình tự động hóa xử lý hầu hết các CAPTCHA và cơ chế xác minh chính thống thường gặp trong trích xuất web và tự động hóa trình duyệt, bao gồm:

Tại sao tích hợp CapSolver với Maxun?

Khi xây dựng robot Maxun tương tác với các trang web được bảo vệ—dù là trích xuất dữ liệu, theo dõi giá, hay nghiên cứu thị trường—các thách thức CAPTCHA trở thành rào cản lớn. Dưới đây là lý do tại sao tích hợp quan trọng:

  1. Trích xuất dữ liệu liên tục: Robot có thể hoàn thành nhiệm vụ mà không cần can thiệp thủ công
  2. Thao tác có thể mở rộng: Xử lý các thách thức CAPTCHA trên nhiều lần thực thi robot song song
  3. Quy trình liền mạch: Giải CAPTCHA như một phần của pipeline trích xuất của bạn
  4. Hiệu quả về chi phí: Chỉ thanh toán cho các CAPTCHA được giải thành công
  5. Tỷ lệ thành công cao: Độ chính xác hàng đầu trong tất cả các loại CAPTCHA được hỗ trợ

Cài đặt

Yêu cầu

  • Node.js 18 hoặc cao hơn
  • npm hoặc yarn
  • Một khóa API CapSolver

Cài đặt SDK Maxun

bash Copy
# Cài đặt SDK Maxun
npm install maxun-sdk

# Cài đặt các phụ thuộc bổ sung cho tích hợp CapSolver
npm install axios

Cài đặt Docker (Maxun tự lưu trữ)

bash Copy
# Sao chép kho lưu trữ Maxun
git clone https://github.com/getmaxun/maxun.git
cd maxun

# Chạy bằng Docker Compose
docker-compose up -d

Thiết lập môi trường

Tạo một tệp .env với cấu hình của bạn:

env Copy
CAPSOLVER_API_KEY=your_capsolver_api_key
MAXUN_API_KEY=your_maxun_api_key

# Đối với Maxun Cloud (app.maxun.dev)
MAXUN_BASE_URL=https://app.maxun.dev/api/sdk

# Đối với Maxun tự lưu trữ (mặc định)
# MAXUN_BASE_URL=http://localhost:8080/api/sdk

Lưu ý: Cấu hình baseUrl là bắt buộc khi sử dụng Maxun Cloud. Các cài đặt tự lưu trữ mặc định là http://localhost:8080/api/sdk.


Tạo dịch vụ CapSolver cho Maxun

Dưới đây là một dịch vụ TypeScript có thể tái sử dụng tích hợp CapSolver với Maxun:

Dịch vụ CapSolver cơ bản

typescript Copy
import axios, { AxiosInstance } from 'axios';

interface TaskResult {
  gRecaptchaResponse?: string;
  token?: string;
  cookies?: Array<{ name: string; value: string }>;
  userAgent?: string;
}

interface CapSolverConfig {
  apiKey: string;
  timeout?: number;
  maxAttempts?: number;
}

class CapSolverService {
  private client: AxiosInstance;
  private apiKey: string;
  private maxAttempts: number;

  constructor(config: CapSolverConfig) {
    this.apiKey = config.apiKey;
    this.maxAttempts = config.maxAttempts || 60;

    this.client = axios.create({
      baseURL: 'https://api.capsolver.com',
      timeout: config.timeout || 30000,
      headers: { 'Content-Type': 'application/json' },
    });
  }

  private async createTask(taskData: Record<string, unknown>): Promise<string> {
    const response = await this.client.post('/createTask', {
      clientKey: this.apiKey,
      task: taskData,
    });

    if (response.data.errorId !== 0) {
      throw new Error(`Lỗi CapSolver: ${response.data.errorDescription}`);
    }

    return response.data.taskId;
  }

  private async getTaskResult(taskId: string): Promise<TaskResult> {
    for (let attempt = 0; attempt < this.maxAttempts; attempt++) {
      await this.delay(2000);

      const response = await this.client.post('/getTaskResult', {
        clientKey: this.apiKey,
        taskId,
      });

      const { status, solution, errorDescription } = response.data;

      if (status === 'ready') {
        return solution as TaskResult;
      }

      if (status === 'failed') {
        throw new Error(`Nhiệm vụ thất bại: ${errorDescription}`);
      }
    }

    throw new Error('Hết thời gian chờ giải CAPTCHA');
  }

  private delay(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  async solveReCaptchaV2(websiteUrl: string, websiteKey: string): Promise<string> {
    const taskId = await this.createTask({
      type: 'ReCaptchaV2TaskProxyLess',
      websiteURL: websiteUrl,
      websiteKey,
    });

    const solution = await this.getTaskResult(taskId);
    return solution.gRecaptchaResponse || '';
  }

  async solveReCaptchaV3(
    websiteUrl: string,
    websiteKey: string,
    pageAction: string = 'submit'
  ): Promise<string> {
    const taskId = await this.createTask({
      type: 'ReCaptchaV3TaskProxyLess',
      websiteURL: websiteUrl,
      websiteKey,
      pageAction,
    });

    const solution = await this.getTaskResult(taskId);
    return solution.gRecaptchaResponse || '';
  }

  async solveTurnstile(
    websiteUrl: string,
    websiteKey: string,
    action?: string,
    cdata?: string
  ): Promise<string> {
    const taskData: Record<string, unknown> = {
      type: 'AntiTurnstileTaskProxyLess',
      websiteURL: websiteUrl,
      websiteKey,
    };

    // Thêm thông tin tùy chọn
    if (action || cdata) {
      taskData.metadata = {};
      if (action) (taskData.metadata as Record<string, string>).action = action;
      if (cdata) (taskData.metadata as Record<string, string>).cdata = cdata;
    }

    const taskId = await this.createTask(taskData);
    const solution = await this.getTaskResult(taskId);
    return solution.token || '';
  }

  async checkBalance(): Promise<number> {
    const response = await this.client.post('/getBalance', {
      clientKey: this.apiKey,
    });

    return response.data.balance || 0;
  }
}

export { CapSolverService, CapSolverConfig, TaskResult };

★ Gợi ý ─────────────────────────────────────
Dịch vụ CapSolver sử dụng mẫu polling (getTaskResult) vì việc giải CAPTCHA là bất đồng bộ—API chấp nhận một nhiệm vụ, xử lý nó trên máy chủ của họ, và trả về kết quả khi sẵn sàng. Khoảng thời gian 2 giây giữa các lần kiểm tra cân bằng giữa tính phản hồi và giới hạn tần suất API.
─────────────────────────────────────────────────


Giải các loại CAPTCHA khác nhau

reCAPTCHA v2 với Maxun

Vì Maxun hoạt động ở cấp độ cao hơn so với tự động hóa trình duyệt, cách tích hợp tập trung vào việc giải CAPTCHA trước hoặc trong khi thực thi robot:

typescript Copy
import { Trích xuất } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const CAPSOLVER_API_KEY = process.env.CAPSOLVER_API_KEY!;
const MAXUN_API_KEY = process.env.MAXUN_API_KEY!;
const MAXUN_BASE_URL = process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk';

const capSolver = new CapSolverService({ apiKey: CAPSOLVER_API_KEY });
const extractor = new Trích xuất({
  apiKey: MAXUN_API_KEY,
  baseUrl: MAXUN_BASE_URL,
});

async function trích xuấtVớiReCaptchaV2() {
  const targetUrl = 'https://example.com/trang-bảo-mật';
  const reCAPTCHA_siteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC';

  console.log('Giải reCAPTCHA v2...');

  // Giải CAPTCHA trước tiên
  const token = await capSolver.solveReCaptchaV2(targetUrl, reCAPTCHA_siteKey);

  console.log('CAPTCHA đã được giải, tạo robot trích xuất...');

  // Tạo robot bằng cách chuỗi phương thức
  const robot = await extractor
    .tạo('Trình trích xuất sản phẩm')
    .điều hướng(targetUrl)
    .nhập('#g-recaptcha-response', token)
    .nhấn('nút[type="submit"]')
    .chờ(2000)
    .thu-thập-danh-sách({ selector: '.sản-phẩm' });

  // Chạy robot
  const kết_quả = await robot.chạy({ timeout: 30000 });

  console.log('Trích xuất hoàn tất:', kết_quả.dữ_liệu);
  return kết_quả.dữ_liệu;
}

trích xuấtVớiReCaptchaV2().catch(console.error);

reCAPTCHA v3 với Maxun

typescript Copy
import { Trích xuất } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const CAPSOLVER_API_KEY = process.env.CAPSOLVER_API_KEY!;
const MAXUN_API_KEY = process.env.MAXUN_API_KEY!;
const MAXUN_BASE_URL = process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk';

const capSolver = new CapSolverService({ apiKey: CAPSOLVER_API_KEY });
const extractor = new Trích xuất({
  apiKey: MAXUN_API_KEY,
  baseUrl: MAXUN_BASE_URL,
});

async function trích xuấtVớiReCaptchaV3() {
  const targetUrl = 'https://example.com/v3-bảo-mật';
  const reCAPTCHA_siteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDEF';

  console.log('Giải reCAPTCHA v3 với điểm số cao...');

  // Giải với hành động trang tùy chỉnh
  const token = await capSolver.solveReCaptchaV3(
    targetUrl,
    reCAPTCHA_siteKey,
    'submit'  // hành động trang
  );

  console.log('Token đã được nhận với điểm số cao, tạo robot...');

  // Tạo robot trích xuất bằng cách chuỗi phương thức
  const robot = await extractor
    .tạo('Trình trích xuất bảo vệ v3')
    .điều hướng(targetUrl)
    .nhập('input[name="g-recaptcha-response"]', token)
    .nhấn('#nút-gửi')
    .chờ(2000)
    .thu-thập-text({ kết_quả: '.kết_quả' });

  const kết_quả = await robot.chạy({ timeout: 30000 });

  console.log('Dữ liệu trích xuất:', kết_quả.dữ_liệu);
  return kết_quả.dữ_liệu;
}

trích xuấtVớiReCaptchaV3().catch(console.error);

Cloudflare Turnstile với Maxun

typescript Copy
import { Trích xuất } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const CAPSOLVER_API_KEY = process.env.CAPSOLVER_API_KEY!;
const MAXUN_API_KEY = process.env.MAXUN_API_KEY!;
const MAXUN_BASE_URL = process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk';

const capSolver = new CapSolverService({ apiKey: CAPSOLVER_API_KEY });
const scraper = new Trích xuất({
  apiKey: MAXUN_API_KEY,
  baseUrl: MAXUN_BASE_URL,
});

async function trích xuấtVớiTurnstile() {
  const targetUrl = 'https://example.com/turnstile-bảo-mật';
  const turnstile_siteKey = '0x4xxxxxxxxxxxxxxxxxxxxxxxxxxxxGHI';

  console.log('Giải Cloudflare Turnstile...');

  // Giải với thông tin tùy chọn (action và cdata)
  const token = await capSolver.solveTurnstile(
    targetUrl,
    turnstile_siteKey,
    'đăng nhập',                              // hành động tùy chọn
    '0000-1111-2222-3333-thông-tin-cdata'  // thông tin cdata tùy chọn
  );

  console.log('Turnstile đã được giải, tạo robot trích xuất...');

  // Tạo robot trích xuất - đối với Turnstile, chúng ta thường cần
  // gửi token qua yêu cầu POST trước, sau đó trích xuất
  const robot = await scraper.tạo('trình-trích-xuất-turnstile', targetUrl, {
    định_dạng: ['markdown', 'html'],
  });

  const kết_quả = await robot.chạy({ timeout: 30000 });

  console.log('Trích xuất hoàn tất');
  console.log('Markdown:', kết_quả.dữ_liệu.markdown?.substring(0, 500));
  return kết_quả.dữ_liệu;
}

trích xuấtVớiTurnstile().catch(console.error);

Tích hợp với quy trình Maxun

Sử dụng với lớp Trích xuất

Lớp Trích xuất được sử dụng để trích xuất dữ liệu có cấu trúc từ các phần tử trang cụ thể. Nó hỗ trợ trích xuất được hỗ trợ bởi LLM (dùng lời nhắc ngôn ngữ tự nhiên) và trích xuất không LLM (dùng các lựa chọn CSS):

typescript Copy
import { Trích xuất } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const capSolver = new CapSolverService({ apiKey: process.env.CAPSOLVER_API_KEY! });
const extractor = new Trích xuất({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk',
});

interface DữLiệuSảnPhẩm {
  tên: string;
  giá: string;
  đánh_giá: string;
}

async function trích xuấtSảnPhẩmVớiCaptcha(): Promise<DữLiệuSảnPhẩm[]> {
const targetUrl = 'https://example.com/products';
  const siteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC';

  // Giải CAPTCHA trước
  const captchaToken = await capSolver.solveReCaptchaV2(targetUrl, siteKey);

  console.log('CAPTCHA đã được giải, tạo robot trích xuất...');

  // Tạo robot trích xuất bằng cách kế thừa phương thức
  const robot = await extractor
    .create('Trình trích xuất sản phẩm')
    .navigate(targetUrl)
    .type('#g-recaptcha-response', captchaToken)
    .click('button[type="submit"]')
    .wait(3000)
    .captureList({
      selector: '.product-card',
      pagination: { type: 'clickNext', selector: '.next-page' },
      maxItems: 50,
    });

  // Chạy trích xuất
  const result = await robot.run({ timeout: 60000 });

  return result.data.listData as ProductData[];
}

extractProductsWithCaptcha()
  .then((products) => {
    products.forEach((product) => {
      console.log(`${product.name}: ${product.price}`);
    });
  })
  .catch(console.error);

★ Insight ─────────────────────────────────────
Phương thức captureList trong lớp Extract của Maxun tự động phát hiện các trường trong các mục danh sách và xử lý phân trang. Khi bạn chỉ định loại phân trang (scrollDown, clickNext, hoặc clickLoadMore), robot sẽ tiếp tục trích xuất cho đến khi đạt giới hạn của bạn hoặc hết trang.
─────────────────────────────────────────────────

Sử dụng với lớp Scrape

Lớp Scrape chuyển trang web thành HTML sạch, Markdown phù hợp với LLM, hoặc hình ảnh chụp màn hình:

typescript Copy
import { Scrape } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';
import axios from 'axios';

const capSolver = new CapSolverService({ apiKey: process.env.CAPSOLVER_API_KEY! });
const scraper = new Scrape({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk',
});

interface ScrapeResult {
  url: string;
  markdown?: string;
  html?: string;
  captchaSolved: boolean;
}

async function scrapeWithCaptchaHandling(): Promise<ScrapeResult[]> {
  const urls = [
    'https://example.com/page1',
    'https://example.com/page2',
    'https://example.com/page3',
  ];

  const results: ScrapeResult[] = [];

  for (const url of urls) {
    try {
      // Đối với các trang bị CAPTCHA, giải trước và thiết lập phiên
      const siteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC'; // Lấy động nếu cần

      console.log(`Giải CAPTCHA cho ${url}...`);
      const captchaToken = await capSolver.solveReCaptchaV2(url, siteKey);

      // Gửi CAPTCHA để nhận cookie phiên
      const verifyResponse = await axios.post(`${url}/verify`, {
        'g-recaptcha-response': captchaToken,
      });

      // Tạo robot ghi chú cho trang đã xác thực
      const robot = await scraper.create(`scraper-${Date.now()}`, url, {
        formats: ['markdown', 'html'],
      });

      const result = await robot.run({ timeout: 30000 });

      results.push({
        url,
        markdown: result.data.markdown,
        html: result.data.html,
        captchaSolved: true,
      });

      // Dọn dẹp - xóa robot sau khi sử dụng
      await robot.delete();

    } catch (error) {
      console.error(`Không thể ghi chú ${url}:`, error);
      results.push({ url, captchaSolved: false });
    }
  }

  return results;
}

scrapeWithCaptchaHandling().then(console.log).catch(console.error);

Sử dụng với lớp Crawl

Lớp Crawl tự động phát hiện và ghi chú nhiều trang bằng cách sử dụng sitemap và theo dõi liên kết:

typescript Copy
import { Crawl } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';
import axios from 'axios';

const capSolver = new CapSolverService({ apiKey: process.env.CAPSOLVER_API_KEY! });
const crawler = new Crawl({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk',
});

interface PageResult {
  url: string;
  title: string;
  text: string;
  wordCount: number;
}

async function crawlWithCaptchaProtection(): Promise<PageResult[]> {
  const startUrl = 'https://example.com';
  const siteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC';

  // Giải CAPTCHA cho miền trước
  console.log('Giải CAPTCHA để truy cập miền...');
  const captchaToken = await capSolver.solveReCaptchaV2(startUrl, siteKey);

  // Gửi CAPTCHA để thiết lập phiên (tùy theo miền)
  await axios.post(`${startUrl}/verify`, {
    'g-recaptcha-response': captchaToken,
  });

  // Tạo robot ghi chú với cấu hình theo miền
  const robot = await crawler.create('site-crawler', startUrl, {
    mode: 'domain',           // Phạm vi ghi chú: 'domain', 'subdomain', hoặc 'path'
    limit: 50,                // Số trang tối đa để ghi chú
    maxDepth: 3,              // Sâu tối đa để theo dõi liên kết
    useSitemap: true,         // Phân tích sitemap.xml để lấy URL
    followLinks: true,        // Trích xuất và theo dõi liên kết trang
    includePaths: ['/blog/', '/docs/'],  // Mẫu regex để bao gồm
    excludePaths: ['/admin/', '/login/'], // Mẫu regex để loại trừ
    respectRobots: true,      // Tôn trọng robots.txt
  });

  // Chạy ghi chú
  const result = await robot.run({ timeout: 120000 });

  // Mỗi trang trong kết quả chứa: metadata, html, text, wordCount, links
  return result.data.crawlData.map((page: any) => ({
    url: page.metadata.url,
    title: page.metadata.title,
    text: page.text,
    wordCount: page.wordCount,
  }));
}

crawlWithCaptchaProtection()
  .then((pages) => {
    console.log(`Đã ghi chú ${pages.length} trang`);
    pages.forEach((page) => {
      console.log(`- ${page.title}: ${page.url} (${page.wordCount} từ)`);
    });
  })
  .catch(console.error);

Mẫu Xác thực Trước

Đối với các trang yêu cầu CAPTCHA trước khi truy cập nội dung, sử dụng quy trình xác thực trước:

typescript Copy
import axios from 'axios';
import { Extract } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const capSolver = new CapSolverService({ apiKey: process.env.CAPSOLVER_API_KEY! });
const extractor = new Extract({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk',
});

interface SessionCookies {
  name: string;
  value: string;
  domain: string;
}

async function preAuthenticateWithCaptcha(
  loginUrl: string,
  siteKey: string
): Promise<SessionCookies[]> {
  // Bước 1: Giải CAPTCHA
  const captchaToken = await capSolver.solveReCaptchaV2(loginUrl, siteKey);

  // Bước 2: Gửi token CAPTCHA để nhận cookie phiên
  const response = await axios.post(
    loginUrl,
    {
      'g-recaptcha-response': captchaToken,
    },
    {
      withCredentials: true,
      maxRedirects: 0,
      validateStatus: (status) => status < 400,
    }
  );

  // Bước 3: Trích xuất cookie từ phản hồi
  const setCookies = response.headers['set-cookie'] || [];
  const cookies: SessionCookies[] = setCookies.map((cookie: string) => {
    const [nameValue] = cookie.split(';');
    const [name, value] = nameValue.split('=');
    return {
      name: name.trim(),
      value: value.trim(),
      domain: new URL(loginUrl).hostname,
    };
  });

  return cookies;
}

async function extractWithPreAuth() {
  const loginUrl = 'https://example.com/verify';
  const targetUrl = 'https://example.com/protected-data';
  const siteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC';

  // Xác thực trước để nhận cookie phiên
  const sessionCookies = await preAuthenticateWithCaptcha(loginUrl, siteKey);

  console.log('Phiên đã thiết lập, tạo robot trích xuất...');

  // Tạo robot trích xuất bằng cách kế thừa phương thức
  // Lưu ý: Sử dụng setCookies() để truyền cookie phiên đã xác thực
  const robot = await extractor
    .create('Trình trích xuất đã xác thực')
    .setCookies(sessionCookies)
    .navigate(targetUrl)
    .wait(2000)
    .captureText({ content: '.protected-content' });

  // Chạy trích xuất
  const result = await robot.run({ timeout: 30000 });

  return result.data;
}

extractWithPreAuth().then(console.log).catch(console.error);

★ Insight ─────────────────────────────────────
Mẫu xác thực trước tách biệt việc giải CAPTCHA khỏi việc trích xuất dữ liệu. Điều này đặc biệt hữu ích với Maxun vì nó hoạt động ở mức trừu tượng cao hơn—thay vì chèn token vào DOM, bạn thiết lập phiên đã xác thực trước, sau đó để robot của Maxun làm việc trong phiên đó.
─────────────────────────────────────────────────


Chạy Nhiều Robot Song Song Với Xử Lý CAPTCHA

Xử lý CAPTCHA trên nhiều phiên robot song song:

typescript Copy
import { Scrape } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const capSolver = new CapSolverService({ apiKey: process.env.CAPSOLVER_API_KEY! });
const scraper = new Scrape({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk',
});

interface ExtractionJob {
  url: string;
  siteKey?: string;
}

interface ExtractionResult {
  url: string;
  data: { markdown?: string; html?: string };
  captchaSolved: boolean;
  duration: number;
}

async function processJob(job: ExtractionJob): Promise<ExtractionResult> {
  const startTime = Date.now();

  let captchaSolved = false;

  // Giải CAPTCHA nếu có site key
  if (job.siteKey) {
    console.log(`Giải CAPTCHA cho ${job.url}...`);
    const token = await capSolver.solveReCaptchaV2(job.url, job.siteKey);
    captchaSolved = true;
    // Token sẽ được gửi để thiết lập phiên trước khi ghi chú
  }

  // Tạo và chạy robot ghi chú
  const robot = await scraper.create(`scraper-${Date.now()}`, job.url, {
    formats: ['markdown', 'html'],
  });

  const result = await robot.run({ timeout: 30000 });

  // Dọn dẹp robot sau khi sử dụng
  await robot.delete();

  return {
    url: job.url,
    data: {
      markdown: result.data.markdown,
      html: result.data.html,
    },
    captchaSolved,
    duration: Date.now() - startTime,
  };
}

async function runParallelExtractions(
  jobs: ExtractionJob[],
  concurrency: number = 5
): Promise<ExtractionResult[]> {
  const results: ExtractionResult[] = [];
  const chunks: ExtractionJob[][] = [];

  // Chia công việc thành các khối để kiểm soát độ đồng thời
  for (let i = 0; i < jobs.length; i += concurrency) {
    chunks.push(jobs.slice(i, i + concurrency));
  }

  for (const chunk of chunks) {
    const chunkResults = await Promise.all(chunk.map(processJob));
    results.push(...chunkResults);
  }

  return results;
}

// Ví dụ sử dụng
const jobs: ExtractionJob[] = [
  { url: 'https://site1.com/data', siteKey: '6Lc...' },
  { url: 'https://site2.com/data' },
  { url: 'https://site3.com/data', siteKey: '6Lc...' },
  // ... nhiều công việc hơn
];

runParallelExtractions(jobs, 5)
  .then((results) => {
    const solved = results.filter((r) => r.captchaSolved).length;
    console.log(`Hoàn thành ${results.length} trích xuất, giải được ${solved} CAPTCHA`);

    results.forEach((r) => {
      console.log(`${r.url}: ${r.duration}ms`);
    });
  })
  .catch(console.error);

Các Nguyên Tắc Tốt

1. Xử Lý Lỗi Với Thử Lại

typescript Copy
async function solveWithRetry<T>(
  solverFn: () => Promise<T>,
  maxRetries: number = 3
): Promise<T> {
  let lastError: Error | undefined;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await solverFn();
    } catch (error) {
      lastError = error as Error;
      console.warn(`Lần thử ${attempt + 1} thất bại: ${lastError.message}`);

      // Tái thử theo cấp số nhân
      await new Promise((resolve) =>
        setTimeout(resolve, Math.pow(2, attempt) * 1000)
      );
    }
  }

  throw new Error(`Đã vượt quá số lần thử lại: ${lastError?.message}`);
}

// Sử dụng
const token = await solveWithRetry(() =>
  capSolver.solveReCaptchaV2(url, siteKey)
);

2. Quản Lý Số Dư

typescript Copy
async function ensureSufficientBalance(minBalance: number = 1.0): Promise<void> {
  const balance = await capSolver.checkBalance();

  if (balance < minBalance) {
    throw new Error(
      `Số dư CapSolver không đủ: $${balance.toFixed(2)}. Vui lòng nạp tiền.`
    );
  }

  console.log(`Số dư CapSolver: $${balance.toFixed(2)}`);
}

// Kiểm tra số dư trước khi bắt đầu công việc trích xuất
await ensureSufficientBalance(5.0);

3. Lưu Trữ Token

typescript Copy
interface CachedToken {
  token: string;
  timestamp: number;
}

class TokenCache {
  private cache = new Map<string, CachedToken>();
  private ttlMs: number;

  constructor(ttlSeconds: number = 90) {
    this.ttlMs = ttlSeconds * 1000;
  }

  private getKey(domain: string, siteKey: string): string {
    return `${domain}:${siteKey}`;
  }

  get(domain: string, siteKey: string): string | null {
    const key = this.getKey(domain, siteKey);
    const cached = this.cache.get(key);

    if (!cached) return null;

    if (Date.now() - cached.timestamp > this.ttlMs) {
      this.cache.delete(key);
      return null;
    }

    return cached.token;
  }

  set(domain: string, siteKey: string, token: string): void {
    const key = this.getKey(domain, siteKey);
    this.cache.set(key, { token, timestamp: Date.now() });
  }
}

const tokenCache = new TokenCache(90);

async function getCachedOrSolve(
  url: string,
  siteKey: string
): Promise<string> {
  const domain = new URL(url).hostname;

  const cached = tokenCache.get(domain, siteKey);
  if (cached) {
    console.log('Sử dụng token đã lưu');
    return cached;
  }

  const token = await capSolver.solveReCaptchaV2(url, siteKey);
  tokenCache.set(domain, siteKey, token);

  return token;
}

Các Tùy Chọn Cấu Hình

Maxun hỗ trợ cấu hình thông qua biến môi trường và tùy chọn SDK:

Cài đặt Mô tả Mặc định
MAXUN_API_KEY Mã API Maxun của bạn -
MAXUN_BASE_URL URL cơ sở API Maxun http://localhost:8080/api/sdk (tự host) hoặc https://app.maxun.dev/api/sdk (đám mây)
CAPSOLVER_API_KEY Mã API CapSolver của bạn -
CAPSOLVER_TIMEOUT Thời gian chờ yêu cầu tính bằng ms 30000
CAPSOLVER_MAX_ATTEMPTS Số lần thử tối đa 60

Cấu Hình SDK

typescript Copy
import { Extract, Scrape, Crawl, Search } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

// Đối với Maxun Cloud (app.maxun.dev)
const MAXUN_BASE_URL = 'https://app.maxun.dev/api/sdk';

// Đối với Maxun tự host (mặc định)
// const MAXUN_BASE_URL = 'http://localhost:8080/api/sdk';

// Cấu hình các module SDK Maxun
const extractor = new Extract({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: MAXUN_BASE_URL,
});
const scraper = new Scrape({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: MAXUN_BASE_URL,
});
const crawler = new Crawl({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: MAXUN_BASE_URL,
});
const searcher = new Search({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: MAXUN_BASE_URL,
});

// Cấu hình CapSolver
const capSolver = new CapSolverService({

Tuyên bố Tuân thủ: Thông tin được cung cấp trên blog này chỉ mang tính chất tham khảo. CapSolver cam kết tuân thủ tất cả các luật và quy định hiện hành. Việc sử dụng mạng lưới CapSolver cho các hoạt động bất hợp pháp, gian lận hoặc lạm dụng là hoàn toàn bị cấm và sẽ bị điều tra. Các giải pháp giải captcha của chúng tôi nâng cao trải nghiệm người dùng trong khi đảm bảo tuân thủ 100% trong việc giúp giải quyết các khó khăn về captcha trong quá trình thu thập dữ liệu công khai. Chúng tôi khuyến khích việc sử dụng dịch vụ của chúng tôi một cách có trách nhiệm. Để biết thêm thông tin, vui lòng truy cập Điều khoản Dịch vụ và Chính sách Quyền riêng tư.

Thêm

Maxun với tích hợp CapSolver
Cách giải Captcha trong Maxun với tích hợp CapSolver

Một hướng dẫn thực tế về việc tích hợp CapSolver với Maxun cho quét web thực tế. Học cách xử lý reCAPTCHA, Cloudflare Turnstile và các trang web được bảo vệ bằng CAPTCHA bằng cách sử dụng quy trình xác thực trước và luồng công việc robot.

web scraping
Logo of CapSolver

Anh Tuan

21-Jan-2026

Browser4 với Tích hợp CapSolver
Cách giải Captcha trong Browser4 với tích hợp CapSolver

Tự động hóa Browser4 tỷ lệ xử lý cao kết hợp với CapSolver để xử lý các thách thức CAPTCHA trong việc trích xuất dữ liệu web quy mô lớn.

web scraping
Logo of CapSolver

Anh Tuan

21-Jan-2026

Bot gỡ mã là gì và cách xây dựng một cái
Bot rút trích là gì và cách xây dựng một cái

Học về bot quét và cách xây dựng một bot để trích xuất dữ liệu tự động. Khám phá các công cụ hàng đầu, kỹ thuật vượt qua bảo mật và thực hành trích xuất dữ liệu có đạo đức.

web scraping
Logo of CapSolver

Anh Tuan

15-Jan-2026

Scrapy so với Selenium
Scrapy so với Selenium: Cái nào tốt nhất cho Dự án Ghi dữ liệu từ Web của bạn?

Khám phá các điểm mạnh và sự khác biệt giữa Scrapy và Selenium trong việc quét dữ liệu trên web. Học cách chọn công cụ phù hợp nhất với dự án của bạn và cách xử lý các thách thức như CAPTCHAs.

web scraping
Logo of CapSolver

Rajinder Singh

14-Jan-2026

Cách sử dụng Selenium Driverless để trích xuất dữ liệu từ web hiệu quả
Cách sử dụng Selenium Driverless để quét web hiệu quả

Học cách sử dụng Selenium Driverless để quét web hiệu quả. Hướng dẫn này cung cấp các bước từng bước để cài đặt môi trường của bạn, viết script Selenium Driverless đầu tiên của bạn và xử lý nội dung động. Tối ưu hóa các nhiệm vụ quét web bằng cách tránh sự phức tạp trong quản lý WebDriver truyền thống, giúp quy trình trích xuất dữ liệu của bạn trở nên đơn giản hơn, nhanh hơn và dễ di chuyển hơn.

web scraping
Logo of CapSolver

Sora Fujimoto

14-Jan-2026

Giải quyết Lỗi 403 Cấm Khi Truy Cập Website bằng Python
Giải quyết lỗi 403 Truy cập bị từ chối khi quét trang web bằng Python

Học cách vượt qua các lỗi 403 Forbidden khi quét trang web bằng Python. Hướng dẫn này bao gồm quay vòng IP, giả mạo user-agent, kiểm soát tần suất yêu cầu, xử lý xác thực và sử dụng trình duyệt không đầu để vượt qua các hạn chế truy cập và tiếp tục quét web thành công.

web scraping
Logo of CapSolver

Sora Fujimoto

13-Jan-2026