项目三 动态网页数据解析

用 XPath(lxml)与 BeautifulSoup 从 HTML 中精准提取标题、时间、来源、正文。

解析第5-6周lxml · XPath · BeautifulSoup11 段代码

本项目学习目标

  • 能看懂 HTML 结构与节点关系
  • 能用 XPath 做层级、属性、位置、文本定位
  • 能用 BeautifulSoup 的 find / select 提取内容
  • 能把提取结果整理成字典或列表

本项目任务导览

01

动态网页数据解析

使用 XPath 解析"新闻动态"、使用 Beautiful Soup 解析"浪潮云说",掌握从 HTML 文档中精准提取数据的能力。

  • 项目导言与学习目标
  • 任务 3-1 使用 XPath 解析"新闻动态"
  • 任务 3-2 使用 Beautiful Soup 解析"浪潮云说"
  • 知识拓展与实例案例(3 例)
项目导言与学习目标

采集到网页源码之后,还需要从 HTML 中提取出真正需要的数据。

利用 Requests / Urllib 向目标网页发起请求,获取包含数据的 HTML 源码,这是数据采集的第一步。

在获取的 HTML 中,利用 XPath、Beautiful Soup 等解析技术定位并提取目标数据,这是本项目重点解决的问题。

掌握 XPath 的基本语法与元素定位方法; 掌握 lxml 库的安装与使用; 掌握 Beautiful Soup 解析库的安装与常见解析器; 掌握 Beautiful Soup 的标签选择器、方法选择器与 CSS 选择器。

能够使用 XPath 从 HTML 中提取元素与属性; 能够使用 Beautiful Soup 完成网页数据的精准解析; 能够综合使用解析技术完成数据提取任务。

03

任务 3-1 使用 XPath 解析"新闻动态"

XPath 是一门在 XML 文档中查找信息的语言,同样适用于 HTML 文档。

一、XPath 简介

XPath(XML Path Language)是一门在 XML/HTML 文档中查找信息的语言,通过路径表达式选取节点或节点集,是网页数据解析的常用技术。

  • 打开 cmd 命令窗口;
  • 执行 pip install lxml 命令安装 lxml 库;
  • 等待依赖包下载安装完成;
  • 在 Python 中通过 import lxml 验证安装。

二、etree 常用方法

lxml.etree 提供了对 HTML/XML 文档进行解析的多种方法。

方法说明
HTML()解析 HTML 字符串,返回 Element 对象。参数:text(HTML 文本)、parser(解析器)、base_url(基准 URL)
XML()解析 XML 字符串,返回 Element 对象
parse()从文件解析 HTML/XML 文档
tostring()将 Element 对象序列化为字符串
xpath()在元素上执行 XPath 表达式,返回匹配结果
参数说明
text要解析的 HTML 文本
parser指定解析器,可选 XMLParser、XMLPullParser、HTMLParser、HTMLPullParser
base_url基准 URL,用于解析相对路径

三、元素定位

符号含义
/从根节点选取
//从任意位置选取匹配的节点
.选取当前节点
..选取当前节点的父节点
|选取多个路径的并集
*匹配任何元素节点
nodeName[n]选取第 n 个子节点
last()选取最后一个节点
position()<n选取位置小于 n 的节点
node()匹配任何类型的节点
表达式含义
//div选取文档中所有 div 元素
//div/p/a[2]选取所有 div 下 p 下第 2 个 a 元素
//div[@id='a']选取 id 为 a 的 div 元素
//p/text()选取所有 p 元素的文本内容

四、属性定位

写法含义
//div/@属性名选取 div 元素指定属性(如 href、class、id)的值
//div/@*选取 div 元素的所有属性
//div[@属性='值']选取具有指定属性值的 div 元素(条件定位)

五、运算符

  • = 等于
  • != 不等于
  • < 小于
  • <= 小于等于
  • > 大于
  • >= 大于等于
  • and 与
  • or 或
  • not() 非
  • + 加
  • - 减
  • * 乘
  • div 除
  • mod 取模

六、数据提取

提取目标表达式
属性值提取nodeName/@属性名,如 //a/@href
元素内容提取nodeName/text(),如 //h3/text()
PYTHON
# XPath 解析代码示例
from lxml import etree
html = etree.HTML(page_source)
# 提取所有标题文本
titles = html.xpath('//h3/text()')
# 提取所有链接地址
links = html.xpath('//a/@href')

