Beautifulsoup4
# Beautifulsoup4
Beautiful Soup (opens new window) 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup 会帮你节省数小时甚至数天的工作时间.
Beautifulsoup 四种解析器
| 解析器 | 使用方法 | 优势 | 劣势 |
|---|---|---|---|
| Python 标准库 | BeautifulSoup(markup, "html.parser") | Python 的内置标准库执行速度适中文档容错能力强 | Python 2.7.3 or 3.2.2) 前 的版本中文档容错能力差 |
| lxml HTML 解析器 | BeautifulSoup(markup, "lxml") | 速度快文档容错能力强 | 需要安装 C 语言库 |
| lxml XML 解析器 | BeautifulSoup(markup, ["lxml-xml"])``BeautifulSoup(markup, "xml") | 速度快唯一支持 XML 的解析器 | 需要安装 C 语言库 |
| html5lib | BeautifulSoup(markup, "html5lib") | 最好的容错性以浏览器的方式解析文档生成 HTML5 格式的文档 | 速度慢不依赖外部扩展 |
# 构造方法
- BeautifulSoup(html,"html.parser")
url="http://wsjkw.sc.gov.cn/scwsjkw/gzbd/fyzt.shtml"
res=requests.get(url)
res.encoding="utf-8" #转为utf-u解码
html=res.text #将源码转为文本赋值给html
soup=BeautifulSoup(html,'html.parser') #对象化html "lxml"
2
3
4
5
# 四大对象种类
- Tag HTML 中的一个个标签
- Name(标签名) 通过 .name 获取
- Attributes(属性) 字典获取 tag ["class"] tag.attrs 可以获取整个字典
- Multi-valued attributes(多值属性) 也是字典获取 返回一个列表
- NavigableString 获取标签内部的文字用 .string 即可
- BeautifulSoup 表示的是一个文档的内容
- Comment 是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。
# 遍历文档树
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')
2
soup.tag 使用标签名进行遍历 soup.head soup.h2
Tag.contents 获取该标签中所有元素
head_tag = soup.head head_tag # <head><title>The Dormouse's story</title></head> head_tag.contents [<title>The Dormouse's story</title>] title_tag = head_tag.contents[0] title_tag # <title>The Dormouse's story</title>1
2
3
4
5
6
7
8
9
10
Tag.children 对 tag 的子节点进行循环
for child in title_tag.children: print(child)1
2
3
Tag.descendants 可以对所有 tag 的子孙节点进行递归循环
for child in head_tag.descendants: print(child)1
2
soup.strings 获取 tag 中的字符串包含子标签
for string in soup.strings: print(repr(string)) # u"The Dormouse's story" # u'\n\n' # u"The Dormouse's story" # u'\n\n' # u'Once upon a time there were three little sisters; and their names were\n' # u'Elsie' # u',\n' # u'Lacie' # u' and\n' # u'Tillie' # u';\nand they lived at the bottom of a well.' # u'\n\n' # u'...' # u'\n'1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
soup.stripped_strings 输出的字符串中可能包含了很多空格或空行,使用
.stripped_strings可以去除多余空白内容:for string in soup.stripped_strings: print(repr(string)) # u"The Dormouse's story" # u"The Dormouse's story" # u'Once upon a time there were three little sisters; and their names were' # u'Elsie' # u',' # u'Lacie' # u'and' # u'Tillie' # u';\nand they lived at the bottom of a well.' # u'...'1
2
3
4
5
6
7
8
9
10
11
12
Tag.parent 获取某个元素的父节点
title_tag = soup.title title_tag # <title>The Dormouse's story</title> title_tag.parent # <head><title>The Dormouse's story</title></head>1
2
3
4
5
Tag.parents 可以递归得到元素的所有父辈节点
link = soup.a link # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a> for parent in link.parents: if parent is None: print(parent) else: print(parent.name) # p # body # html # [document] # None1
2
3
4
5
6
7
8
9
10
11
12
13
# 搜索文档树
- soud.find () 搜索第一个符合条件的标签
- soud.find_all (name , attrs , recursive , string , **kwargs) 搜索所有符合条件的标签
唯一的区别是 find_all () 方法的返回结果是值包含一个元素的列表,而 find () 方法直接返回结果.
# 字符串
最简单的过滤器是字符串。在搜索方法中传入一个字符串参数,Beautiful Soup 会查找与字符串完整匹配的内容
soup.find_all('b')
# [<b>The Dormouse's story</b>]
2
# 正则表达式
如果传入正则表达式作为参数,Beautiful Soup 会通过正则表达式的 match() 来匹配内容.
import re
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
# body
# b
2
3
4
5
# 列表
如果传入列表参数,Beautiful Soup 会将与列表中任一元素匹配的内容返回
soup.find_all(["a", "b"])
# [<b>The Dormouse's story</b>,
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
2
3
4
5
# keyword 属性值
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字 tag 的属性来搜索
soup.find_all(id='link2') #搜索所有id为link2的标签
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
2
# 按 CSS 搜索
class 在 Python 中是保留字,使用 class 做参数会导致语法错误。从 Beautiful Soup 的 4.1.1 版本开始,可以通过 class_ 参数搜索有指定 CSS 类名的 tag
soup.find_all("a", class_="sister")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
2
3
4
class 属性是 多值属性。按照 CSS 类名搜索 tag 时,可以分别搜索 tag 中的每个 CSS 类名
css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.find_all-0-0-("p", class_="strikeout")
# [<p class="body strikeout"></p>]
css_soup.find_all("p", class_="body")
# [<p class="body strikeout"></p>]
2
3
4
5
6
搜索 class 属性时也可以通过 CSS 值完全匹配
css_soup.find_all("p", class_="body strikeout")
# [<p class="body strikeout"></p>]
2
完全匹配 class 的值时,如果 CSS 类名的顺序与实际不符,将搜索不到结果
soup.find_all("a", attrs={"class": "sister"})
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
2
3
4
# String 参数
通过 string 参数可以搜搜文档中的字符串内容
soup.find_all(string="Elsie")
# [u'Elsie']
soup.find_all(string=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']
soup.find_all(string=re.compile("Dormouse"))
[u"The Dormouse's story", u"The Dormouse's story"]
def is_the_only_string_within_a_tag(s):
""Return True if this string is the only child of its parent tag.""
return (s == s.parent.string)
soup.find_all(string=is_the_only_string_within_a_tag)
# [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# limit 参数
find_all () 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢。如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量。效果与 SQL 中的 limit 关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果.
soup.find_all("a", limit=2)
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
2
3
# recursive 参数
调用 tag 的 find_all () 方法时,Beautiful Soup 会检索当前 tag 的所有子孙节点,如果只想搜索 tag 的直接子节点,可以使用参数 recursive=False
# 父辈节点
find_all () 和 find () 只搜索当前节点的所有子节点,孙子节点等. find_parents () 和 find_parent () 用来搜索当前节点的父辈节点,搜索方法与普通 tag 的搜索方法相同,搜索文档搜索文档包含的内容
- soud.find_parents()
- soud.find_parents()
# 修改文档树
Beautiful Soup 的强项是文档树的搜索,但同时也可以方便的修改文档树
# 修改 tag 的名称和属性
重命名一个 tag, 改变属性的值,添加或删除属性
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
tag.name = "blockquote"
tag['class'] = 'verybold'
tag['id'] = 1
tag
# <blockquote class="verybold" id="1">Extremely bold</blockquote>
del tag['class']
del tag['id']
tag
# <blockquote>Extremely bold</blockquote>
2
3
4
5
6
7
8
9
10
11
12
13
# 修改 .string
给 tag 的 .string 属性赋值,就相当于用当前的内容替代了原来的内容
如果当前的 tag 包含了其它 tag, 那么给它的 .string 属性赋值会覆盖掉原有的所有内容包括子 tag
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup)
tag = soup.a
tag.string = "New link text."
tag
# <a href="http://example.com/">New link text.</a>
2
3
4
5
6
7
# append()
Tag.append () 方法想 tag 中添加内容
soup = BeautifulSoup("<a>Foo</a>")
soup.a.append("Bar")
soup
# <html><head></head><body><a>FooBar</a></body></html>
soup.a.contents
# [u'Foo', u'Bar']
2
3
4
5
6
7
# clear()
Tag.clear () 方法移除当前 tag 的内容
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup)
tag = soup.a
tag.clear()
tag
# <a href="http://example.com/"></a>
2
3
4
5
6
7
# extract()
PageElement.extract () 方法将当前 tag 移除文档树,并作为方法结果返回
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup)
a_tag = soup.a
i_tag = soup.i.extract()
a_tag
# <a href="http://example.com/">I linked to</a>
i_tag
# <i>example.com</i>
print(i_tag.parent)
None
2
3
4
5
6
7
8
9
10
11
12
13
14
# decompose()
Tag.decompose () 方法将当前节点移除文档树并完全销毁
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup)
a_tag = soup.a
soup.i.decompose()
a_tag
# <a href="http://example.com/">I linked to</a>
2
3
4
5
6
7
8
# replace_with()
PageElement.replace_with () 方法移除文档树中的某段内容,并用新 tag 或文本节点替代它:
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup)
a_tag = soup.a
new_tag = soup.new_tag("b")
new_tag.string = "example.net"
a_tag.i.replace_with(new_tag)
a_tag
# <a href="http://example.com/">I linked to <b>example.net</b></a>
2
3
4
5
6
7
8
9
10
# bs4 的简单使用
from bs4 import BeautifulSoup
import requests
url="http://wsjkw.sc.gov.cn/scwsjkw/gzbd/fyzt.shtml"
res=requests.get(url)
res.encoding="utf-8" #转为utf-u解码
html=res.text #将源码转为文本赋值给html
soup=BeautifulSoup(html,'html.parser') #对象化html "lxml"
h =soup.find('h2') #寻找文本中 h2标签的内容
print(h)
h = soup.find('h2').text #只获取h2标签中的内容
print(h)
a = soup.find('a') #会寻找文本中第一个a标签
print(a)
print(type(a))
a = soup.find('a').attrs #获取a标签中 href以及 target 存放在字典中
print(a)
print(a['href'])
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19