爬虫-使用BeautifulSoup4(bs4)解析html数据

Beautiful Soup 是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据。

一、安装

pip install beautifulsoup4

二、使用

  1. 导入模块

    from bs4 import BeautifulSoup
  2. 创建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对象

  3. 获取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对象后面接上‘.标签名’来获取需要查找的标签,可叠加

  4. Tag对象常用属性

    1. name-----显示标签名

      In [13]: bs.name #大部分时候,可以把BeautifulSoup当作Tag对象,是一个特殊的 Tag
      Out[13]: [document]
      
      In [14]: bs.li.name
      Out[14]: li

      BeautifulSoup 对象表示的是一个文档的内容。大部分时候,可以把它当作 Tag 对象

    2. 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

       

    3. string----获取标签里面的内容

      In [20]: bs.li.string #li标签里面只有唯一的a标签了,那么 .string 会返回最里面a标签的内容
      Out[20]: first item
      
      In [21]: bs.li.a.string #返回a标签的内容
      Out[21]: first item

      注意:如果标签内容是一个注释,则注释符号会被去掉,比如“<!-- 这是一个注释 -->”,则返回"这是一个注释"

    4. 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]
    5. 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>

       

    6. 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
  5. Tag对象常用方法

    1. find(self, name=None, attrs={}, recursive=True, text=None,**kwargs)----------只返回第一个匹配的对象

      1. 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(rl$)) #查找第一个以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>
      2. 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>
      3. 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>
      4. text参数----可以搜索文档中匹配的内容,和name参数一样,有字符串、正则、列表这3种形式

        In [41]: bs.find(text=first item) #查找字符串,需要传入完整内容,否则无法匹配
        Out[41]: first item
        
        In [42]: bs.find(text=re.compile(ritem))#查找第一个包含item的内容
        Out[42]: first item
        
        In [43]: bs.find(text=re.compile(rir))#查找第一个包含ir的内容
        Out[43]: first item
        
        In [44]: bs.find(text=[second item,third item]) #查找内容为second item或third item的第一个内容
        Out[44]: second item
      5. 其它关键字参数----关键字为属性名,但是注意不能传入和python关键字重名的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
    2. 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>]
    3. 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
    4. get_text()方法----获取标签里面的内容,同string属性返回的结果一样

      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‘ 
    5. select()方法----css选择器,同find_all方法有点类似,返回的是列表

      1. 通过标签名查找

        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>]
      2. 通过类名查找,类名前加上‘.‘

        In [54]: bs.select(.bold) #查找class=‘bold‘的标签
        Out[54]: [<span class="bold">third item</span>]
      3. 通过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>]
      4. 混合查找

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

        直接子标签查找,则使用 > 分隔

      5. 通过属性查找

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

         

爬虫-使用BeautifulSoup4(bs4)解析html数据

上一篇:ZHI.ZSystem开发组件介绍之发送HTTP请求


下一篇:Git ignore文件的用法