如何抓取动态加载的http://proxydb.net页面?Selenium CPU占用过高
解决动态页面抓取的高效方案(针对十万+页面的大型项目)
针对你遇到的proxydb.net因JS动态加载导致cURL返回空、Firefox驱动Selenium CPU占用过高的问题,结合大型爬虫项目的实践经验,我给你推荐几个可行方案,按资源效率从高到低排序:
1. 优先分析页面的后端API(最优解)
大多数动态加载页面的内容,其实是通过AJAX/Fetch请求从后端接口获取后渲染的。直接调用这些接口完全不需要渲染页面,资源占用极低、速度最快,最适合十万+级别的抓取需求。
操作步骤:
- 打开Chrome/Firefox开发者工具(F12),切换到
Network面板。 - 刷新页面,过滤
XHR或Fetch类型的请求,逐一查看返回内容,找到包含代理数据的接口。 - 复制该接口的请求URL、请求头(尤其是
Cookie、User-Agent、Referer等)和请求参数,用requests或aiohttp这类轻量级请求库直接发起请求。
注意事项:
- 部分接口可能有反爬机制(比如签名参数、IP限制、Cookie有效期),需要模拟浏览器的请求逻辑,必要时用
requests.Session保持会话。 - 如果接口返回JSON数据,直接解析即可,比解析HTML效率高得多。
2. 使用Headless Chrome/Chromium + Puppeteer(高效且易实现)
相比Firefox驱动的Selenium,Headless Chrome结合Puppeteer的资源占用更低,API也更简洁,适合批量处理动态页面。通过配置参数,还能进一步降低CPU和内存消耗。
优化配置示例(Node.js代码):
const puppeteer = require('puppeteer'); (async () => { // 启动Headless Chrome,配置资源限制参数 const browser = await puppeteer.launch({ headless: 'new', // 新版无头模式,资源占用更低 args: [ '--disable-gpu', // 禁用GPU加速 '--no-sandbox', // 禁用沙箱(部分环境需要) '--disable-dev-shm-usage', // 避免/dev/shm内存不足 '--disable-extensions', // 禁用扩展 '--disable-images', // 禁用图片加载,减少渲染压力 '--blink-settings=imagesEnabled=false', // 同上 '--window-size=800,600' // 缩小窗口尺寸,减少渲染区域 ], defaultViewport: null, slowMo: 0 // 关闭延迟,加快速度 }); // 复用浏览器实例,批量处理页面 for (let i = 0; i < 100; i++) { const page = await browser.newPage(); await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'); await page.goto('http://proxydb.net', { waitUntil: 'domcontentloaded' }); // 等待DOM加载完成即可 const html = await page.content(); // 获取渲染后的源码 // 处理html逻辑... await page.close(); // 关闭页面释放资源 } await browser.close(); })();
关键优化点:
- 复用同一个浏览器实例,不要每次请求都启动新浏览器(这是Selenium CPU飙升的核心原因之一)。
- 禁用图片、CSS等非必要资源加载,减少渲染工作量。
- 使用
domcontentloaded代替load作为等待条件,缩短等待时间。 - 控制并发数,避免同时打开过多页面导致资源耗尽。
3. 使用Scrapy + Splash(适合Python生态的分布式爬虫)
如果你的项目基于Python的Scrapy框架,Splash是一个轻量级动态页面渲染服务(基于QtWebKit),资源占用远低于Selenium,还能部署成独立服务支持分布式调用。
核心配置:
- 安装并启动Splash服务:
docker run -p 8050:8050 scrapinghub/splash - 在Scrapy的
settings.py中配置Splash:
SPLASH_URL = 'http://localhost:8050' DOWNLOADER_MIDDLEWARES = { 'scrapy_splash.SplashCookiesMiddleware': 723, 'scrapy_splash.SplashMiddleware': 725, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810, } SPIDER_MIDDLEWARES = { 'scrapy_splash.SplashDeduplicateArgsMiddleware': 100, } DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
- 在爬虫中使用Splash请求页面:
import scrapy from scrapy_splash import SplashRequest class ProxySpider(scrapy.Spider): name = 'proxy_spider' start_urls = ['http://proxydb.net'] def start_requests(self): for url in self.start_urls: yield SplashRequest( url, callback=self.parse, args={'wait': 0.5, 'render_all': False}, # 只等待必要时间,不渲染所有资源 headers={'User-Agent': 'Mozilla/5.0...'} ) def parse(self, response): # 处理渲染后的response.body pass
4. 轻量级JS引擎:jsdom(适合简单动态页面)
如果页面的JS逻辑不复杂,可以用jsdom在Node.js环境中模拟DOM渲染,资源占用极低,但对复杂浏览器API(如Canvas、WebGL)支持有限。
示例代码:
const { JSDOM } = require('jsdom'); (async () => { const dom = await JSDOM.fromURL('http://proxydb.net', { runScripts: 'dangerously', // 允许执行页面JS resources: 'usable' // 加载必要资源 }); // 等待JS执行完成(可根据页面逻辑调整延迟) setTimeout(() => { const html = dom.serialize(); // 获取渲染后的源码 // 处理html逻辑... }, 1000); })();
最后,针对你的十万+页面需求,优先推荐方案1(API分析);如果无法找到可用接口,再选择方案2或3,这两个方案在合理配置下,完全可以支撑大规模抓取,不会出现CPU瞬间100%的问题。
内容的提问来源于stack exchange,提问作者Sven
相关产品推荐
相关产品推荐

