当前位置:首页 > 前端开发 > 正文

js生成的html如何爬取

需用 Selenium/Puppeteer 等工具模拟浏览器执行

核心挑战:为何传统爬虫失效?

现代网页普遍采用异步加载技术(AJAX/Fetch API),其本质特征为:
| 现象类型 | 表现形式 | 技术根源 |
|—————-|——————————|————————|
| 空白初始页面 | 首次请求仅返回空容器/占位符 | DOM由JS动态构建 |
| XHR二次请求 | 网络面板可见额外API调用 | XMLHttpRequest/fetch|
| 加密数据流 | 响应体为二进制密文 | WebAssembly/WASM沙箱 |
| 单页应用(SPA) | URL不变但内容切换 | History API路由控制 |

传统爬虫(如requests+BeautifulSoup)只能获取初始HTML骨架,无法直接捕获后续JS生成的内容,需采用能模拟浏览器行为的方案。


四大主流解决方案深度对比

方案1:Selenium + ChromeDriver(全能型)

适用场景:复杂交互式页面(表单提交/滚动加载/弹窗处理)
工作原理:启动真实Chrome实例,完全复现用户操作环境
实施步骤

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time
# 配置无头模式(可选)
options = webdriver.ChromeOptions()
options.add_argument('--headless')  # 后台运行
options.add_argument('--disable-gpu')
# 初始化驱动
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
try:
    driver.get("https://example.com")  # 目标网址
    time.sleep(3)  # 等待JS执行完成(可根据需求调整)
    # 获取渲染后的页面源码
    html_content = driver.page_source
    # 此处可接续解析逻辑(BS4/lxml等)
finally:
    driver.quit()

优势:支持CSS选择器/XPath定位,可模拟点击/输入等操作
缺点:资源占用高(约500MB内存),速度较慢(冷启动~2秒)

方案2:Pyppeteer/Playwright(轻量化替代)

适用场景:中等复杂度页面,追求更快速度
工作原理:基于Chromium内核的轻量级浏览器引擎
代码示例(Playwright):

from playwright.sync_api import sync_playwright
with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto("https://example.com", wait_until="domcontentloaded")  # 关键等待条件
    # 等待特定元素出现(更精准的控制)
    page.wait_for_selector("div.data-container")
    html_content = page.content()  # 获取完整HTML
    browser.close()

优势:原生支持异步API,内置截图/PDF生成功能
性能提升:相比Selenium快3-5倍,内存占用降低60%

方案3:逆向分析API接口(高效首选)

核心思路:通过开发者工具找到数据源接口,直连后端服务
操作流程

  1. 打开浏览器F12 → Network面板
  2. 刷新页面 → 筛选XHR/fetch请求
  3. 识别返回JSON/数据的请求URL
  4. 构造请求参数(注意Cookie/Headers)

典型请求头构造示例
| 字段 | 值 | 说明 |
|—————|——————————|————————–|
| User-Agent | Mozilla/5.0 (Windows NT...) | 模拟浏览器访问 |
| Referer | https://example.com/list | 防盗链机制 |
| Cookie | sessionid=xxx; token=yyy | 身份验证凭证 |
| Content-Type | application/json | POST请求常见类型 |

代码实现(requests):

import requests
import json
headers = {
    "User-Agent": "Mozilla/5.0...",
    "Referer": "https://example.com/list",
    "Cookie": "sessionid=abc123"
}
params = {"page": 1, "size": 20}
response = requests.get("https://api.example.com/data", headers=headers, params=params)
data = response.json()  # 直接获取结构化数据

优势:毫秒级响应,无需渲染JS,适合大规模采集
限制:部分网站采用JWT令牌/非对称加密,需破解签名算法

方案4:PhantomJS(淘汰预警)

现状:已停止维护,存在安全破绽,推荐迁移至上述方案


关键技术增强点

智能等待策略

