BeautifulSoup是一个用来从HTML和XML文件中提取数据的Python库,最近需要爬取一些数据,简单记录一下BeautifulSoup的基本用法。BeautifulSoup的详细用法可以参考文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
目前BeautifulSoup的版本为第四版,可以直接使用pip进行安装:
pip install beautifulsoup4
之后可以通过pip list
检查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将HTML文档转换为一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为四种:Tag,NavigableString,BeautifulSoup和Comment。
当我们使用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']
字符串常被包含在标签(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对象表示的是一个文档的全部内容,大部分时候可以把它看作Tag对象,支持遍历文档树中的大部分方法,它的name属性有一个特殊值
document
。
Comment对象是一个特殊的NavigableString对象,表示注释内容。
markup = "<b><!-- a comment --></b>" soup = BeautifulSoup(markup) comment = soup.b.string type(comment) # <class 'bs4.element.Comment'> comment # a comment
通过一个例子说明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定义了多种搜索方法,这里着重介绍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://"]')
使用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>
如果只想得到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']
如有错误,欢迎留言指出,我会及时修改,感谢阅读,希望您能有所收获。
a
--
123456789
更改id为3
--
test
更改id为2
--
commentor
伪造名称???
--
hhh
伪造名称???
--
yayay