七、任务实施(共 7 步)

  • 采集"新闻动态"页面 HTML 源码;
  • 分析页面结构,确定新闻标题、链接等数据的位置;
  • 安装 lxml 库并导入 etree;
  • 使用 etree.HTML() 解析页面源码;
  • 编写 XPath 表达式提取新闻数据;
  • 使用循环遍历提取全部新闻条目;
  • 运行程序,输出并验证解析结果。
04

任务 3-2 使用 Beautiful Soup 解析"浪潮云说"

Beautiful Soup 是 Python 最流行的 HTML/XML 解析库,语法简单、功能强大。

一、安装与常见解析器

SHELL
pip install beautifulsoup4
解析器使用方法优势劣势
Python 标准库BeautifulSoup(markup, "html.parser")内置标准库、执行速度适中、容错能力强较老版本的容错能力稍差
lxml HTMLBeautifulSoup(markup, "lxml")速度快、文档容错能力强需要安装 C 语言库
lxml XMLBeautifulSoup(markup, "lxml-xml")速度快、唯一支持 XML 的解析器需要安装 C 语言库
html5libBeautifulSoup(markup, "html5lib")最好的容错性、以浏览器方式解析速度慢、需要额外依赖
参数说明
markup要解析的 HTML/XML 文档(字符串或文件对象)
parser指定使用的解析器(如 "html.parser"、"lxml")

二、标签选择器

通过 soup.标签名 直接选取标签,语法为 soup.name.node.parameter。

属性说明
name标签的名称
attrs['属性']标签的指定属性值,如 attrs['class']、attrs['href']
string标签内的文本内容
属性说明
contents直接子节点列表
children直接子节点生成器
descendants所有后代节点生成器
parent父节点
parents所有祖先节点生成器
next_sibling下一个兄弟节点
previous_sibling上一个兄弟节点
PYTHON
# 标签选择器示例
from bs4 import BeautifulSoup
soup = BeautifulSoup(page_source, "html.parser")
# 获取第一个 title 标签的文本
print(soup.title.string)
# 获取第一个 a 标签的 href 属性
print(soup.a.attrs['href'])

三、方法选择器

方法说明
find()查找符合条件的第一个节点,返回 Tag 对象或 None
find_all()查找所有符合条件的节点,返回列表。支持 name、attrs、string、limit 等参数
PYTHON
# 方法选择器示例
# 查找所有 div 标签
divs = soup.find_all('div')
# 查找 class 为 title 的第一个标签
title = soup.find(class_='title')
# 查找 id 为 main 的标签
main = soup.find(id='main')

四、CSS 选择器

通过 select() 方法使用 CSS 语法选择元素,返回列表。

选择器写法含义
select('title')选取所有 title 标签
select('.sister')选取所有 class 为 sister 的元素
select('#link')选取 id 为 link 的元素
select('div p')选取 div 内的所有 p 元素(后代选择器)
select('div > p')选取 div 的直接子 p 元素(子选择器)
select('a[href]')选取带有 href 属性的 a 元素(属性选择器)
PYTHON
# CSS 选择器示例
items = soup.select('.news-item a')
for a in items:
    print(a.get('href'), a.string)

五、任务实施(共 6 步)

  • 采集"浪潮云说"页面 HTML 源码;
  • 安装并导入 beautifulsoup4;
  • 创建 BeautifulSoup 对象并选择解析器;
  • 分析页面结构,使用标签选择器 / 方法选择器定位数据;
  • 使用 CSS 选择器补充提取复杂结构中的数据;
  • 运行程序,输出并验证解析结果。
05

知识拓展与实例案例

课堂讲解用:3 个可运行实例 + 知识拓展卡片。

知识拓展

实例 1:XPath 提取新闻列表(标题 + 链接)

目标:解析一段新闻列表 HTML,用 XPath 批量提取标题和链接地址。

PYTHON
# xpath_news.py
from lxml import etree

html = """
<div class="news-list">
  <a href="/news/1.html">学校召开教学改革会议</a>
  <a href="/news/2.html">运动会圆满落幕</a>
  <a href="/news/3.html">新图书馆正式开放</a>
</div>
"""
root = etree.HTML(html)

# 提取所有标题文本
titles = root.xpath('//div[@class="news-list"]/a/text()')
# 提取所有链接
links = root.xpath('//div[@class="news-list"]/a/@href')

for t, l in zip(titles, links):
    print(t, "→", l)
