我们通过Requests请求url获取数据,请求把数据返回来之后就要提取目标数据,不同的网站返回的内容通常有多种不同的格式,一种是 json 格式,我们可以直接通过json.loads转换python的json对象处理。另一种 XML 格式的,还有一种最常见格式的是 HTML 文档,今天就来讲讲如何从 HTML 中提取出感兴趣的数据。
BeautifulSoup 是一个用于解析 HTML 文档的 Python 库,通过 BeautifulSoup,你只需要用很少的代码就可以提取出 HTML 中任何感兴趣的内容,此外,它还有一定的 HTML 容错能力,对于一个格式不完整的HTML 文档,它也可以正确处理。
pip install beautifulsoup4
初始化对象时可以直接传递字符串或者文件句柄
soup = BeautifulSoup(open("index.html"))
soup = BeautifulSoup("data")
支持多种解析接口
# python内置HTML解析
BeautifulSoup(markup, "html.parser")
# lxml语言支持HTML解析
BeautifulSoup(markup, "lxml")
# 解析XML引擎
BeautifulSoup(markup, "xml")
# 解析HTML5引擎
BeautifulSoup(markup, "html5lib")
下面是一段不规范的html,缺少闭合标签
html_doc = """
The Dormouse's story
The Dormouse's story
Once upon a time there were three little sisters; and their names were
Elsie,
Lacie and
Tillie;
and they lived at the bottom of a well.
...
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')
print(soup.prettify())
prettify()标准缩进格式的输出。输出内容如下:
<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 class="sister" href="http://example.com/elsie" id="link1">
Elsie
a>
,
<a class="sister" href="http://example.com/lacie" id="link2">
Lacie
a>
and
<a class="sister" href="http://example.com/tillie" id="link2">
Tillie
a>
; and they lived at the bottom of a well.
p>
<p class="story">
...
p>
body>
html>
# title标签
soup.title
# The Dormouse's story
# title标签名称
soup.title.name
# 'title'
# # title标签的文本字符内容
soup.title.string
# 'The Dormouse's story'
# title标签父节点名称
soup.title.parent.name
# 'head'
# 从前向后找到html孙节点第一个p节点
soup.p
# The Dormouse's story
# p节点的class属性
soup.p['class']
# ['title']
# 进栈出栈的方式找到第一个a标签
soup.a
# Elsie
# p节点的href属性
soup.a["href"]
# 'http://example.com/elsie'
soup.find_all('a')
# 同上
soup.find_all("p")[1].find_all("a")
# [Elsie,
# Lacie,
# Tillie]
soup.find(id="link3")
# Tillie
从根节点 html 标签开始遍历,元素进栈出栈,直到找到目标元素为止。
BeatifulSoup 将 HTML 抽象成为 4 类主要的数据类型:
type(soup)
#
type(soup.p)
#
# type(soup.p.string)
<class 'bs4.element.NavigableString'>
Tag标签
每个 Tag 都有一个名字,它对应 HTML 的标签名称。
soup.p.name
# 'p'
标签有属性,属性的访问方式和字典是类似的,它返回一个列表对象或字符串。
soup.p['class']
# ['title']
soup.a['href']
# 'http://example.com/elsie'
NavigableString
获取标签中的内容,直接使用 .stirng 即可获取,它是一个 NavigableString 对象 。
soup.p.string
# "The Dormouse's story"
type(soup.p.string)
bs4.element.NavigableString
搜索文档树是通过指定标签名来搜索元素,还可以通过指定标签的属性值来精确定位某个节点元素,最常用的两个方法就是 find 和 find_all。这两个方法在 BeatifulSoup 和 Tag 对象上都可以被调用。
find_all()方法
find_all( name , attrs , recursive , text , **kwargs )
第一个参数 name 是标签节点的名字。
# 所有p标签
soup.find_all("p")
# [The Dormouse's story
,
# Once upon a time there were three little sisters; and their names were
# Elsie,
# Lacie and
# Tillie;
# and they lived at the bottom of a well.,
# ...
]
第二个参数是标签的class属性值
soup.find_all("p","title")
# 同上
soup.find_all("p",class_ ="title")
# [The Dormouse's story
]
kwargs 是标签的属性名值对。
import re
# 支持使用标签属性
soup.find_all(href="http://example.com/lacie")
soup.find_all(id="link2")
# 支持使用正则
soup.find_all(href=re.compile("lacie"))
# [Lacie]
# 支持使用布尔类型
soup.find_all('a',id=True)
遍历和搜索相结合,先定位到 body 标签,再从 body 中找 a 标签.。
soup.body.find_all('a',id=True)
find()方法
find 方法跟 find_all 类似,唯一不同的地方是,它返回的单个 Tag 对象而非列表,如果没找到匹配的节点则返回 None。如果匹配多个 Tag,只返回第0个。
soup.body.find("a")
# Elsie
get_text()方法
获取标签里面内容,除了可以使用 .string 之外,还可以使用 get_text 方法,不同的地方在于前者返回的一个 NavigableString 对象,后者返回的是 字符串。
soup.body.find("a").get_text()
# Elsie
实际场景中我们一般使用 get_text 方法获取标签中的内容。
总结:
通过beautifulsoup我们能够解析大部分静态html网页,遍历和搜索组合方式定位html的标签,并获取相应标签的内容。