查看全课大纲(第 19 / 101 节)
  1. 1.数据分析基本概念
  2. 2.学习数据分析的一般路线
  3. 3.数据分析的流程
  4. 4.数据类型
  5. 5.环境部署(1)
  6. 6.环境部署(2)
  7. 7.课程介绍
  8. 8.TXT文件操作
  9. 9.JSON文件操作
  10. 10.CSV文件操作
  11. 11.Excel文件操作
  12. 12.数据库及SQL常用语法
  13. 13.数据库基本操作
  14. 14.数据库多表连接
  15. 15.实战:欧洲职业足球数据库分析
  16. 16.爬虫简介
  17. 17.URL管理模块
  18. 18.网页下载模块
  19. 19.网页解析模块(1)
  20. 20.网页解析模块(2)
  21. 21.Scrapy简介
  22. 22.Scrapy使用步骤(1)
  23. 23.Scrapy使用步骤(2)
  24. 24.Scrapy使用步骤(3)
  25. 25.Scrapy使用步骤(4)
  26. 26.实战:获取国内城市空气质量指数数据
  27. 27.NumPy和SciPy介绍
  28. 28.多维数组
  29. 29.多维数组操作
  30. 30.NumPy的常用方法
  31. 31.向量化介绍
  32. 32.向量化及通用函数
  33. 33.实战:2016美国大选分析
  34. 34.数据结构-Series
  35. 35.数据结构-DataFrame
  36. 36.数据结构-Index
  37. 37.Series的索引操作
  38. 38.DataFrame的索引操作
  39. 39.索引操作总结
  40. 40.运算与对齐
  41. 41.函数应用操作(1) -- map
  42. 42.函数应用操作 (2) -- apply applymap
  43. 43.文件读写操作
  44. 44.排序操作
  45. 45.数据清洗--处理缺失数据
  46. 46.数据清洗--处理重复数据
  47. 47.数据清洗--替换数据
  48. 48.常用统计方法(1) -- describe quantile
  49. 49.常用统计方法(2) -- sum mean median count
  50. 50.常用统计方法(3) -- max min idxmax idxmin
  51. 51.常用统计方法(4) -- mad var std cumsum
  52. 52.实战:全球食品数据分析
  53. 53.层级索引
  54. 54.分组与聚合介绍
  55. 55.分组操作(1) -- GroupBy对象及常用聚合操作
  56. 56.分组操作(2) -- 自定义分组及聚合操作
  57. 57.透视表介绍
  58. 58.透视表操作
  59. 59.数据规整(1) -- 数据合并concat
  60. 60.数据规整(2) -- 数据连接merge
  61. 61.数据重构(3) -- 数据重构stack unstack
  62. 62.实战:互联网电影资料库分析
  63. 63.探索性数据分析EDA介绍
  64. 64.EDA的目的
  65. 65.EDA常用工具
  66. 66.Matplotlib绘图基本介绍
  67. 67.Matplotlib画布
  68. 68.散点图和柱状图的绘制
  69. 69.直方图的绘制
  70. 70.矩阵绘图
  71. 71.子图的使用
  72. 72.Matplotlib颜色、标记、线型
  73. 73.Matplotlib坐标刻度、标签、图例、标题
  74. 74.Seaborn介绍
  75. 75.数据集分布可视化(1) -- 单变量分布、双变量分布
  76. 76.数据集分布可视化(2) -- 变量关系可视化
  77. 77.类别数据可视化 -- 类别散布图、类别内数据分布、类别内统计图
  78. 78.交互式数据可视化工具Bokeh介绍
  79. 79.Bokeh绘制散点图、柱状图、盒子图、弦图
  80. 80.Bokeh绘制常用图形元素
  81. 81.3D绘图 -- mplot3d
  82. 82.3D曲线可视化
  83. 83.3D散点图可视化
  84. 84.3D柱状图可视化
  85. 85.Pandas绘图
  86. 86.实战:Lending Club借贷数据探索性分析及可视化
  87. 87.机器学习介绍及应用场景
  88. 88.机器学习建模介绍 (1) -- 分类
  89. 89.机器学习建模介绍 (2) -- 回归
  90. 90.机器学习建模介绍 (3) -- 聚类
  91. 91.机器学习分类
  92. 92.机器学习工具scikit-learn
  93. 93.使用scikit-learn的流程
  94. 94.数据集准备及划分
  95. 95.模型选择
  96. 96.数据预处理及特征工程
  97. 97.过拟合与欠拟合
  98. 98.模型调参介绍
  99. 99.模型调参方法
  100. 100.模型测试及评价
  101. 101.实战:通过移动设备行为数据预测性别和年龄