方法 适用场景 代码片段
time.sleep() 简单粗暴(不推荐) time.sleep(5)
显式等待(Explicit) 特定元素出现 WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "main")))
隐式等待(Implicit) 全局超时设置 driver.implicitly_wait(10)
滚动触发加载 无限滚动列表 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

反爬对抗策略

威胁类型 解决方案 实施方式
IP封禁 代理池轮换 集成ProxyMesh/Luminati代理服务
人机验证 打码平台/AI识别 Tesseract OCR + 第三方验证码破解
请求频率限制 随机延迟+分布式节点 random.uniform(1,3)间隔请求
指纹追踪 动态UA/Canvas指纹混淆 fake_useragent库 + Stealthy模块

数据解析优化

  • 正则表达式:适用于非标准HTML结构(如<script>标签内的JSONP数据)
  • JsonPath:比XPath更适合处理嵌套JSON数据
  • AST解析:对付混淆过的JS代码(需借助esprima等库)

实战案例:电商评论爬取

假设目标站点特点:

  • 评论通过滚动加载(无限下拉)
  • 数据来源于/comments?pid=XXX&page=Y接口
  • 需要登录态才能访问

混合方案设计

  1. 使用Selenium登录获取Cookie
  2. 提取Cookie中的auth_token
  3. 改用requests直接调用API接口
  4. 并行多线程采集(控制并发数≤5)

关键代码片段

# Step1: Selenium登录获取Cookie
driver.get("https://login.example.com")
driver.find_element(By.NAME, "username").send_keys("user")
driver.find_element(By.NAME, "pwd").send_keys("pass")
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
cookies = driver.get_cookies()
# Step2: 构造API请求
session = requests.Session()
for cookie in cookies:
    session.cookies.set(cookie['name'], cookie['value'])
# Step3: 批量采集评论
results = []
for page in range(1, 10):
    url = f"https://api.example.com/comments?pid=123&page={page}"
    resp = session.get(url, headers={"Accept": "application/json"})
    results.extend(resp.json()["data"])

常见问题FAQs

Q1: 为什么有时能抓到数据,有时抓不到?

原因分析

  1. 时机问题:JS执行未完成即开始解析(解决方案:增加等待时间/监听事件)
  2. 环境差异:本地IP被屏蔽(解决方案:启用高质量代理)
  3. 版本冲突:网站检测到自动化工具特征(解决方案:更新User-Agent/禁用图片加载)
  4. 缓存机制:第一次访问成功后续失败(解决方案:强制刷新Ctrl+F5

排查步骤
① 手动复制目标元素的XPath到浏览器控制台测试有效性
② 在代码中插入print(len(driver.find_elements(...)))验证元素数量
③ 启用日志记录(logging模块)追踪完整请求流程

Q2: 如何处理动态加载的图片/视频地址?

技术路线

  1. 拦截网络请求:使用Mitmproxy中间人代理截获媒体资源URL
  2. 延迟加载检测:通过IntersectionObserverAPI判断元素是否进入视口
  3. 懒加载破解:修改img标签的data-src属性为src后重新加载
  4. WebSocket监控:对实时推送类应用(如直播弹幕)建立长连接监听

代码示例(修改懒加载)

js生成的html如何爬取  第1张

// 在Page对象创建后注入脚本
await page.evaluate(() => {
    const lazyImages = document.querySelectorAll('img[data-src]');
    lazyImages.forEach(img => {
        img.src = img.dataset.src;
    });
});

伦理与法律提示

  1. robots.txt协议:遵守/robots.txt文件中的规则(可通过requests.get("https://example.com/robots.txt")查看)
  2. 版权风险:商业用途需获得网站授权(《著作权法》第10条)
  3. 个人隐私:避免采集敏感信息(身份证号/手机号等),违反《个人信息保护法》
  4. 技术底线:禁止突破网站安全防护(如绕过支付验证流程)

建议将采集频率控制在合理范围(一般不超过1次/秒),必要时联系网站管理员

0