查看全课大纲(第 19 / 101 节)
- 1.数据分析基本概念
- 2.学习数据分析的一般路线
- 3.数据分析的流程
- 4.数据类型
- 5.环境部署(1)
- 6.环境部署(2)
- 7.课程介绍
- 8.TXT文件操作
- 9.JSON文件操作
- 10.CSV文件操作
- 11.Excel文件操作
- 12.数据库及SQL常用语法
- 13.数据库基本操作
- 14.数据库多表连接
- 15.实战:欧洲职业足球数据库分析
- 16.爬虫简介
- 17.URL管理模块
- 18.网页下载模块
- 19.网页解析模块(1)
- 20.网页解析模块(2)
- 21.Scrapy简介
- 22.Scrapy使用步骤(1)
- 23.Scrapy使用步骤(2)
- 24.Scrapy使用步骤(3)
- 25.Scrapy使用步骤(4)
- 26.实战:获取国内城市空气质量指数数据
- 27.NumPy和SciPy介绍
- 28.多维数组
- 29.多维数组操作
- 30.NumPy的常用方法
- 31.向量化介绍
- 32.向量化及通用函数
- 33.实战:2016美国大选分析
- 34.数据结构-Series
- 35.数据结构-DataFrame
- 36.数据结构-Index
- 37.Series的索引操作
- 38.DataFrame的索引操作
- 39.索引操作总结
- 40.运算与对齐
- 41.函数应用操作(1) -- map
- 42.函数应用操作 (2) -- apply applymap
- 43.文件读写操作
- 44.排序操作
- 45.数据清洗--处理缺失数据
- 46.数据清洗--处理重复数据
- 47.数据清洗--替换数据
- 48.常用统计方法(1) -- describe quantile
- 49.常用统计方法(2) -- sum mean median count
- 50.常用统计方法(3) -- max min idxmax idxmin
- 51.常用统计方法(4) -- mad var std cumsum
- 52.实战:全球食品数据分析
- 53.层级索引
- 54.分组与聚合介绍
- 55.分组操作(1) -- GroupBy对象及常用聚合操作
- 56.分组操作(2) -- 自定义分组及聚合操作
- 57.透视表介绍
- 58.透视表操作
- 59.数据规整(1) -- 数据合并concat
- 60.数据规整(2) -- 数据连接merge
- 61.数据重构(3) -- 数据重构stack unstack
- 62.实战:互联网电影资料库分析
- 63.探索性数据分析EDA介绍
- 64.EDA的目的
- 65.EDA常用工具
- 66.Matplotlib绘图基本介绍
- 67.Matplotlib画布
- 68.散点图和柱状图的绘制
- 69.直方图的绘制
- 70.矩阵绘图
- 71.子图的使用
- 72.Matplotlib颜色、标记、线型
- 73.Matplotlib坐标刻度、标签、图例、标题
- 74.Seaborn介绍
- 75.数据集分布可视化(1) -- 单变量分布、双变量分布
- 76.数据集分布可视化(2) -- 变量关系可视化
- 77.类别数据可视化 -- 类别散布图、类别内数据分布、类别内统计图
- 78.交互式数据可视化工具Bokeh介绍
- 79.Bokeh绘制散点图、柱状图、盒子图、弦图
- 80.Bokeh绘制常用图形元素
- 81.3D绘图 -- mplot3d
- 82.3D曲线可视化
- 83.3D散点图可视化
- 84.3D柱状图可视化
- 85.Pandas绘图
- 86.实战:Lending Club借贷数据探索性分析及可视化
- 87.机器学习介绍及应用场景
- 88.机器学习建模介绍 (1) -- 分类
- 89.机器学习建模介绍 (2) -- 回归
- 90.机器学习建模介绍 (3) -- 聚类
- 91.机器学习分类
- 92.机器学习工具scikit-learn
- 93.使用scikit-learn的流程
- 94.数据集准备及划分
- 95.模型选择
- 96.数据预处理及特征工程
- 97.过拟合与欠拟合
- 98.模型调参介绍
- 99.模型调参方法
- 100.模型测试及评价
- 101.实战:通过移动设备行为数据预测性别和年龄
网页解析模块(1)
约 13 分钟
网页解析模块(1)
小象实战讲义 · Python数据分析实战
当我们从网络下载到网页内容后,面对的是一长串 HTML 代码字符串。如何从这“一锅乱炖”的字符串中,精准地捞出我们想要的数据“食材”?这就是网页解析模块的核心任务。本节将带你认识网页的结构化本质,并学习使用强大的 BeautifulSoup 工具来“品尝”网页,提取所需信息。
💡 核心导读
- 网页解析的目的:从已下载的 HTML 字符串中提取结构化或感兴趣的数据。
- 网页的结构化本质:理解 DOM(文档对象模型)树状结构是高效解析的基础。
- BeautifulSoup 简介:一个功能强大的 Python 库,专门用于结构化网页解析。
- BeautifulSoup 核心三步:创建解析对象、查找节点、获取节点信息。
- 查找节点的多种方式:可按标签类型、属性、文本内容等多种规则进行精确查找。
网页解析:从字符串到结构化数据
网络爬虫流程中,下载模块负责获取网页的原始字节流,并将其解码为字符串。接下来的挑战是:如何从这个字符串中提取出我们需要的信息?例如,新闻的标题、商品的价格、所有的超链接等。
网页解析模块正是为此而生。它的任务是从已下载的网页字符串中解析出所需的内容。实现解析的方式有多种,本质上都是对字符串进行操作:
- 字符串匹配(如正则表达式):制定一套规则,在字符串中搜索匹配该规则的子串。这种方式灵活但编写复杂规则有一定门槛。
- Python 自带的
html.parser:一个基础的 HTML 解析工具,可以处理简单的 HTML 结构。 - BeautifulSoup:我们将重点介绍的第三方库,它提供了非常便捷和强大的结构化网页解析能力。
理解网页的结构:DOM 树
为什么可以进行“结构化”解析?因为网页(HTML)本身就不是一团乱麻,而是一种有严密层次结构的文档。这种结构标准被称为 DOM(Document Object Model,文档对象模型)。
DOM 将 HTML 文档表示为一个树形结构。树中的每个分支的末端都是一个节点(Node),每个节点都代表一个 HTML 元素、属性或文本内容。
我们来看一个简单的 HTML 例子及其对应的 DOM 树:
<!DOCTYPE html>
<html>
<head>
<title>HTML Document</title>
</head>
<body>
<h1>Document的结构</h1>
<p>这是一个包含<a href="link.html">链接</a>的段落。</p>
</body>
</html>Document (根)
|
└── <html> (根元素)
|
├── <head>
| |
| └── <title>
| |
| └── 文本: "HTML Document"
|
└── <body>
|
├── <h1>
| |
| └── 文本: "Document的结构"
|
└── <p>
|
├── 文本: "这是一个包含"
|
├── <a href="link.html">
| |
| └── 文本: "链接"
|
└── 文本: "的段落。"如上所示,整个文档构成一棵树。<html> 是根元素,包含 <head> 和 <body> 两个子节点。<head> 下又有 <title>,<title> 下包含文本节点。<body> 下包含 <h1> 和 <p>,<p> 中又嵌套了 <a> 链接标签,链接标签拥有 href 属性,并包含自己的文本节点。
正是这种树状结构,使得我们可以像在文件系统中导航文件夹一样,沿着特定的路径(标签嵌套关系)或根据节点的特征(标签名、属性),精准地定位并提取出我们想要的“节点”及其包含的信息。 BeautifulSoup 就是一个帮助我们轻松完成这项导航和提取工作的“向导”。
初识 BeautifulSoup
BeautifulSoup 是一个 Python 库,它的名字寓意着能够帮助我们优雅地“品尝”(解析)网页这锅“汤”。它能够自动将复杂的 HTML 字符串转换为一个复杂的树形结构(Soup 对象),并提供了简单易用的方法来搜索和修改这棵树。
使用 BeautifulSoup 通常遵循以下三个步骤:
- 创建 BeautifulSoup 对象:将网页内容(字符串或文件对象)和指定的解析器传入,构造一个可操作的解析对象。
- 查询节点:使用
find()或find_all()等方法,在树中定位一个或多个符合条件的节点。 - 获取节点信息:从找到的节点对象中,提取其文本内容、属性值等信息。
步骤一:创建解析对象
要使用 BeautifulSoup,首先需要导入它。虽然原课中使用了 requests 库获取网页,但根据本课依赖白名单,我们将使用 Python 标准库进行演示。同时,为了完全自包含,我们将直接使用硬编码的 HTML 字符串作为示例。
# 示例:使用硬编码的HTML字符串演示BeautifulSoup基础
html_doc = """
<html>
<head><title>测试页面</title></head>
<body>
<p class="intro">这是一个介绍段落。</p>
<p>这是另一个段落,包含一个<a href="http://example.com/page1" class="link" id="first">链接一</a>。</p>
<p>这里还有第二个<a href="http://example.com/page2" class="link">链接二</a>。</p>
</body>
</html>
"""
# 由于环境限制,我们无法实际运行bs4,以下代码逻辑基于BeautifulSoup的典型用法进行说明。
# 在实际环境中,创建对象的代码类似:
# from bs4 import BeautifulSoup
# soup = BeautifulSoup(html_doc, 'html.parser') # 使用Python内置解析器
# 参数说明:
# 1. html_doc: 要解析的HTML字符串或文件对象。
# 2. 'html.parser': 指定使用的解析器。还可以是'lxml'(更快,需安装)或'html5lib'(容错性强)。
# 3. from_encoding='utf-8': 可指定编码,确保中文等字符正确解析。
print("已创建模拟的HTML文档用于解析演示。")已创建模拟的HTML文档用于解析演示。步骤二与三:查找与获取节点信息
创建 Soup 对象后,就可以开始查找节点了。最常用的两个方法是 find() 和 find_all()。
find(name, attrs, ...):返回第一个匹配的标签。find_all(name, attrs, ...):返回一个包含所有匹配标签的列表。
查找时,可以按多种规则进行:
按标签名查找:传入标签名的字符串。
soup.find_all('p')# 查找所有<p>标签soup.find('title')# 查找第一个<title>标签
按属性查找:使用关键字参数。属性名和要匹配的值构成
属性名=值的形式。- 查找
href属性为"http://example.com/page1"的<a>标签:soup.find_all('a', href='http://example.com/page1') - 查找
class属性为"link"的<a>标签(注意:class是 Python 关键字,需加下划线class_):soup.find_all('a', class_='link') - 可以组合多个属性条件:
soup.find_all('a', class_='link', href='http://example.com/page2')
- 查找
按文本内容查找:使用
string参数。- 查找文本内容为
“链接一”的标签:soup.find_all('a', string='链接一')(返回符合条件的<a>Tag 对象列表) - 注意区分:
soup.find_all(string='链接一')(不带标签名)返回的是文本节点本身(NavigableString对象),而不是包含它的 Tag——两种写法的结果类型不同,按需选用。
- 查找文本内容为
找到节点(Tag 对象)后,可以轻松获取其信息:
- 获取标签名:
tag.name - 获取文本内容:
tag.text或tag.get_text() - 获取属性值:像字典一样访问,
tag['href']或使用tag.get('href')
为了更直观地理解字符串解析与结构化解析的区别,我们用一个简单的例子模拟字符串查找:
# 模拟使用字符串查找方法提取第一个<li>标签内的文本(非BeautifulSoup方式)
html_fragment = '<ul id="fruits">\n <li class="fruit">苹果</li>\n <li class="fruit">香蕉</li>\n</ul>'
# 找到第一个`<li>`标签的开始和结束位置
start_tag_start = html_fragment.find('<li') # 找到'<li'的位置
start_tag_end = html_fragment.find('>', start_tag_start) + 1 # 定位到开始标签的'>'之后
end_tag_start = html_fragment.find('</li>', start_tag_end) # 找到对应的结束标签开始位置
fruit_text = html_fragment[start_tag_end:end_tag_start].strip() # 截取中间的文本并去除空白
print(f"使用字符串查找提取的第一个水果是:{fruit_text}")
print("说明:这种方式需要精确计算位置,对于复杂或变化的HTML结构非常脆弱。")使用字符串查找提取的第一个水果是:苹果
说明:这种方式需要精确计算位置,对于复杂或变化的HTML结构非常脆弱。实战演练:解析思路分析
原课程中,讲师以百度首页为例,演示了如何查找标题、第一个链接、所有链接,以及特定样式(class="mnav")的链接。虽然我们无法在此运行依赖 requests 和真实网络的代码,但可以完全复现其解析逻辑。
核心思路如下:
- 获取网页 HTML 内容(原课用
requests.get(),我们这里用硬编码字符串模拟)。 - 用
BeautifulSoup(html_content, 'html.parser')创建解析对象。 - 使用
soup.find('title')获取页面标题。 - 使用
soup.find('a')获取页面第一个链接标签,通过.text和['href']获取其文本和链接地址。 - 使用
soup.find_all('a')获取页面所有链接。 - 通过审查元素发现顶部导航链接都有
class="mnav"的特征,于是使用soup.find_all('a', class_='mnav')精准提取出这些导航链接。
下面的代码块模拟了上述第3到第6步的解析逻辑(使用我们之前定义的 html_doc 作为模拟数据):
# 模拟BeautifulSoup解析流程(逻辑演示)
# 假设soup是已经创建好的BeautifulSoup对象,对应之前定义的html_doc
print("【模拟解析流程】")
print("1. 查找标题标签(find('title')):")
print(" 结果: <title>测试页面</title>")
print(" 获取文本: '测试页面'")
print()
print("2. 查找第一个链接标签(find('a')):")
print(" 结果: <a class=\"link\" href=\"http://example.com/page1\" id=\"first\">链接一</a>")
print(" 获取href属性: 'http://example.com/page1'")
print(" 获取文本: '链接一'")
print()
print("3. 查找所有链接标签(find_all('a')):")
print(" 结果: 一个包含2个<a>标签的列表")
print(" 列表内容: [<a ...>链接一</a>, <a ...>链接二</a>]")
print()
print("4. 查找所有class为'link'的链接标签(find_all('a', class_='link')):")
print(" 结果: 一个包含2个<a>标签的列表(两个链接class都是'link')")
print(" 列表内容: [<a ...>链接一</a>, <a ...>链接二</a>]")
print()
print("5. 查找id为'first'的链接标签(find_all('a', id='first')):")
print(" 结果: 一个包含1个<a>标签的列表")
print(" 列表内容: [<a ...>链接一</a>]")【模拟解析流程】
1. 查找标题标签(find('title')):
结果: <title>测试页面</title>
获取文本: '测试页面'
2. 查找第一个链接标签(find('a')):
结果: <a class="link" href="http://example.com/page1" id="first">链接一</a>
获取href属性: 'http://example.com/page1'
获取文本: '链接一'
3. 查找所有链接标签(find_all('a')):
结果: 一个包含2个<a>标签的列表
列表内容: [<a ...>链接一</a>, <a ...>链接二</a>]
4. 查找所有class为'link'的链接标签(find_all('a', class_='link')):
结果: 一个包含2个<a>标签的列表(两个链接class都是'link')
列表内容: [<a ...>链接一</a>, <a ...>链接二</a>]
5. 查找id为'first'的链接标签(find_all('a', id='first')):
结果: 一个包含1个<a>标签的列表
列表内容: [<a ...>链接一</a>]📝 动手练一练
概念辨析:正则表达式、
html.parser和 BeautifulSoup 在解析网页时各有何特点?分别适用于什么场景?👉 点击查看参考答案
正则表达式:基于模式匹配字符串,非常灵活和强大,但编写复杂的HTML解析规则较为繁琐且难以维护,适合提取格式固定、结构简单的文本片段。
html.parser:Python标准库自带,无需安装额外依赖,能进行基本的HTML解析,生成树状结构,但处理有错误或不规范的HTML时可能不如其他解析器健壮。
BeautifulSoup:是一个第三方库,它提供了一个非常友好和强大的API来解析HTML/XML。它通常搭配一个底层解析器(如html.parser,lxml)工作,能自动修正许多常见的HTML编写错误,使得查找、遍历和修改解析树变得极其简单直观,是进行复杂网页数据提取的首选工具。代码实践:假设你有一个HTML字符串
'<div><span class="price">¥29.9</span><span class="price">¥49.9</span></div>'。请描述如何使用BeautifulSoup(模拟代码逻辑)提取出所有价格文本(29.9和49.9)?👉 点击查看参考答案
# 模拟代码逻辑 # 1. 创建BeautifulSoup对象 # soup = BeautifulSoup(html_string, 'html.parser') # 2. 查找所有class为'price'的span标签 # price_tags = soup.find_all('span', class_='price') # 3. 遍历找到的标签,提取文本并处理 # prices = [] # for tag in price_tags: # text = tag.text # 例如得到'¥29.9' # price_num = text.replace('¥', '') # 去除货币符号,得到'29.9' # prices.append(float(price_num)) # 转换为浮点数 # print(prices) # 输出: [29.9, 49.9]核心步骤:
find_all按类和标签名定位节点 -> 循环遍历节点列表 -> 使用.text获取原始文本 -> 进行字符串清洗(如去除“¥”) -> 转换为所需数据类型。
本章小结
本节我们深入了网络数据获取流程中的关键一环——网页解析。我们认识到网页并非无结构的文本,而是基于DOM的树形结构,这为精准数据提取提供了可能。BeautifulSoup库凭借其简洁的API,成为解析这类结构化数据的利器。我们学习了其核心的使用流程:创建对象、查找节点、获取信息,并掌握了按标签名、属性、文本等多种方式定位节点的技巧。
📋 行动清单
- 在本地Python环境中安装
beautifulsoup4库(pip install beautifulsoup4),并尝试运行讲义中的模拟逻辑代码(需替换为真实的BeautifulSoup调用)。 - 打开一个你常浏览的网页,使用浏览器的“开发者工具”(F12)查看其HTML结构,尝试识别出某个特定信息(如文章标题、商品价格)所在的标签及其属性特征。
- 思考:如果网页数据是通过JavaScript动态加载的,直接下载HTML源码可能找不到数据。这引出了爬虫的另一个挑战,你知道有哪些常见的解决方案吗?(提示:这与下节课可能涉及的内容有关。)
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。
- 下载本节课件:网页解析模块(1)PDF · 355KB
- 下载全套课件打包(第1-5章)ZIP · 12.8MB
- 下载全套课件打包(第6-8章)ZIP · 15MB
- 下载实战数据集:AppleStore 应用商城分析ZIP · 329KB
- 下载实战数据集:女性服装电商分析ZIP · 2.8MB
- 下载Python 数据分析环境搭建指南PDF · 2MB
- 下载Scrapy 安装教程PDF · 12.7MB
- 下载附加实战项目:AppleStore 应用商城数据分析ZIP · 0.3MB · ipynb + CSV 数据
- 下载附加实战项目:银行电话营销数据分析ZIP · 0.4MB · ipynb + CSV 数据
- 下载附加实战项目:女性服装电商评论数据分析ZIP · 2.7MB · ipynb + CSV 数据
- 下载附加实战项目:美国化学学会杂志数据分析ZIP · 34.2MB · ipynb + SQLite 数据库