返回博客

JavaScript代理渲染:如何避免被阻止和错误

JavaScript渲染在使用代理时需要特殊方法。让我们了解会出现哪些问题以及如何解决它们。

📅2025年12月4日
```html

通过代理进行 JavaScript 渲染:如何避免阻止和错误

当您解析通过 JavaScript 加载内容的网站时,简单的 HTTP 请求变得无效。加上机器人保护和地理位置限制,任务的复杂性会增加数倍。代理解决了部分问题,但需要正确配置。

为什么 JavaScript 渲染需要代理

现代网站经常使用 React、Vue 或 Angular 等框架,这些框架在客户端加载内容。当您发送普通的 GET 请求时,您会收到一个空的 HTML,其中包含标签 <div id="root"></div>,而不是准备好的内容。

代理解决的问题:

  • 地理位置阻止。 网站按国家/地区限制访问。来自所需地区的代理 IP 可以绕过这些限制。
  • 机器人保护。 Cloudflare、hCaptcha 和类似系统会阻止自动化请求。住宅代理看起来像普通用户,能更好地通过检查。
  • 速率限制。 服务器可能在多次请求后阻止单个 IP。代理分散流量并避免阻止。
  • 匿名性。 在解析时隐藏您的真实 IP。

无头浏览器和代理:基础知识

JavaScript 渲染使用无头浏览器 — 没有图形界面的 Chromium。流行的选项:

  • Puppeteer — 用于管理 Chrome/Chromium 的 Node.js 库。
  • Playwright — 跨浏览器替代方案,支持 Chrome、Firefox、Safari。
  • Selenium — 经典选择,适用于不同的浏览器。

所有这些都通过浏览器启动参数或连接选项支持代理。

实际配置

Puppeteer 与代理

将代理连接到 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();
})();

如果代理需要身份验证:

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.authenticate({
    username: 'user',
    password: 'pass'
  });
  
  await page.goto('https://example.com');
  const content = await page.content();
  
  await browser.close();
})();

Playwright 与代理

在 Playwright 中,代理通过浏览器上下文配置:

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();
})();

多个请求的代理轮换

对于大规模解析,需要代理轮换。这是一个使用数组的简单示例:

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;
}

// 使用
(async () => {
  const urls = ['https://example.com/1', 'https://example.com/2'];
  for (const url of urls) {
    const content = await getPageWithProxy(url);
    console.log('已解析:', url);
  }
})();

常见错误和解决方案

错误 原因 解决方案
ERR_TUNNEL_CONNECTION_FAILED 代理不可用或凭据不正确 检查代理 IP:port、登录名/密码。通过 curl 进行测试
加载超时 代理速度慢或网站阻止请求 增加超时时间,添加 User-Agent,使用住宅代理
403 禁止访问 网站识别了机器人 添加真实的 headers,使用住宅代理,在请求之间添加延迟
每次请求都出现验证码 网站看到相同的 User-Agent 轮换 User-Agent,为每个浏览器使用不同的代理

添加真实的 headers

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');

性能优化

禁用不必要的资源

加载图像和样式会减慢解析。如果您只需要文本:

const page = await browser.newPage();

// 阻止加载图像和样式
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');

使用浏览器池

为了并行处理多个页面,创建浏览器池,而不是为每个请求启动新浏览器:

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();
  }
}

// 使用
(async () => {
  await initBrowser();
  const urls = ['url1', 'url2', 'url3'];
  
  for (const url of urls) {
    await parsePage(url);
  }
  
  await browser.close();
})();

工具和库

  • Puppeteer Extra — Puppeteer 扩展,支持用于绕过机器人保护的插件。
  • Cheerio — 轻量级 HTML 解析库,用于浏览器渲染后的内容。
  • Axios + Proxy Agent — 用于通过代理进行简单请求,无需浏览器。
  • Scrapy — Python 框架,内置代理支持和分布式解析。

重要: 使用代理时,请确保遵守目标网站的使用条款,不违反其 robots.txt。解析应该是道德的,不会过载服务器。

结论

通过代理进行 JavaScript 渲染是自动化解析的强大工具,但需要注意细节。正确的浏览器配置、代理轮换、真实的 headers 和性能优化是可靠工作的关键。

对于具有高匿名性要求的大规模解析,住宅代理是合适的选择,它们看起来像普通用户,可以绕过大多数机器人保护。

```