BeautifulSoup是一个可以从HTML或者XML文件中提取数据的Python库,它通过解析器把文档解析为利于人们理解的文档导航模式,有利于查找和修改文档。
BeautifulSoup3目前已经停止开发,现在推荐使用BeautifulSoup4,它被移植到了bs4中。
# 使用时需要导入from bs4 import BeautifulSoup
解析器
BeautifulSoup4中常用4种主要的解析器,使用前需要安装:
#不同系统安装方法$ apt-get install Python-lxml$ easy_install lxml$ pip install lxml# pycharm中安装可以先import xxx,显示有错误然后点击安装,安装后删除import语句,即可正常使用
解析器 | 使用方法 | 优势 | 劣势 |
Python标准库 | BeautifulSoup(DocumentName, "html.parser")
|
| Python 2.7.3 or 3.2.2前的班中文容错能力差 |
lxml HTML解析器 | BeautifulSoup(DocumentName, "lxml") |
| 需要安装C语言库 |
lxml XML解析器 | BeautifulSoup(DocumentName, "xml") BeautifulSoup(DocumentName, ["lxml","xml"]) |
| 需要安装C语言库 |
html5lib | BeautifulSoup(DocumentName, "html5lib") |
| 速度慢,需要依赖python库 |
不同解析器的解析结果:
# 符合HTML标准的解析结果 htmldoc = ""print("None :",BeautifulSoup(htmldoc))print("html.parser :", BeautifulSoup(htmldoc, "html.parser"))print("lxml :", BeautifulSoup(htmldoc, "lxml"))print("xml :", BeautifulSoup(htmldoc, "lxml-xml"))print("html5lib :", BeautifulSoup(htmldoc, "html5lib"))"""结果为:None : html.parser : lxml : xml : html5lib : """
# 不符合HTML标准的解析结果htmldoc = ""print("None :",BeautifulSoup(htmldoc))print("html.parser :", BeautifulSoup(htmldoc, "html.parser"))print("lxml :", BeautifulSoup(htmldoc, "lxml"))print("xml :", BeautifulSoup(htmldoc, "lxml-xml"))print("html5lib :", BeautifulSoup(htmldoc, "html5lib"))"""结果为:None : html.parser : lxml : xml : html5lib : """
html5lib会把所有的标签不全,并且加上html、head、body,标准的html格式;默认、html.parser、lxml 解析器会把错误标签忽略掉。
编码
任何HTML或者XML文档都有自己的编码方式,但使用BeautifulSoup解析后,文档都会被转换为Unicode,输出时编码均为UTF-8。
因为BeautifulSoup用来编码自动检测库来识别当前文档的编码,并自动转换为Unicode编码。但也有小概率会识别出错,可以用.original_encoding来检测编码格式。
并且设置from_encoding参数可以提高文档的解析速度。
htmldoc = b"\xed\xe5\xec\xf9
"soup = BeautifulSoup(htmldoc, from_encoding="iso-8859-8")print(soup.h1)print(soup.original_encoding)"""结果:םולש
'iso8859-8'"""
指定输出编码:
htmldoc = b"\xed\xe5\xec\xf9
"soup = BeautifulSoup(htmldoc, from_encoding="iso-8859-8") print(soup.prettify("latin-1"))
""" 结果: b'\n νεμω\n
'"""
遍历文档树:
1. 注释<class 'bs4.element.Comment'> 和 替换Comment内容
htmldoc = " "soup = BeautifulSoup(htmldoc)comment = soup.b.stringprint(comment)print(type(comment))print(soup2.b)print(soup2.b.prettify()) #comment特色输出方式# 替换Commentcdata= CData("A CData block")comment.replace_with(cdata)print(soup2.b.prettify())"""结果:Hey, buddy. Want to buy a used parser?"""
CData使用时需要导入 from bs4 import CData
2. soup.tagName 返回类型 <class 'bs4.element.Tag'>,得到文档中第一个tagName标签 == soup.find(tagName)
soup.div #得到文章中第一个div标签soup.a #得到文章中第一个a标签
3. soup.tagName.get_text() / soup.tagName.text 返回类型 <class 'str'>,得到该标签内容,对每个BeautifulSoup处理后的对象都生效。
soup.a.get_text()soup.a.text
4. soup.tagName.tagName["AttributeName"] 获得标签内属性值,逐级访问标签可以用 . 连接,某个属性值用 ["属性名"] 访问。
soup.div.a['href']
5. soup.ul.contents 返回类型为<class 'list'>,可以用下标访问其中的元素
list内元素类型为 <class 'bs4.element.Tag'> or <class 'bs4.element.NavigableString'>
如果是单一标签可以用 string 返回文本,如果超过1个标签就返回None
soup.ul.contentstype(soup.ul.contents) #soup.ul.contents[0].stringtype(soup.ul.contents[0])
6. find_all(name, attrs, recursice, text, limit, **kwargs),返回的类型为 <class 'bs4.element.ResultSet'>
# 找到所有标签为tagName的集合soup.find_all("tagName")soup.find_all("a")# 找到所有标签为tagName 且 class=className的集合soup.find_all("tagName", "className")soup.find_all("div","Score")# 找到所有id=idName的标签soup.find_all(id = "idName")# 使用多个指定名字的参数可以同时过滤tag的多个属性:soup.find_all(href = re.compile("else"))soup.find_all(href=re.compile("elsie"), id='link1')# [Elsie]# 有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性data_soup = BeautifulSoup('foo!')data_soup.find_all(data-foo="value")# SyntaxError: keyword can't be an expression# 可以用attrs 参数定义一个字典参数来搜索包含特殊属性的tagdata_soup.find_all(attrs={ "data-foo": "value"})# [foo!]# 找到所有有id的标签soup.find_all(id = True)# 找到所有标签为tagName且class = "className"的标签soup.find_all("tagName", class_ = "className")# css class参数过滤soup.find_all(class_=re.compile("itl"))# [The Dormouse's story
]# 通过文本查找文本soup.find_all(text = "textContent")soup.find_all(text = ["Content1", "Content2"])# 文本参数过滤soup.find_all(text=re.compile("Dormouse"))# 限制结果个数soup.find_all("tagName", limit = 2)elemSet = soup.find_all("div", limit = 2)# 可循环出每个元素for item in elemSet: print(item) print(item.text)
7. 通过 css 选择器查找,返回值 <class 'list'>,list中元素类型为 <class 'bs4.element.Tag'>
htmldoc = """The Dormouse's story The Dormouse's story
Once upon a time there were three little sisters; and their names wereElsie,Lacie andTillie;and they lived at the bottom of a well.
...
"""soup = BeautifulSoup(htmldoc, "lxml")# tag标签查找soup.select("title")# tag标签逐层查找soup.select("html head title")soup.select("head title")soup.select("body a")# tag标签下的直接子标签soup.select("head > title")soup.select("p > a")soup.select("p > a:nth-of-type(2)")soup.select("p > #link1")# css类名查找soup.select(".sister")# id 查找soup.select("#link1")# 通过属性查找soup.select("a[href]")soup.select('a[href="http://example.com/elsie"]')soup.select('a[href^="http://example.com/"]')soup.select('a[href$="tillie"]')soup.select('a[href*=".com/el"]')type(soup.select("a[href]")) ## 通过循环获取到每个taglist = soup.select("a[href]") for item in list: print(item) print(type(item)) # print(item.text) print(item.string)