爬虫学习阶段三:动态网页爬取(完整学习文档)

🕷️ 爬虫工程师学习路径 · 阶段三:动态网页爬取(完整学习文档)

      • [📌 阶段目标](#📌 阶段目标)
    • [📖 第1章 动态网页概述](#📖 第1章 动态网页概述)
      • [1.1 什么是动态网页?](#1.1 什么是动态网页?)
      • [1.2 抓取动态网页的两种思路](#1.2 抓取动态网页的两种思路)
    • [🔧 第2章 浏览器开发者工具(Network 面板)](#🔧 第2章 浏览器开发者工具(Network 面板))
      • [2.1 打开 Network 面板](#2.1 打开 Network 面板)
      • [2.2 分析请求](#2.2 分析请求)
      • [2.3 实战:找到微博热搜的数据接口](#2.3 实战:找到微博热搜的数据接口)
    • [🌐 第3章 Ajax 接口分析与模拟](#🌐 第3章 Ajax 接口分析与模拟)
      • [3.1 确定接口 URL 和请求方式](#3.1 确定接口 URL 和请求方式)
      • [3.2 模拟 GET 请求](#3.2 模拟 GET 请求)
      • [3.3 模拟 POST 请求](#3.3 模拟 POST 请求)
      • [3.4 处理分页](#3.4 处理分页)
    • [📦 第4章 JSON 数据解析](#📦 第4章 JSON 数据解析)
      • [4.1 示例:提取微博热搜词](#4.1 示例:提取微博热搜词)
      • [4.2 处理复杂嵌套](#4.2 处理复杂嵌套)
    • [🤖 第5章 Selenium 基础](#🤖 第5章 Selenium 基础)
      • [5.1 安装与配置](#5.1 安装与配置)
      • [5.2 基本用法](#5.2 基本用法)
      • [5.3 常用操作](#5.3 常用操作)
      • [5.4 等待机制](#5.4 等待机制)
      • [5.5 处理下拉滚动](#5.5 处理下拉滚动)
    • [🚀 第6章 Playwright 简介](#🚀 第6章 Playwright 简介)
      • [6.1 安装](#6.1 安装)
      • [6.2 基本用法](#6.2 基本用法)
    • [🛡️ 第7章 绕过 WebDriver 检测](#🛡️ 第7章 绕过 WebDriver 检测)
      • [7.1 修改 `navigator.webdriver`](#7.1 修改 navigator.webdriver)
      • [7.2 使用真实 User-Agent](#7.2 使用真实 User-Agent)
      • [7.3 设置窗口大小](#7.3 设置窗口大小)
    • [🎯 第8章 实战一:爬取微博热搜榜(Ajax 版)](#🎯 第8章 实战一:爬取微博热搜榜(Ajax 版))
      • [8.1 目标](#8.1 目标)
      • [8.2 分析步骤](#8.2 分析步骤)
      • [8.3 代码实现(以最新接口为例,可能需要调整)](#8.3 代码实现(以最新接口为例,可能需要调整))
      • [8.4 常见问题](#8.4 常见问题)
    • [🎯 第9章 实战二:爬取拉勾网职位信息(动态渲染)](#🎯 第9章 实战二:爬取拉勾网职位信息(动态渲染))
      • [9.1 目标](#9.1 目标)
      • [9.2 分析 Ajax 接口(首选)](#9.2 分析 Ajax 接口(首选))
      • [9.3 使用 Selenium 模拟](#9.3 使用 Selenium 模拟)
        • [9.3.1 思路](#9.3.1 思路)
        • [9.3.2 代码实现](#9.3.2 代码实现)
        • [9.3.3 注意事项](#9.3.3 注意事项)
      • [9.4 使用 Playwright 替代](#9.4 使用 Playwright 替代)
    • [📝 第10章 总结与进阶](#📝 第10章 总结与进阶)
      • [10.1 本阶段核心能力](#10.1 本阶段核心能力)
      • [10.2 常见反爬与应对总结](#10.2 常见反爬与应对总结)
      • [10.3 下一步建议](#10.3 下一步建议)
    • [⚠️ 法律与道德提醒](#⚠️ 法律与道德提醒)

欢迎进入阶段三!在前两个阶段,你已经学会了爬取静态网页,处理登录和会话。但现代网站越来越多地采用动态渲染技术,页面内容由 JavaScript 动态生成,直接请求 HTML 可能得不到想要的数据。本阶段将带你掌握动态网页的抓取技巧,包括分析 Ajax 接口、使用浏览器自动化工具,以及应对常见的反爬策略。完成本阶段后,你将能够爬取大多数需要 JavaScript 执行的网站。


📌 阶段目标

  • 熟练使用浏览器开发者工具的 Network 面板分析 Ajax 请求
  • 能够找到隐藏的数据接口,直接模拟请求获取 JSON 数据
  • 掌握 Selenium/Playwright 的基本使用,处理 JavaScript 渲染的页面
  • 理解显式等待、隐式等待,确保元素加载完成
  • 学会绕过简单的 WebDriver 检测
  • 实战:完成两个练习------爬取微博热搜榜(Ajax 版)和爬取拉勾网职位信息(动态渲染)

📖 第1章 动态网页概述

1.1 什么是动态网页?

动态网页是指页面内容不是写死在 HTML 中的,而是通过 JavaScript 向服务器请求数据(通常是 JSON),然后动态填充到 DOM 中。这种技术称为 Ajax(Asynchronous JavaScript and XML),现在更常用 JSON 作为数据格式。

静态网页 vs 动态网页

  • 静态网页:所有内容在 HTML 源代码中直接可见。
  • 动态网页:HTML 源代码中只有框架,数据是通过后续 Ajax 请求加载的。

判断方法:在浏览器中右键 → "查看网页源代码",搜索你期望的数据。如果找不到,说明是动态加载的。

1.2 抓取动态网页的两种思路

  1. 直接分析 Ajax 接口 :找到浏览器向服务器请求数据的真实 URL,然后用 requests 模拟请求,获取 JSON 数据。这是最高效、最稳定的方法。
  2. 使用浏览器自动化工具:如 Selenium、Playwright,它们会驱动真实浏览器加载页面,执行 JavaScript,然后我们可以从渲染后的 DOM 中提取数据。适用于接口复杂、加密参数多的情况。

本阶段将重点学习第一种方法,并介绍第二种作为补充。


🔧 第2章 浏览器开发者工具(Network 面板)

在阶段一我们简单接触过开发者工具,现在需要深入掌握 Network 面板,它是分析动态网页的核心。

2.1 打开 Network 面板

  • 按 F12 打开开发者工具,切换到 Network 选项卡。
  • 刷新页面,你会看到所有网络请求(HTML、CSS、JS、图片、XHR 等)。
  • 勾选 Preserve log 可以保留请求日志,防止页面跳转时清空。
  • 点击 XHR 过滤器,只显示 Ajax 请求(通常就是我们需要的)。

2.2 分析请求

每个请求包含:

  • Name:请求的 URL 路径。
  • Status:响应状态码。
  • Type:文档类型(xhr 表示 Ajax 请求)。
  • Initiator:发起请求的调用者(可帮助定位)。
  • SizeTime:大小和耗时。
  • Preview:查看响应内容的预览(如果是 JSON,会自动格式化)。
  • Response:查看原始响应数据。
  • Headers:查看请求头(包括 URL、Method、User-Agent、Cookie、Referer 等)。
  • Payload/Form Data:如果是 POST 请求,这里显示提交的参数。

2.3 实战:找到微博热搜的数据接口

  1. 打开微博热搜榜:https://s.weibo.com/top/summary
  2. 打开开发者工具,切换到 Network 面板,刷新页面。
  3. 筛选 XHR,你会看到一些请求,其中可能包含 ?Refer=top_summary 之类的 URL。
  4. 点击某个请求,在 Preview 中查看响应是否为热搜数据(通常是一个 JSON,包含热搜词、热度等)。
  5. 找到真正的数据接口后,复制其 URL 和必要的请求头,就可以用 Python 模拟请求了。

🌐 第3章 Ajax 接口分析与模拟

3.1 确定接口 URL 和请求方式

在 Network 中找到数据接口后,观察:

  • 请求方法:GET 还是 POST?
  • URL:完整地址(可能包含查询参数)。
  • 请求头:是否需要特定的 Cookie、Referer、User-Agent 等。
  • 参数:如果是 POST,查看 Payload 中的参数。

3.2 模拟 GET 请求

以微博热搜为例(假设接口为 GET):

python 复制代码
import requests
import json

url = 'https://weibo.com/ajax/statuses/hot_band'  # 示例,实际需根据最新接口修改
headers = {
    'User-Agent': 'Mozilla/5.0',
    'Referer': 'https://s.weibo.com/top/summary',
    'Cookie': '你的Cookie'  # 有时需要登录 Cookie
}
response = requests.get(url, headers=headers)
data = response.json()  # 直接解析 JSON
print(json.dumps(data, indent=2, ensure_ascii=False))

注意:Cookie 可能是必须的,尤其是需要登录的网站。可以先在浏览器登录,复制 Cookie 到代码中。但 Cookie 会过期,需要定期更新或使用 Session 保持。

3.3 模拟 POST 请求

如果是 POST 请求,需要找到参数。有时参数是加密的(如 sign、token),这种情况可能需要逆向 JavaScript(阶段七内容)。但很多网站只是简单的表单提交。

python 复制代码
payload = {
    'page': 1,
    'count': 20
}
response = requests.post(url, data=payload, headers=headers)

如果参数在请求体中是 JSON 格式,则使用 json=payload

3.4 处理分页

通常接口会有 pagecursor 参数,通过循环获取所有页的数据。

python 复制代码
all_data = []
for page in range(1, 6):
    params = {'page': page, 'count': 20}
    response = requests.get(url, params=params, headers=headers)
    data = response.json()
    all_data.extend(data['data']['list'])
    # 控制频率
    time.sleep(1)

📦 第4章 JSON 数据解析

拿到 JSON 数据后,需要提取所需字段。JSON 在 Python 中自动转为字典/列表,通过键访问即可。

4.1 示例:提取微博热搜词

假设返回的 JSON 结构如下(简化版):

json 复制代码
{
  "data": {
    "realtime": [
      {
        "rank": 1,
        "word": "肖战新剧",
        "num": 1256789
      },
      ...
    ]
  }
}

提取代码:

python 复制代码
for item in data['data']['realtime']:
    rank = item['rank']
    word = item['word']
    hot = item['num']
    print(f'{rank}: {word} - {hot}')

4.2 处理复杂嵌套

可以使用 jsonpath 或递归遍历,但通常简单的字典操作就够了。


🤖 第5章 Selenium 基础

当无法找到直接的数据接口,或者接口参数加密难以破解时,可以使用浏览器自动化工具。Selenium 是最经典的。

5.1 安装与配置

bash 复制代码
pip install selenium

还需要下载对应浏览器的驱动:

将驱动所在目录添加到系统 PATH,或在代码中指定路径。

5.2 基本用法

python 复制代码
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 创建浏览器对象
driver = webdriver.Chrome()  # 如果驱动不在 PATH,可指定 executable_path

# 打开网页
driver.get('https://www.lagou.com/zhaopin/Python/')

# 等待几秒,让页面加载
time.sleep(3)

# 查找元素(以职位列表为例)
jobs = driver.find_elements(By.CLASS_NAME, 'item__title')
for job in jobs:
    print(job.text)

# 关闭浏览器
driver.quit()

5.3 常用操作

  • 点击element.click()
  • 输入element.send_keys('Python')
  • 获取文本element.text
  • 获取属性element.get_attribute('href')
  • 执行 JavaScriptdriver.execute_script('window.scrollTo(0, document.body.scrollHeight)')

5.4 等待机制

动态页面需要等待元素加载完成,否则可能找不到元素。Selenium 提供两种等待:

隐式等待:设置一个全局等待时间,在查找元素时如果未立即出现,会轮询直到超时。

python 复制代码
driver.implicitly_wait(10)  # 最多等待10秒

显式等待:针对特定条件等待,更精准。

python 复制代码
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 等待直到元素可见
element = WebDriverWait(driver, 10).until(
    EC.visibility_of_element_located((By.ID, 'jobList'))
)

5.5 处理下拉滚动

很多网站采用懒加载,需要滚动到底部加载更多内容。

python 复制代码
# 滚动到页面底部
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
time.sleep(2)  # 等待新内容加载

🚀 第6章 Playwright 简介

Playwright 是微软推出的新一代自动化工具,比 Selenium 更强大,支持异步、自动等待、内置浏览器驱动等。推荐作为 Selenium 的替代。

6.1 安装

bash 复制代码
pip install playwright
playwright install  # 安装浏览器驱动

6.2 基本用法

python 复制代码
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    # 启动浏览器
    browser = p.chromium.launch(headless=False)  # headless=True 无头模式
    page = browser.new_page()
    
    # 访问网页
    page.goto('https://www.lagou.com/zhaopin/Python/')
    
    # 等待元素出现(自动等待,无需显式设置)
    page.wait_for_selector('.item__title')
    
    # 提取文本
    titles = page.query_selector_all('.item__title')
    for title in titles:
        print(title.text_content())
    
    browser.close()

Playwright 自动等待元素,通常不需要手动 time.sleep


🛡️ 第7章 绕过 WebDriver 检测

有些网站会检测浏览器是否被自动化工具控制,如果检测到则返回假数据或拒绝服务。常见的检测方法有:

  • 检查 navigator.webdriver 属性(Selenium 中默认为 true)
  • 检查 User-Agent 是否包含 "Headless"
  • 检查浏览器指纹(如窗口大小、插件等)

在 Selenium 中,可以通过 ChromeOptions 禁用该属性:

python 复制代码
from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_experimental_option('useAutomationExtension', False)

driver = webdriver.Chrome(options=options)
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")

Playwright 默认已经隐藏了自动化特征,通常无需额外配置。

7.2 使用真实 User-Agent

python 复制代码
options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...')

7.3 设置窗口大小

python 复制代码
options.add_argument('--window-size=1920,1080')

🎯 第8章 实战一:爬取微博热搜榜(Ajax 版)

8.1 目标

  • 爬取微博热搜榜前 50 条热搜词和热度
  • 数据格式:排名、热搜词、热度值
  • 要求:通过分析 Ajax 接口直接获取 JSON

8.2 分析步骤

  1. 打开微博热搜榜:https://s.weibo.com/top/summary
  2. 打开开发者工具,Network → XHR,刷新页面。
  3. 观察请求,找到一个名为 ?Refer=top_summary 或类似的热搜接口。实际接口可能是 https://weibo.com/ajax/statuses/hot_band(需确认)。
  4. 点击该请求,查看 Preview,确认返回的是热搜数据。
  5. 查看 Headers,复制完整的 URL、Request Headers(重点是 User-Agent、Referer、Cookie)。
  6. 注意:可能需要登录 Cookie,可以在浏览器登录后复制 Cookie。

8.3 代码实现(以最新接口为例,可能需要调整)

python 复制代码
import requests
import time
import json

# 如果接口需要 Cookie,先复制到下面
cookies = {
    'SUB': '...',  # 你的 Cookie
}

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Referer': 'https://s.weibo.com/top/summary',
}

url = 'https://weibo.com/ajax/statuses/hot_band'  # 示例,可能已变

response = requests.get(url, headers=headers, cookies=cookies)
data = response.json()

# 提取热搜列表
hot_list = data['data']['band_list']  # 根据实际结构调整
result = []
for idx, item in enumerate(hot_list[:50], start=1):
    word = item.get('word', '')
    hot = item.get('raw_hot', '') or item.get('num', '')
    result.append({
        'rank': idx,
        'word': word,
        'hot': hot
    })

# 保存到 JSON
with open('weibo_hot.json', 'w', encoding='utf-8') as f:
    json.dump(result, f, ensure_ascii=False, indent=2)

print('爬取完成,共', len(result), '条')

8.4 常见问题

  • 接口返回空数据:可能是 Cookie 失效,需要更新。
  • 请求频率过快 :加上 time.sleep
  • 找不到接口:可能接口名称变化,需重新分析。也可以尝试抓包手机 App 版。

🎯 第9章 实战二:爬取拉勾网职位信息(动态渲染)

9.1 目标

  • 爬取拉勾网 Python 职位信息(职位名称、公司、薪资、地点、经验要求)
  • 要求:先尝试分析 Ajax 接口,若失败则用 Selenium 模拟滚动加载

9.2 分析 Ajax 接口(首选)

  1. 打开拉勾网 Python 职位页面:https://www.lagou.com/zhaopin/Python/
  2. 打开开发者工具 Network → XHR,刷新页面,并向下滚动加载更多。
  3. 观察请求,可能会发现 https://www.lagou.com/jobs/positionAjax.json 或类似的接口。
  4. 查看请求参数,可能有 cityneedAddtionalResultisSchoolJobpageNopageSize 等。
  5. 拉勾网的反爬较强,需要设置请求头,尤其是 RefererCookie,且参数可能包含加密的 signtoken
  6. 如果参数简单且没有加密,可以直接模拟。

示例代码(假设接口可用)

python 复制代码
import requests
import time

url = 'https://www.lagou.com/jobs/positionAjax.json'
headers = {
    'User-Agent': 'Mozilla/5.0',
    'Referer': 'https://www.lagou.com/zhaopin/Python/',
    'Cookie': '你的Cookie',  # 拉勾通常需要登录
}
params = {
    'city': '全国',
    'needAddtionalResult': False,
    'isSchoolJob': False,
    'pageNo': 1,
    'pageSize': 15,
}
response = requests.post(url, data=params, headers=headers)
data = response.json()
print(data)

如果返回 {"status": false, "msg": "您操作太频繁,请稍后再访问"},说明触发了反爬,此时需要考虑 Selenium。

9.3 使用 Selenium 模拟

当 Ajax 接口难以模拟时,用 Selenium 操作真实浏览器,模拟用户滚动加载。

9.3.1 思路
  • 打开职位列表页
  • 不断滚动到底部,等待新内容加载
  • 提取所有职位卡片的信息
  • 控制滚动次数以获取足够多数据
9.3.2 代码实现
python 复制代码
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import json

# 配置浏览器选项,尝试绕过检测
options = webdriver.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_experimental_option('useAutomationExtension', False)

driver = webdriver.Chrome(options=options)
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")

# 打开拉勾网 Python 职位页
driver.get('https://www.lagou.com/zhaopin/Python/')

# 等待职位列表加载
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'item__title')))

# 模拟滚动加载,获取更多数据
for i in range(5):  # 滚动5次
    driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
    time.sleep(2)  # 等待新数据加载

# 提取所有职位项
job_items = driver.find_elements(By.CLASS_NAME, 'item__wrap')
results = []
for item in job_items:
    try:
        title = item.find_element(By.CLASS_NAME, 'item__title').text
        company = item.find_element(By.CLASS_NAME, 'item__company').text
        salary = item.find_element(By.CLASS_NAME, 'item__salary').text
        location = item.find_element(By.CLASS_NAME, 'item__location').text
        # 可能还有其他字段
        results.append({
            'title': title,
            'company': company,
            'salary': salary,
            'location': location
        })
    except:
        continue

driver.quit()

# 保存
with open('lagou_jobs.json', 'w', encoding='utf-8') as f:
    json.dump(results, f, ensure_ascii=False, indent=2)

print(f'共爬取 {len(results)} 条职位信息')
9.3.3 注意事项
  • 拉勾网可能会弹出登录框,需要手动登录或预先登录。可以在代码启动后,手动扫码登录,然后再执行爬取。
  • 页面结构可能会变,需要根据实际调整选择器。
  • 滚动加载可能触发反爬,适当增加延时,或使用随机等待时间。

9.4 使用 Playwright 替代

Playwright 更现代,自动等待且不易被检测。示例:

python 复制代码
from playwright.sync_api import sync_playwright
import time

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto('https://www.lagou.com/zhaopin/Python/')
    
    # 等待列表加载
    page.wait_for_selector('.item__title')
    
    # 滚动5次
    for _ in range(5):
        page.evaluate('window.scrollTo(0, document.body.scrollHeight)')
        page.wait_for_timeout(2000)
    
    # 提取所有职位
    jobs = page.query_selector_all('.item__wrap')
    results = []
    for job in jobs:
        title = job.query_selector('.item__title').inner_text()
        company = job.query_selector('.item__company').inner_text()
        salary = job.query_selector('.item__salary').inner_text()
        location = job.query_selector('.item__location').inner_text()
        results.append({'title': title, 'company': company, 'salary': salary, 'location': location})
    
    browser.close()
    print(results)

📝 第10章 总结与进阶

10.1 本阶段核心能力

  • 能够分析 Ajax 请求,直接获取数据,效率高且稳定。
  • 掌握 Selenium/Playwright,处理复杂动态页面。
  • 理解等待机制,避免因加载延迟导致的错误。
  • 能够绕过基础的 WebDriver 检测。

10.2 常见反爬与应对总结

反爬手段 应对方法
无接口或接口加密 使用 Selenium/Playwright 渲染
IP 频率限制 使用代理池、增加延时
登录验证 预先登录,保存 Cookie
WebDriver 检测 修改 navigator.webdriver,使用 Playwright
验证码 手动介入或接入打码平台

10.3 下一步建议

  • 进入阶段四:反爬虫对抗,学习代理池、验证码识别、指纹浏览器等。
  • 学习 Scrapy 框架,提高开发效率。
  • 研究 App 爬虫,进入移动端领域。

⚠️ 法律与道德提醒

  • 爬取微博、拉勾等商业网站时,请控制频率,不要对服务器造成压力。
  • 尊重网站的 robots.txt,遵守相关法律法规。
  • 本练习仅供学习,请勿用于商业用途或恶意攻击。

按照本阶段文档的指导,动手完成两个实战练习,你将真正掌握动态网页爬取的核心技能。如果在实践中遇到问题,欢迎随时交流!

相关推荐
MoRanzhi12032 小时前
Pillow 图像滤波、卷积与边缘处理
图像处理·python·计算机视觉·pillow·卷积·边缘检测·图像滤波
南 阳2 小时前
Python从入门到精通day48
开发语言·python
虎大猫猫2 小时前
JupyterLab的安装与使用完全指南
ide·python·jupyter
web3.08889992 小时前
如何确保1688商品数据API接口的安全性
python
失败才是人生常态2 小时前
大数据基础学习
大数据·学习
<-->2 小时前
SGLang 相比 vLLM 的主要优势
人工智能·pytorch·python·transformer
星幻元宇VR2 小时前
VR社区安全学习机:居民安全教育新选择
科技·学习·安全·vr·虚拟现实
夫唯不争,故无尤也2 小时前
Agent 开发者如何快速上手 SQL:从表设计到 Python 交互的一篇实战入门
python·sql·交互