Quay lại blog

Kỹ thuật render JavaScript qua proxy: Cách tránh bị chặn và lỗi

Kết xuất JavaScript yêu cầu cách tiếp cận đặc biệt khi làm việc với proxy. Hãy tìm hiểu những vấn đề phát sinh và cách giải quyết chúng.

📅4 tháng 12, 2025
```html

Kết xuất JavaScript thông qua proxy: cách tránh các khối chặn và lỗi

Khi bạn phân tích các trang web tải nội dung thông qua JavaScript, các yêu cầu HTTP đơn giản trở nên không hiệu quả. Thêm vào đó bảo vệ chống bot và các hạn chế địa lý — và nhiệm vụ trở nên phức tạp gấp nhiều lần. Proxy giải quyết một phần vấn đề, nhưng yêu cầu cấu hình chính xác.

Tại sao kết xuất JavaScript yêu cầu proxy

Các trang web hiện đại thường sử dụng các framework như React, Vue hoặc Angular, tải nội dung phía máy khách. Khi bạn gửi một yêu cầu GET thông thường, bạn nhận được HTML trống với thẻ <div id="root"></div>, thay vì nội dung đã sẵn sàng.

Các vấn đề mà proxy giải quyết:

  • Các khối chặn địa lý. Các trang web hạn chế quyền truy cập theo quốc gia. Proxy có IP từ khu vực cần thiết vượt qua các hạn chế này.
  • Bảo vệ chống bot. Cloudflare, hCaptcha và các hệ thống tương tự chặn các yêu cầu tự động. Proxy dân cư trông giống như người dùng bình thường và vượt qua các kiểm tra tốt hơn.
  • Giới hạn tỷ lệ. Máy chủ có thể chặn một IP sau nhiều yêu cầu. Proxy phân phối lưu lượng và tránh các khối chặn.
  • Tính ẩn danh. Ẩn IP thực của bạn khi phân tích.

Trình duyệt Headless và proxy: những điều cơ bản

Để kết xuất JavaScript, sử dụng trình duyệt headless — Chromium không có giao diện đồ họa. Các tùy chọn phổ biến:

  • Puppeteer — thư viện Node.js để quản lý Chrome/Chromium.
  • Playwright — giải pháp thay thế đa trình duyệt, hỗ trợ Chrome, Firefox, Safari.
  • Selenium — lựa chọn cổ điển, hoạt động với các trình duyệt khác nhau.

Tất cả chúng đều hỗ trợ proxy thông qua các tham số khởi chạy trình duyệt hoặc các tùy chọn kết nối.

Cấu hình thực tế

Puppeteer với proxy

Ví dụ cơ bản về kết nối proxy với Puppeteer:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    args: [
      '--proxy-server=http://proxy.example.com:8080'
    ]
  });

  const page = await browser.newPage();
  await page.goto('https://example.com');
  
  const content = await page.content();
  console.log(content);
  
  await browser.close();
})();

Nếu proxy yêu cầu xác thực:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    args: [
      '--proxy-server=http://proxy.example.com:8080'
    ]
  });

  const page = await browser.newPage();
  
  // Đặt thông tin xác thực cho proxy
  await page.authenticate({
    username: 'user',
    password: 'pass'
  });
  
  await page.goto('https://example.com');
  const content = await page.content();
  
  await browser.close();
})();

Playwright với proxy

Trong Playwright, proxy được cấu hình thông qua ngữ cảnh trình duyệt:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({
    proxy: {
      server: 'http://proxy.example.com:8080',
      username: 'user',
      password: 'pass'
    }
  });

  const context = await browser.newContext();
  const page = await context.newPage();
  
  await page.goto('https://example.com');
  const content = await page.content();
  
  await browser.close();
})();

Xoay vòng proxy cho nhiều yêu cầu

Để phân tích quy mô lớn, bạn cần xoay vòng proxy. Đây là một ví dụ đơn giản với một mảng:

const puppeteer = require('puppeteer');

const proxies = [
  'http://proxy1.com:8080',
  'http://proxy2.com:8080',
  'http://proxy3.com:8080'
];

let proxyIndex = 0;

async function getPageWithProxy(url) {
  const currentProxy = proxies[proxyIndex % proxies.length];
  proxyIndex++;
  
  const browser = await puppeteer.launch({
    args: [`--proxy-server=${currentProxy}`]
  });
  
  const page = await browser.newPage();
  await page.goto(url);
  const content = await page.content();
  
  await browser.close();
  return content;
}

// Sử dụng
(async () => {
  const urls = ['https://example.com/1', 'https://example.com/2'];
  for (const url of urls) {
    const content = await getPageWithProxy(url);
    console.log('Parsed:', url);
  }
})();

Các lỗi phổ biến và giải pháp

Lỗi Nguyên nhân Giải pháp
ERR_TUNNEL_CONNECTION_FAILED Proxy không khả dụng hoặc thông tin xác thực không chính xác Kiểm tra IP:port proxy, tên đăng nhập/mật khẩu. Kiểm tra thông qua curl
Timeout khi tải Proxy chậm hoặc trang web chặn yêu cầu Tăng timeout, thêm User-Agent, sử dụng proxy dân cư
403 Forbidden Trang web nhận ra bot Thêm header thực tế, sử dụng proxy dân cư, thêm độ trễ giữa các yêu cầu
CAPTCHA ở mỗi yêu cầu Trang web thấy User-Agent giống nhau Xoay vòng User-Agent, sử dụng các proxy khác nhau cho mỗi trình duyệt

Thêm header thực tế

const page = await browser.newPage();

await page.setUserAgent(
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
);

await page.setExtraHTTPHeaders({
  'Accept-Language': 'en-US,en;q=0.9',
  'Accept': 'text/html,application/xhtml+xml',
  'Referer': 'https://google.com'
});

await page.goto('https://example.com');

Tối ưu hóa hiệu suất

Tắt tài nguyên không cần thiết

Tải hình ảnh và kiểu dáng làm chậm quá trình phân tích. Nếu bạn chỉ cần văn bản:

const page = await browser.newPage();

// Chặn tải hình ảnh và kiểu dáng
await page.on('request', (request) => {
  const resourceType = request.resourceType();
  if (['image', 'stylesheet', 'font', 'media'].includes(resourceType)) {
    request.abort();
  } else {
    request.continue();
  }
});

await page.goto('https://example.com');

Sử dụng nhóm trình duyệt

Để xử lý song song nhiều trang, hãy tạo một nhóm trình duyệt thay vì khởi chạy trình duyệt mới cho mỗi yêu cầu:

const puppeteer = require('puppeteer');

let browser;
const maxPages = 5;
let activePage = 0;

async function initBrowser() {
  browser = await puppeteer.launch({
    args: ['--proxy-server=http://proxy.example.com:8080']
  });
}

async function parsePage(url) {
  const page = await browser.newPage();
  try {
    await page.goto(url);
    const content = await page.content();
    return content;
  } finally {
    await page.close();
  }
}

// Sử dụng
(async () => {
  await initBrowser();
  const urls = ['url1', 'url2', 'url3'];
  
  for (const url of urls) {
    await parsePage(url);
  }
  
  await browser.close();
})();

Công cụ và thư viện

  • Puppeteer Extra — phần mở rộng Puppeteer với hỗ trợ plugin để vượt qua bảo vệ chống bot.
  • Cheerio — thư viện nhẹ để phân tích HTML sau khi kết xuất trình duyệt.
  • Axios + Proxy Agent — cho các yêu cầu đơn giản thông qua proxy mà không cần trình duyệt.
  • Scrapy — framework Python với hỗ trợ proxy tích hợp và phân tích phân tán.

Quan trọng: Khi làm việc với proxy, hãy đảm bảo bạn tuân thủ các điều khoản sử dụng của trang web đích và không vi phạm robots.txt của nó. Phân tích phải có đạo đức và không quá tải máy chủ.

Kết luận

Kết xuất JavaScript thông qua proxy là một công cụ mạnh mẽ để tự động hóa phân tích, nhưng yêu cầu chú ý đến chi tiết. Cấu hình trình duyệt chính xác, xoay vòng proxy, header thực tế và tối ưu hóa hiệu suất — những chìa khóa để hoạt động đáng tin cậy.

Để phân tích quy mô lớn với yêu cầu cao về tính ẩn danh, proxy dân cư phù hợp, trông giống như người dùng bình thường và vượt qua hầu hết các bảo vệ chống bot.

```