一、 三种方式创建 BeautifulSoup 对象
将文档传入 BeautifulSoup 构造方法即可生成文档对象,常见数据源有三种:
- 传入字符串(HTML/XML片段)
直接解析一段字符串格式的网页代码。from bs4 import BeautifulSoup soup = BeautifulSoup("<html>data</html>", "html.parser") - 传入文件句柄(读取本地文件)
打开本地 HTML 文件进行解析,建议指定编码格式(如utf-8)避免乱码。# 基础写法(图中示例未指定解析器,实际使用时建议补充如 "html.parser") soup = BeautifulSoup(open("index.html"), "html.parser") # 推荐写法:指定编码并使用 prettify() 格式化输出 soup = BeautifulSoup(open("index.html", encoding="utf-8"), "html.parser") print(soup.prettify()) - 通过 URL 获取 HTML 文档
结合网络请求库(如urllib)获取网页源码后再解析。from bs4 import BeautifulSoup import urllib.request def gethtml(url): page = urllib.request.urlopen(url) html = page.read().decode("utf-8") return html html_doc = gethtml("http://www.cnblogs.com") soup = BeautifulSoup(html_doc, "html.parser") print(soup.prettify())
二、 对象的种类
BeautifulSoup 将复杂的 HTML 文档转换为树形结构,每个节点都是 Python 对象,主要归纳为 4 种类型:
- Tag:原生文档中的标签(如
<b>、<p>)。 - NavigableString:标签内部的文本内容。
- BeautifulSoup:整个文档的根对象。
- Comment:文档中的注释内容。
Tag 对象基础操作:
- 获取 Tag:通过
soup.标签名获取第一个匹配的标签。soup = BeautifulSoup('<b class="boldest">中间内容</b>', "html.parser") tag = soup.b print(type(tag)) # 输出: <class 'bs4.element.Tag'> - Name(标签名):通过
.name获取标签名称。print(tag.name) # 输出: b - Attributes(属性操作):属性操作方式与字典完全相同,支持获取、添加、修改、删除。
# 获取属性(多种方式) print(tag['class']) # 输出: ['boldest'] (或 'boldest' 视版本而定) print(tag.get('class')) # 修改/添加属性 tag['class'] = 'verybold' tag['id'] = 1
三、 多值属性
- HTML 中部分属性可包含多个值(最常见的是
class,还有rel、rev、accept-charset等)。 - 在 BeautifulSoup 中,多值属性被解析后返回的类型是列表(list)。
# 例如 <b class="boldest verybold"> 中 # tag['class'] 的返回值为 ['boldest', 'verybold']
以下是关于 BeautifulSoup 处理多值属性(以 class 为例)在不同场景下的返回值差异及核心要点:
一、 HTML 格式下的多值属性
在 HTML 文档中,class 属性支持同时指定多个值(以空格分隔)。BeautifulSoup 会将其自动解析为列表(list)类型。
from bs4 import BeautifulSoup
# 包含多个 class 值
css_soup = BeautifulSoup('<p class="body strikeout"></p>', 'html.parser')
print(css_soup.p['class'])
# 输出: ['body', 'strikeout'] (返回列表)
# 只包含单个 class 值
css_soup2 = BeautifulSoup('<p class="body"></p>', 'html.parser')
print(css_soup2.p['class'])
# 输出: ['body'] (即使只有一个值,依然返回单元素列表)Code language: PHP (php)
二、 XML 格式下的属性处理
如果文档以 XML 解析器(xml)进行转换,XML 规范中不包含多值属性的概念。此时属性值会被视为完整的纯字符串,不做拆分。
from bs4 import BeautifulSoup
xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
print(xml_soup.p['class'])
# 输出: 'body strikeout' (返回完整字符串,而非列表)Code language: PHP (php)
三、 核心差异对比
| 解析模式 | 代码示例 | tag['class'] 返回类型 | 返回值示例 |
|---|---|---|---|
| HTML 模式 | BeautifulSoup(html, 'html.parser') | 列表 (list) | ['body', 'strikeout'] |
| 单值 class | class="body" | 列表 (list) | ['body'] |
| XML 模式 | BeautifulSoup(xml, 'xml') | 字符串 (str) | 'body strikeout' |
四、 注意
- 默认解析器差异:图中代码未显式写出 HTML 解析器参数(如
html.parser),实际开发中建议始终补充,否则可能触发警告或依赖系统默认解析器(如 lxml)。 - 其他多值属性:除
class外,HTML 中的rel、rev、accept-charset等在 HTML 模式下同样返回列表,在 XML 模式下返回字符串。 - 属性操作一致性:获取时类型有差异,但修改方式一致(如
tag['class'] = 'new_class'或赋值为列表tag['class'] = ['a', 'b']),BeautifulSoup 会在输出时根据解析器类型自动处理格式。
例子
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://foxdevelop.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://foxdevelop.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://foxdevelop.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc)
print(soup.prettify())
print(soup.title)
for link in soup.find_all('a'):
print(link.get('href'))
print(soup.get_text())
soup2 = BeautifulSoup(open("index.html", encoding="utf-8"))
print(soup2.prettify())Code language: HTML, XML (xml)
远程抓取
from bs4 import BeautifulSoup
import urllib.request
def gethtml(url):
page = urllib.request.urlopen(url)
html = page.read().decode("utf-8")
return html
html_doc = gethtml("http://www.cnblogs.com")
soup = BeautifulSoup(html_doc)
print(soup.prettify())Code language: JavaScript (javascript)
属性 和对象
from bs4 import BeautifulSoup
soup = BeautifulSoup('<a></a><b class="boldest" sddsf="foxdevelop.com">中间内容</b>')
print(soup.b)
print(soup.a)
print(type(soup))
print(type(soup.b))
soup.b.name = "span"
print(soup)
# <span class="boldest">中间内容</span>
print(soup.span["class"][0])
# boldest
print(soup.span.get('sddsf'))
# foxdevelop.comCode language: PHP (php)