跳转至

13.4 Web分析与爬虫——动态页面爬取示例

内容梗概

本节课解决 Ajax 动态渲染页面的爬取问题。老师先分析:含 Ajax 的页面,浏览器能自动运行 JS 补全内容,所以用户看到完整页面;但 requests 拿到的 HTML 是残缺的,BeautifulSoup 又不提供 JavaScript 运行环境,直接解析无济于事。随后引入 Web 自动化测试工具 Selenium(课上未念名字,称"这个工具"):Python 程序驱动 chromedriver,再驱动真实 Chrome 浏览器,从而获得 JS 渲染环境。课程演示了环境配置三要素(装库、装浏览器、下载对应版本 driver 并配环境变量),以及用 driver.get + find_elements_by_css_selector 抓取动态页面学生名单的完整过程。

知识点详解

为什么 requests 搞不定动态页面(约 00:00–01:55)

  • 不涉及 Ajax 时,requests 直接拿到整个页面的完整 HTML(即 13.3 的情形)。
  • 若网站部分内容由 JavaScript 通过 Ajax 生成:浏览器访问时会自动运行 JS 并把取回的内容补全,用户看到的是完整 HTML;但爬虫用 requests 请求,服务器除了返回残缺 HTML 外还返回一堆 JS,后续还要发新请求。
  • 把这样的 HTML 直接扔给 BeautifulSoup 没用——BeautifulSoup 不提供 JavaScript 运行环境(至少旧版本没有)。因此需要一个能提供 **JavaScript 渲染环境**的新工具。

Selenium:Web 自动化测试工具(约 01:55–04:00,09:40–11:40)

  • 网上搜到的最常见工具就是 Selenium(老师自称发音总错,放弃念名字)。
  • 它本是做 **Web 测试**的工具:公司开发页面后要验证页面跳转逻辑是否按设计工作,人工点击很愚蠢,于是用程序自动化地点页面——由此产生了自动化的 Web 测试平台。
  • 并非专为 Python 开发,Java、Python 等多种语言都可用。
  • 驱动链条:Python 程序(.py)→ driver.exe → 浏览器(如 chrome.exe)。运行程序会自动弹出浏览器窗口访问页面,浏览器顶栏会提示"Chrome 正在受自动测试软件的控制"。

动态页面实测对比(约 04:00–09:15)

  • 演示对象:上一节课的 Flask 动态渲染演示网站(老师把默认端口 5000 改了一下),页面只显示前 10~20 个学生 ID,其余靠**滚动页面**触发 Ajax 加载。
  • 用 13.3 的爬虫机制面对它的 bug:只能抓到前 10 个;后面内容没有超链接(a 元素),也无法模拟下拉滚动条,直接"傻眼"。
  • 实测:直接用 requests 抓到的 HTML 里,列表的 li 项**全部不见了**。原因:这些 li 是 JS 通过 data?page=1 访问后端接口拿到 JSON 串、再由 JavaScript 写进页面的;requests 和 BeautifulSoup 都不运行 JS,自然拿不到 → 抓取失败。

环境配置三要素(约 11:40–15:35)

  1. pipenv install selenium 安装库(课上为省时间没用虚拟环境,直接装的)。
  2. 本地装有浏览器(Chrome / Firefox 均可),并**确认版本号**(演示机 Chrome 为 83.0)。
  3. 下载**与浏览器版本完全对应**的 driver(Chrome 83 就不能下 84 的 driver),选择对应平台(win32 等);把 chromedriver.exe 放进已在环境变量 PATH 中的目录(老师放在专门的 ctools-bin 目录),使命令行能直接运行 chromedriver.exe。

代码逻辑(约 11:15–12:10,16:25–17:50)

  • 与 requests 思路类似,不再需要 requests 发 HTTP 请求:
    driver.get(url)                                # 类似 requests.get,驱动浏览器访问
    els = driver.find_elements_by_css_selector('li')  # 同样用 CSS 选择器找元素
    for e in els:
        ...                                        # 遍历取内容
    driver.close()                                 # 关闭浏览器
    
  • API 名字好理解;close 会把受控的 Chrome 直接关掉(老师为演示效果先把 close 注释掉,让窗口留着)。
  • 运行效果:自动弹出 Chrome 窗口访问地址,因为本质就是真实浏览器,能完整渲染 Ajax 出来的 li,于是成功抓到全部内容——和用户真实看到的页面一模一样。

同类工具与本质(约 18:20–19:00)

  • Selenium 不是唯一选择,还有 PhantomJS 等其他工具,课后可自行学习,选喜欢的即可。
  • 原理一致:内置/驱动一个 JavaScript 执行环境,把 Ajax 渲染的内容渲染出来,再分析 HTML——本质上仍在分析 HTML 页面来获取内容。

示例与演示

  • 对比演示:同一动态网站,先用 requests 抓取展示残缺的 HTML(li 全消失),再用 Selenium 驱动 Chrome 抓取,成功得到全部学生 ID。
  • 环境配置演示:查看 Chrome 版本(关于 Chrome → 83.0)→ 下载对应版本 win32 的 chromedriver → 放入 PATH 中的 ctools-bin 目录 → 命令行验证 chromedriver.exe 可直接运行。
  • 运行演示:注意先 cd 到 dynamic 目录(老师自己一开始忘切换目录报错);运行后自动弹出 Chrome 窗口,页面提示"正在受自动测试软件的控制",成功提取所有 li 内容;注释掉 close 可保留窗口观察。
  • 课堂小状况:升级 Windows 后疑似虚拟机导致演示卡顿,老师提示卡住可看回放——无实质知识内容。

重点与难点

  • 重点:判断页面是否 Ajax 动态渲染——若 requests 拿到的 HTML 与浏览器看到的不一致(关键元素缺失),就要换带 JS 渲染环境的工具。
  • 重点:Selenium 驱动链 Python → chromedriver → Chrome;环境配置三要素缺一不可,尤其 driver 版本必须与浏览器版本对应 且 driver 要放进 PATH。
  • 易错点:
  • BeautifulSoup 不能运行 JS,别指望它解析出 Ajax 内容。
  • driver 与浏览器版本不匹配会失败(83 不能配 84)。
  • 运行前确认终端所在目录。
  • 翻页方式是"滚动加载"而非超链接时,传统沿链接爬取的逻辑直接失效。
  • Selenium 方案抓到的是真实渲染结果,与用户所见完全一致——这也是它通用性强的原因(呼应 13.5 的总结)。

关联内容

  • 承上:13.3 静态爬取(requests + BeautifulSoup)在本课被证明对动态页面失效;13.2 的 CSS 选择器知识沿用到 find_elements_by_css_selector。
  • 动态网站、Ajax、JSON 接口(data?page=1)等概念来自上一周 Web 开发课程;演示网站即 Web 开发课做的 Flask 动态渲染站点(默认端口 5000)。
  • 启下:13.5 将换一条思路——不渲染页面,直接抓取 JS 访问的数据接口;并预告后续讲真实网站案例及 IP 封禁、登录保护等对抗问题。
  • 同类工具 PhantomJS 留作课后自学。