html.parser 是 Python 标准库的一部分,所以您无需额外安装,可以直接导入使用,它不像 BeautifulSoup 或 lxml 那样功能强大和方便,但对于简单的解析任务,或者在不希望安装第三方依赖的场景下,它是一个非常轻量级的选择。

html.parser 的工作原理
html.parser 的工作方式是事件驱动的,它不会一次性将整个 HTML 文档解析成一个树状结构,而是当解析器遇到 HTML 的特定部分(如开始标签、结束标签、数据等)时,会触发相应的事件。
我们的核心任务就是创建一个自定义的类,继承自 html.parser.HTMLParser,然后重写这些特定的事件处理方法。
核心步骤
- 导入模块:
from html.parser import HTMLParser - 创建子类:定义一个继承自
HTMLParser的类。 - 重写方法:重写以下关键方法来处理不同的事件:
handle_starttag(tag, attrs): 当遇到一个开始标签时被调用(<div>)。handle_endtag(tag): 当遇到一个结束标签时被调用(</div>)。handle_data(data): 当遇到标签内的文本数据时被调用。handle_startendtag(tag, attrs): 当遇到一个自闭合标签时被调用(<img />)。
- 实例化并使用:创建你自定义解析器的实例,然后用
feed()方法喂给它 HTML 内容。 - 获取结果:在解析过程中,将提取的数据存储到你自定义类的属性中。
实战示例:从网页中提取所有链接
假设我们想从一个简单的 HTML 字符串中提取出所有 <a> 标签的 href 属性值。
示例代码
from html.parser import HTMLParser
import urllib.request # 用于从网络下载HTML内容
# 1. 创建一个自定义的解析器类
class MyHTMLParser(HTMLParser):
def __init__(self):
# 必须调用父类的初始化方法
super().__init__()
# 创建一个列表来存储找到的链接
self.links = []
# 2. 重写处理开始标签的方法
def handle_starttag(self, tag, attrs):
# 我们只关心 <a> 标签
if tag == 'a':
# attrs 是一个包含 (属性名, 属性值) 元组的列表
# [('href', 'http://example.com'), ('class', 'link')]
for attr in attrs:
# 如果属性名是 'href'
if attr[0] == 'href':
# 将链接添加到我们的列表中
self.links.append(attr[1])
print(f"找到链接: {attr[1]}")
# (可选) 添加一个方法来获取最终结果
def get_links(self):
return self.links
# --- 主程序 ---
# 模拟一个HTML字符串
html_string = """
<html>
<head><title>一个测试页面</title></head>
<body>
<h1>欢迎!</h1>
<p>这是一个段落,里面有一个链接 <a href="https://www.python.org">Python官网</a>。</p>
<p>这里是另一个链接,但可能没有 href:<a class="external-link">点击我</a></p>
<div>
<a href="/about.html">关于我们</a>
<img src="logo.png" alt="Logo" />
</div>
</body>
</html>
"""
# 3. 实例化我们的解析器
parser = MyHTMLParser()
# 4. 使用 feed() 方法将HTML内容喂给解析器
# 注意:feed() 方法可以处理不完整的HTML,多次调用也没问题
parser.feed(html_string)
# 5. 获取并打印结果
print("\n--- 所有提取的链接 ---")
all_links = parser.get_links()
for link in all_links:
print(link)
# 清空解析器,以便下次使用(如果需要)
parser.close()
代码解释
MyHTMLParser类:我们定义了自己的解析器。__init__:调用了父类的__init__,并初始化了一个self.links列表,用来存放我们找到的链接。handle_starttag(self, tag, attrs):这是核心。- 当解析器遇到任何开始标签(如
<html>,<p>,<a>),这个方法就会被调用。 tag参数是标签名(如'a')。attrs参数是一个元组列表,每个元组代表一个属性,格式如('属性名', '属性值')。- 我们检查
tag是否为'a'。 - 如果是,我们就遍历
attrs列表,查找属性名是否为'href'。 - 如果找到了,就把它的值(URL)添加到
self.links列表中,并打印出来。
- 当解析器遇到任何开始标签(如
parser.feed(html_string):这行代码启动了整个解析过程,解析器会逐个字符地分析html_string,并在遇到相应标签时调用我们重写的方法。parser.get_links():一个简单的辅助方法,用于获取最终收集到的所有链接。
如何从真实网站下载并解析 HTML?
上面的例子使用了字符串,我们来看如何从一个真实的 URL 下载 HTML 内容,然后用 html.parser 解析它,这里需要用到 urllib.request 模块。

from html.parser import HTMLParser
import urllib.request
import urllib.error
class NewsLinkParser(HTMLParser):
def __init__(self):
super().__init__()
self.news_links = []
# 我们可能只关心特定class的链接
self.target_class = "news-title"
def handle_starttag(self, tag, attrs):
# 假设新闻链接都在 <a> 标签里,并且有特定的 class
if tag == 'a':
# 检查是否有 'class' 属性
for attr_name, attr_value in attrs:
if attr_name == 'class' and self.target_class in attr_value:
# 还需要找到 href 属性
for href_name, href_value in attrs:
if href_name == 'href':
self.news_links.append(href_value)
print(f"找到新闻链接: {href_value}")
break # 找到href后就可以跳出内层循环了
def get_news_links(self):
return self.news_links
# --- 主程序:从网络获取数据并解析 ---
def fetch_and_parse(url):
print(f"正在尝试从 {url} 下载内容...")
try:
# 创建一个请求对象,可以添加 User-Agent 等头部信息,模拟浏览器访问
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
# 打开URL并读取内容
with urllib.request.urlopen(req) as response:
# 注意:一定要指定编码,否则可能会出错
# response.info().get_param('charset', 'utf-8') 可以尝试从响应头获取编码
html_content = response.read().decode('utf-8')
print("内容下载成功,开始解析...")
# 创建解析器实例
parser = NewsLinkParser()
# 喂给解析器
parser.feed(html_content)
# 获取结果
links = parser.get_news_links()
print("\n--- 所有提取的新闻链接 ---")
for link in links:
print(link)
return links
except urllib.error.URLError as e:
print(f"无法打开 URL {url},错误: {e.reason}")
return None
except Exception as e:
print(f"发生未知错误: {e}")
return None
# 示例:抓取某个新闻网站首页的链接(请替换为真实且允许抓取的网站)
# 注意:直接抓取商业网站首页可能很复杂,这里仅为演示
# target_url = "https://www.some-news-site.com"
# 为了演示,我们用一个更简单的、结构固定的页面
target_url = "https://www.w3schools.com/html/html_examples.asp"
fetch_and_parse(target_url)
html.parser 的优缺点
优点
- 无需安装:作为 Python 标准库的一部分,开箱即用。
- 轻量级:没有外部依赖,适合简单的脚本或对依赖有严格限制的环境。
- 纯 Python 实现:不依赖 C 扩展,在所有平台上行为一致。
缺点
- 功能有限:不像
BeautifulSoup那样提供便捷的 CSS 选择器(find,find_all)或强大的导航功能

