```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 和性能优化是可靠工作的关键。
对于具有高匿名性要求的大规模解析,住宅代理是合适的选择,它们看起来像普通用户,可以绕过大多数机器人保护。