BeautifulSoup是一个用来从HTML和XML文件中提取数据的Python库,最近需要爬取一些数据,简单记录一下BeautifulSoup的基本用法。BeautifulSoup的详细用法可以参考文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
BeautifulSoup的安装
目前BeautifulSoup的版本为第四版,可以直接使用pip进行安装:
pip install beautifulsoup4
之后可以通过pip list
检查BeautifulSoup是否安装成功。
BeautifulSoup基本使用方法
将一段文档传入BeautifulSoup的构造方法,可以得到一个文档对象,可以传入一段字符串(比如爬取得到的网页源码)或一个文件句柄。
# 使用BeautifulSoup之前需要先引入
from bs4 import BeautifulSoup
# 传入文件句柄的用法,构造方法返回的便是文档对象
soup = BeautifulSoup(open("index.html"))
html = "<html><body>data</body></html>"
# 传入文档字符串的用法
soup1 = BeautifulSoup(html)
BeatuifulSoup会选择最合适的解析器来解析这段文档,当然也可以手动指定解析器,不同解析器的区别可以参考引言处的官方文档,比如指定lxml为解析器,则可以使用:
BeautifulSoup(html,"lxml")
。
BeautifulSoup对象的种类
BeautifulSoup将HTML文档转换为一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为四种:Tag,NavigableString,BeautifulSoup和Comment。
Tag
当我们使用BeautifulSoup构造方法获取到文档对象之后,Tag对象可以看作HTML中的标签对象,可以使用.操作符获取,获取到Tag对象后可以获取对应HTML标签的属性,使用类似字典的操作方法获取。
soup = BeautifulSoup('<b class="bold">tag</b>')
# 通过.操作符可以获取对应的标签对象
type(soup.b) # <class 'bs4.element.Tag'>
tag = soup.b
# Tag可以通过.name获取自己的名字
tag.name # 'b'
# Tag的属性操作方法与字典相同
tag['class'] # 'bold'
# 也可以使用.attrs获取Tag的所有属性
tag.atttrs # {'class':'bold'}
# 若Tag存在多值属性则会返回list
css_soup = BeautifulSoup('<p class="a b"></p>')
css_soup.p['class'] # ['a','b']
NavigableString
字符串常被包含在标签(Tag)内,NavigableString类用来包装Tag中的字符串。获取到Tag对象后,使用.string即可获取到标签内的字符串。
soup = BeautifulSoup('<b class="bold">string</b>')
tag = soup.b
tag.string # string
type(tag.string) # <class 'bs4.element.NavigableString'>
BeautifulSoup
BeautifulSoup对象表示的是一个文档的全部内容,大部分时候可以把它看作Tag对象,支持遍历文档树中的大部分方法,它的name属性有一个特殊值
document
。
Comment
Comment对象是一个特殊的NavigableString对象,表示注释内容。
markup = "<b><!-- a comment --></b>"
soup = BeautifulSoup(markup)
comment = soup.b.string
type(comment) # <class 'bs4.element.Comment'>
comment # a comment
BeautifulSoup遍历文档树
通过一个例子说明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...
</p>
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
</p>
<p class="story">...</p>
</body></html>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc)
# 使用tag的name获取标签内容
soup.title # <title>The Dormouse's story</title>
# 通过.属性的方式只能获取当前名字的第一个tag
soup.a # <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>
# 如果tag内还有tag可以继续使用.属性获取内部tag
soup.body.b # <b>The Dormouse's story</b>
# 如果想得到所有a标签,需要使用搜索文档树中的fing_all()方法
soup.find_all('a') # 得到所有a标签的列表
# 如果tag只有一个NavigableString类型子节点,那么这个tag可以使用.string得到子节点
soup.title.string # The Dormouse's story
# 通过.parent属性可以获取某个元素的父节点
soup.title.parent # <head><title>The Dormouse's story</title></head>
BeautifulSoup搜索文档树
BeautifulSoup定义了多种搜索方法,这里着重介绍find()和find_all()。
# html_doc与遍历文档树使用的一致
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc)
# find_all()方法可以找到想要查找的文档内容,有多种过滤方式
# 1.使用标签名过滤
# 查找所有<b>标签,返回结果是一个list
soup.find_all('b') # [<b>The Dormouse's story</b>]
# 2.使用正则表达式过滤
import re
# 查找所有以b开头的标签
for tag in soup.find_all(re.compile("^b")):
print(tag.name) # body b
# 3.使用列表过滤
# 查找文档中所有的<a>和<b>标签
soup.find_all(['a','b'])
# 4.使用标签属性过滤
# 查找id为link2的标签
soup.find_all(id="link2")
# 查找所有包含id属性的标签
soup.find_all(id=True)
# 指定CSS类名时需要使用class_参数
# 查找所有类名为sister的<a>标签
soup.find_all("a",class_="sister")
find()方法与find_all()使用方法相似,唯一区别是find_all()方法返回的结果是一个列表,而find()方法只返回搜索到的第一个结果。find_all()方法找不到目标时返回空列表,find()方法找不到目标时返回None。
BeautifulSoup还支持使用大部分的CSS选择器语法进行搜索,在Tag或BeautifulSoup对象的select()方法中可以使用CSS选择器语法找到tag,我举几个常用的例子。
# 1.使用tag标签查找,返回结果也是标签列表
soup.select("a")
# 2.使用tag标签逐层查找
soup.select("html head title")
# 3.找到tag下的直接子标签
soup.select("p > a")
# 4.通过CSS类名查找
soup.select(".sister")
# 5.通过id查找
soup.select("#link1")
# 6.通过是否存在某个属性查找
# 查找所有包含href属性的a标签
soup.select('a[href]')
# 7.通过属性的值来查找
# 精准查找
soup.select('a[href="http://example.com/elsie"]')
# 正则查找
soup.select('a[href^="http://"]')
BeautifulSoup格式化输出
使用prettify()方法可以将BeautifulSoup文档树格式化后以Unicode编码输出,每个XML/HTML标签都独占一行。
markup='<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup)
print(soup.a.prettify())
# <a href="http://example.com/">
# I linked to
# <i>
# example.com
# </i>
# </a>
get_text()方法
如果只想得到Tag中包含的文本内容,那么可以使用get_text()方法,这个方法获取到Tag中的所有文版内容包括子孙Tag中的内容,并将结果作为Unicode字符串返回。
markup='<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup)
soup.get_text() # I linked toexample.com
# 也可以使用.stripped_strings生成器获得文本列表后手动处理列表
[text for text in soup.stripped_strings]
# ['Ilinked to','example.com']
如有错误,欢迎留言指出,我会及时修改,感谢阅读,希望您能有所收获。