网页解析模块(1)

约 13 分钟

📺 正在播放小象学院官方高清录播(支持倍速与清晰度调节)

网页解析模块(1)

小象实战讲义 · Python数据分析实战

当我们从网络下载到网页内容后,面对的是一长串 HTML 代码字符串。如何从这“一锅乱炖”的字符串中,精准地捞出我们想要的数据“食材”?这就是网页解析模块的核心任务。本节将带你认识网页的结构化本质,并学习使用强大的 BeautifulSoup 工具来“品尝”网页,提取所需信息。

💡 核心导读

  • 网页解析的目的:从已下载的 HTML 字符串中提取结构化或感兴趣的数据。
  • 网页的结构化本质:理解 DOM(文档对象模型)树状结构是高效解析的基础。
  • BeautifulSoup 简介:一个功能强大的 Python 库,专门用于结构化网页解析。
  • BeautifulSoup 核心三步:创建解析对象、查找节点、获取节点信息。
  • 查找节点的多种方式:可按标签类型、属性、文本内容等多种规则进行精确查找。

网页解析:从字符串到结构化数据

网络爬虫流程中,下载模块负责获取网页的原始字节流,并将其解码为字符串。接下来的挑战是:如何从这个字符串中提取出我们需要的信息?例如,新闻的标题、商品的价格、所有的超链接等。

网页解析模块正是为此而生。它的任务是从已下载的网页字符串中解析出所需的内容。实现解析的方式有多种,本质上都是对字符串进行操作:

  1. 字符串匹配(如正则表达式):制定一套规则,在字符串中搜索匹配该规则的子串。这种方式灵活但编写复杂规则有一定门槛。
  2. Python 自带的 html.parser:一个基础的 HTML 解析工具,可以处理简单的 HTML 结构。
  3. 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 通常遵循以下三个步骤:

  1. 创建 BeautifulSoup 对象:将网页内容(字符串或文件对象)和指定的解析器传入,构造一个可操作的解析对象。
  2. 查询节点:使用 find() 或 find_all() 等方法,在树中定位一个或多个符合条件的节点。
  3. 获取节点信息:从找到的节点对象中,提取其文本内容、属性值等信息。

步骤一:创建解析对象

要使用 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, ...):返回一个包含所有匹配标签的列表。

查找时,可以按多种规则进行:

  1. 按标签名查找:传入标签名的字符串。

    • soup.find_all('p') # 查找所有 <p> 标签
    • soup.find('title') # 查找第一个 <title> 标签
  2. 按属性查找:使用关键字参数。属性名和要匹配的值构成 属性名=值 的形式。

    • 查找 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')
  3. 按文本内容查找:使用 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 和真实网络的代码,但可以完全复现其解析逻辑。

核心思路如下:

  1. 获取网页 HTML 内容(原课用 requests.get(),我们这里用硬编码字符串模拟)。
  2. 用 BeautifulSoup(html_content, 'html.parser') 创建解析对象。
  3. 使用 soup.find('title') 获取页面标题。
  4. 使用 soup.find('a') 获取页面第一个链接标签,通过 .text 和 ['href'] 获取其文本和链接地址。
  5. 使用 soup.find_all('a') 获取页面所有链接。
  6. 通过审查元素发现顶部导航链接都有 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>]

📝 动手练一练

  1. 概念辨析:正则表达式、html.parser 和 BeautifulSoup 在解析网页时各有何特点?分别适用于什么场景?

    👉 点击查看参考答案

    正则表达式:基于模式匹配字符串,非常灵活和强大,但编写复杂的HTML解析规则较为繁琐且难以维护,适合提取格式固定、结构简单的文本片段。
    html.parser:Python标准库自带,无需安装额外依赖,能进行基本的HTML解析,生成树状结构,但处理有错误或不规范的HTML时可能不如其他解析器健壮。
    BeautifulSoup:是一个第三方库,它提供了一个非常友好和强大的API来解析HTML/XML。它通常搭配一个底层解析器(如html.parser, lxml)工作,能自动修正许多常见的HTML编写错误,使得查找、遍历和修改解析树变得极其简单直观,是进行复杂网页数据提取的首选工具。

  2. 代码实践:假设你有一个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 数据库
    下载