PYTHON
学校召开教学改革会议 → /news/1.html
运动会圆满落幕 → /news/2.html
新图书馆正式开放 → /news/3.html
代码白话解释
from lxml import etree从 lxml 库导入 etree 模块——它负责把 HTML 文本变成一棵"节点树",这样就能用路径查找了。
html = """ ... """三引号表示多行字符串:把一段 HTML 代码原样存进变量 html。实际项目中这里是 requests 抓回来的网页源码。
root = etree.HTML(html)让 etree 把 HTML 文本解析成一棵"树",root 是树的根,后面所有查找都从它开始。
//div[@class="news-list"]/a/text()XPath 路径://div 任意位置的 div;[@class="news-list"] 它的 class 属性等于 news-list;/a 它下面的 a 标签;text() 取文本内容。合起来:找到新闻列表里的所有链接文字。
root.xpath('.../a/@href')同上,但 @href 表示取 href 属性的值(链接地址),注意 @ 是"取属性"的固定写法。
for t, l in zip(titles, links):zip 把两个列表"按位置配对":第一条标题配第一条链接。循环依次取出每一对并打印。

实例 2:Beautiful Soup 提取表格数据

目标:解析一个课程表 HTML 表格,用 find_all 提取表头和每一行数据。

PYTHON
# bs_table.py
from bs4 import BeautifulSoup

html = """
<table>
  <tr><th>课程</th><th>时间</th><th>教室</th></tr>
  <tr><td>Python</td><td>周一 1-2 节</td><td>A101</td></tr>
  <tr><td>数据库</td><td>周三 3-4 节</td><td>B203</td></tr>
</table>
"""
soup = BeautifulSoup(html, "html.parser")

# 提取表头
headers = [th.get_text() for th in soup.find_all("th")]
print("表头:", headers)

# 提取每一行
for tr in soup.find_all("tr")[1:]:      # 跳过表头行
    cells = [td.get_text() for td in tr.find_all("td")]
    print("行:", cells)
PYTHON
表头: ['课程', '时间', '教室']
行: ['Python', '周一 1-2 节', 'A101']
行: ['数据库', '周三 3-4 节', 'B203']
代码白话解释
from bs4 import BeautifulSoup从 bs4 库导入 BeautifulSoup 类——它是整个解析工作的"入口工具"。
soup = BeautifulSoup(html, "html.parser")用 html.parser 解析器把 HTML 文本解析成 BeautifulSoup 对象 soup,之后所有查找都调用 soup 的方法。
soup.find_all("th")找出页面中所有 th 标签(表头单元格),返回一个列表。find_all 意为"找出所有",返回的是列表。
th.get_text()取出 th 标签里面的文字内容。get_text() 会把标签内所有文本提取出来,去掉尖括号。
for tr in soup.find_all("tr")[1:]:找到所有 tr 标签(表格行),[1:] 表示"跳过第一行"(第一行是表头),从第二行开始逐行处理。
cells = [td.get_text() for td in tr.find_all("td")]列表推导式:把当前行里每个 td 标签(普通单元格)的文本取出来,组成一个新列表 cells。可以理解成"把这一行的所有单元格文字装进一个列表"。

实例 3:CSS 选择器批量提取图片地址

目标:用 select() 按 CSS 选择器提取所有商品图片的 src 属性,并拼接完整 URL。

PYTHON
# bs_css.py
from bs4 import BeautifulSoup

html = """
<div class="goods">
  <img class="pic" src="/img/1.jpg" alt="手机">
  <img class="pic" src="/img/2.jpg" alt="耳机">
  <img class="pic" src="/img/3.jpg" alt="手表">
</div>
"""
soup = BeautifulSoup(html, "html.parser")
base = "https://www.example.com"

# CSS 选择器:类名 .pic,属性选择器 img[class=pic] 也等价
for img in soup.select(".goods img.pic"):
    full_url = base + img["src"]       # 相对路径 → 完整 URL
    print(img["alt"], "→", full_url)
PYTHON
手机 → https://www.example.com/img/1.jpg
耳机 → https://www.example.com/img/2.jpg
手表 → https://www.example.com/img/3.jpg
代码白话解释
base = "https://www.example.com"定义网站根地址。网页里的图片常用相对路径(如 /img/1.jpg),需要拼上根地址才能访问。
soup.select(".goods img.pic")select() 使用 CSS 选择器查找:.goods 表示 class 为 goods 的元素,空格表示"里面的",img.pic 表示 img 标签且 class 含 pic。合起来:goods 区域里所有 class 为 pic 的图片。
for img in soup.select(...):对找到的每个 img 标签循环处理。
img["src"]取出该 img 标签的 src 属性值(图片地址)。注意字典式的中括号取值语法。
full_url = base + img["src"]把根地址和相对路径拼接成完整 URL,如 https://www.example.com/img/1.jpg。
print(img["alt"], "→", full_url)打印图片的 alt 文字(替代文本)和完整地址,便于人工核对抓取是否正确。