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']  

字符串常被包含在标签(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']  

如有错误,欢迎留言指出,我会及时修改,感谢阅读,希望您能有所收获。

评论

还没有登陆?评论请先登陆注册

还没有评论,抢个沙发吧!

 联系方式 contact me

Github
Email
QQ
Weibo