Beautiful Soup 是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据。
一、安装
sudo pip3 install beautifulsoup4
二、使用
-
导入模块
from bs4 import BeautifulSoup
-
创建BeautifulSoup对象
In [1]: from bs4 import BeautifulSoup In [2]: text = \'\'\' ...: <div> ...: <ul> ...: <li class="item-0" id="first"><a href="link1.html">first item</a></li> ...: <li class="item-1"><a href="link2.html">second item</a></li> ...: <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> ...: <li class="item-1"><a href="link4.html">fourth item</a></li> ...: <li class="item-0"><a href="link5.html">fifth item</a></li> ...: </ul> ...: </div> ...: \'\'\' In [3]: bs = BeautifulSoup(text)#创建BeautifulSoup对象,可以直接传入字符串
In [4]: bs1 = BeautifulSoup(open(\'./test.html\'))#也可以传入文件对象
In [5]: bs Out[5]: <html><body><div> <ul> <li class="item-0" id="first"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> </body></html>创建Beautiful Soup对象时,既可以传入字符串,也可以传入文件对象。它将复杂HTML文档转换成一个复杂的树形结构,并且会自动修正文档,像上述例子中补齐了html和body节点,每个节点都是Python对象
-
获取Tag对象
In [6]: bs.ul #获取ul标签内容 Out[6]: <ul> <li class="item-0" id="first"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> In [7]: type(bs.ul) Out[7]: bs4.element.Tag In [8]: bs.li #获取li标签内容,注意返回的是第一个符合要求的标签 Out[8]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [12]: bs.ul.li.a #可叠加查找标签 Out[12]: <a href="link1.html">first item</a>
通过Beautiful Soup对象后面接上‘.标签名’来获取需要查找的标签,可叠加
-
Tag对象常用属性
-
name-----显示标签名
In [13]: bs.name #大部分时候,可以把BeautifulSoup当作Tag对象,是一个特殊的 Tag Out[13]: \'[document]\' In [14]: bs.li.name Out[14]: \'li
BeautifulSoup 对象表示的是一个文档的内容。大部分时候,可以把它当作 Tag 对象
-
attrs----以字典的方式显示该标签所有属性
In [15]: bs.attrs Out[15]: {} In [16]: bs.li.attrs #以字典的形式显示所有属性 Out[16]: {\'class\': [\'item-0\'], \'id\': \'first\'} In [17]: bs.li.attrs[\'id\'] #获取具体的某个属性方法1 Out[17]: \'first\' In [18]: bs.li[\'id\'] #获取具体属性方法2,\'.attrs\'可省略 Out[18]: \'first\' In [19]: bs.li.get(\'id\')#获取具体 属性方法3,利用get方法 Out[19]: \'first\'
-
text----获取标签里面的内容
In [20]: bs.li.text #获取第一个li标签里面的内容,由于li标签里面只有唯一的a标签了,会返回最里面a标签的内容 Out[20]: \'first item\' In [21]: bs.li.a.text #返回a标签的内容 Out[21]: \'first item\'
注意:如果标签内容是一个注释,则注释符号会被去掉,比如“<!-- 这是一个注释 -->”,则返回"这是一个注释"
-
contents----将直接子节点以列表的形式输出,同时也包含换行符\'\n\'
In [22]: bs.ul.contents Out[22]: [\'\n\', <li class="item-0" id="first"><a href="link1.html">first item</a></li>, \'\n\', <li class="item-1"><a href="link2.html">second item</a></li>, \'\n\', <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>, \'\n\', <li class="item-1"><a href="link4.html">fourth item</a></li>, \'\n\', <li class="item-0"><a href="link5.html">fifth item</a></li>, \'\n\']
-
chilldren----将直接子节点以列表生成器的形式输出,也包括换行符‘\n
In [28]: bs.ul.children #返回的是列表生成器对象 Out[28]: <list_iterator at 0x7f2d9e90ea30> In [29]: for child in bs.ul.children: ...: print(child) ...: <li class="item-0" id="first"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li>
-
descendants----返回的是一个生成器对象,进行迭代取值的时候,会递归循环的显示所有子孙节点
In [30]: bs.ul.descendants #返回的是一个生成器对象,进行迭代取值的时候,会递归循环的显示所有子孙节点 Out[30]: <generator object Tag.descendants at 0x7f2d9e79fc80> In [31]: for d in bs.ul.descendants: ...: print(d) ...: <li class="item-0" id="first"><a href="link1.html">first item</a></li> <a href="link1.html">first item</a> first item <li class="item-1"><a href="link2.html">second item</a></li> <a href="link2.html">second item</a> second item <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <a href="link3.html"><span class="bold">third item</span></a> <span class="bold">third item</span> third item <li class="item-1"><a href="link4.html">fourth item</a></li> <a href="link4.html">fourth item</a> fourth item <li class="item-0"><a href="link5.html">fifth item</a></li> <a href="link5.html">fifth item</a> fifth item
-
-
Tag对象常用方法
-
find(self, name=None, attrs={}, recursive=True, text=None,**kwargs)----------只返回第一个匹配的对象
-
name参数----过滤标签名,可以传入字符串、正则以及列表3种形式
In [32]: bs.find(\'li\') #查找第一个匹配的li标签 Out[32]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [33]: bs.find([\'li\',\'a\']) #查找第一个匹配的li标签或者a标签 Out[33]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [34]: import re In [35]: bs.find(re.compile(r\'^l\')) #查找第一个以l开头的标签,li标签匹配上 Out[35]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [36]: bs.find(re.compile(r\'l$\')) #查找第一个以l结尾的标签,html标签符合 Out[36]: <html><body><div> <ul> <li class="item-0" id="first"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> </body></html>
-
attrs参数----过滤属性,dict类型
In [37]: bs.find(attrs={\'class\':\'item-1\'}) #查找class属性为item-1的第一个标签 Out[37]: <li class="item-1"><a href="link2.html">second item</a></li> -
recursive参数----如果为True,表示是否递归地从子孙节点中去查找匹配对象。否则只从直接子节点中进行查找
In [38]: bs.find(\'li\',recursive=True) #递归查找,能够匹配到li对象 Out[38]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [39]: bs.find(\'li\',recursive=False) #从直接子节点(即html)中无法找到li标签 In [40]: bs.ul.find(\'li\',recursive=False) #ul的直接子节点为li标签,所以能够匹配到 Out[40]: <li class="item-0" id="first"><a href="link1.html">first item</a></li>
-
text参数----可以搜索文档中匹配的内容,和name参数一样,有字符串、正则、列表这3种形式
In [41]: bs.find(text=\'first item\') #查找字符串,需要传入完整内容,否则无法匹配 Out[41]: \'first item\' In [42]: bs.find(text=re.compile(r\'item\'))#查找第一个包含item的内容 Out[42]: \'first item\' In [43]: bs.find(text=re.compile(r\'ir\'))#查找第一个包含ir的内容 Out[43]: \'first item\' In [44]: bs.find(text=[\'second item\',\'third item\']) #查找内容为second item或third item的第一个内容 Out[44]: \'second item\'
-
其它关键字参数----关键字为属性名,但是注意不能直接传入和python关键字重名的class属性,需要在class后面加上下划线,即修改为"class_"
In [45]: bs.find(id=\'first\') #id属性作为关键字参数进行查找 Out[45]: <li class="item-0" id="first"><a href="link1.html">first item</a></li> In [43]: bs.find(href=\'link4.html\') #href属性作为关键字参数进行查找 Out[43]: <a href="link4.html">fourth item</a> In [44]: bs.find(class=\'item-inactive\') #和python关键字class重名的class属性则会报错 File "<ipython-input-42-a9ab4a3f6cee>", line 1 bs.find(class=\'item-inactive\') ^ SyntaxError: invalid syntax
-
-
find_all(self, name=None, attrs={}, recursive=True, text=None,**kwargs)----以列表的形式返回所有能够匹配到的对象,所有参数用法同find()方法
In [45]: bs.find_all(\'li\') #查找所有的li标签 Out[45]: [<li class="item-0" id="first"><a href="link1.html">first item</a></li>, <li class="item-1"><a href="link2.html">second item</a></li>, <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>, <li class="item-1"><a href="link4.html">fourth item</a></li>, <li class="item-0"><a href="link5.html">fifth item</a></li>] In [46]: bs.find_all(\'li\',attrs={"class":"item-1"}) #查找所有的li标签,并且class属性为item-1 Out[46]: [<li class="item-1"><a href="link2.html">second item</a></li>, <li class="item-1"><a href="link4.html">fourth item</a></li>]
-
get()方法----获取对象的特定属性
In [47]: bs.li.get(\'class\') #class属性因为可以有多个,所以返回的是列表形式 Out[47]: [\'item-0\'] In [48]: bs.find(attrs={"class":"item-0"}).get(\'id\') #以字符串的形式返回id属性值 Out[48]: \'first\' In [49]: bs.find_all(\'a\')[1].get(\'href\') Out[49]: \'link2.html\'
-
get_text()方法----获取标签里面的内容,同text属性返回的结果一样
In [50]: bs.li.get_text() #获取第一个li最里面的内容 Out[50]: \'first item\' In [51]: bs.find(attrs={"class":"bold"}).get_text() #获取class属性为bold标签(即span标签)里面的内容 Out[51]: \'third item\' In [52]: bs.find_all(\'a\')[3].get_text() #获取第4个a标签里面的内容 Out[52]: \'fourth item\' -
select()方法----css选择器,同find_all方法有点类似,返回的是列表
-
通过标签名查找
In [53]: bs.select(\'li\') #查找所有li标签 Out[53]: [<li class="item-0" id="first"><a href="link1.html">first item</a></li>, <li class="item-1"><a href="link2.html">second item</a></li>, <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>, <li class="item-1"><a href="link4.html">fourth item</a></li>, <li class="item-0"><a href="link5.html">fifth item</a></li>]
-
通过类名查找,类名前加上\'.\'
In [54]: bs.select(\'.bold\') #查找class=\'bold\'的标签 Out[54]: [<span class="bold">third item</span>]
-
通过id查找,id前加上\'#\'
In [55]: bs.select(\'#first\') #查找id为first的标签 Out[55]: [<li class="item-0" id="first"><a href="link1.html">first item</a></li>]
-
混合查找
In [56]: bs.select(\'.item-0 a\') #查找class="item-0"下的a标签 Out[56]: [<a href="link1.html">first item</a>, <a href="link5.html">fifth item</a>] In [57]: bs.select(\'#first a\') #查找id="first"下面的a标签 Out[57]: [<a href="link1.html">first item</a>] In [58]: bs.select(\'ul span\') #查找ul下面的span标签 Out[58]: [<span class="bold">third item</span>] In [59]: bs.select(\'ul>span\') #标签后面带上">"表示直接子标签,因为span标签不是ul的直接子标签,所以匹配不到 Out[59]: [] In [60]: bs.select(\'a>span\') #span标签是a标签的子标签,所以能匹配到 Out[60]: [<span class="bold">third item</span>]
直接子标签查找,则使用
>分隔 -
通过属性查找
In [61]: bs.select(\'li[class="item-inactive"]\') #查找class属性为\'item-inactive\'的li标签 Out[61]: [<li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>] In [62]: bs.select(\'a[href="link2.html"]\') #查找href属性为\'link2.html\'的a标签 Out[62]: [<a href="link2.html">second item</a>]
-
-