zoukankan      html  css  js  c++  java
  • 爬虫入门【3】BeautifulSoup4用法简介

    快速开始使用BeautifulSoup

    首先创建一个我们需要解析的html文档,这里采用官方文档里面的内容:

    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 three little sisters; and their names were
    <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>;
    and they lived at the bottom of a well.</p>
    
    <p class="story">...</p>
    """
    

    要解析这段代码,需要导入BeautifullSoup,可以选择按照标准的缩进格式来输出内容:

    from bs4 import BeautifulSoup#导入BeautifulSoup的方法
    #可以传入一段字符串,或者传入一个文件句柄。一般都会先用requests库获取网页内容,然后使用soup解析。
    soup=BeautifulSoup(html_doc,'html.parser')#这里一定要指定解析器,可以使用默认的html,也可以使用lxml比较快。
    print(soup.prettify())#按照标准的缩进格式输出获取的soup内容。
    
    <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 three little sisters; and their names were
       <a class="sister" href="http://example.com/elsie" id="link1">
        Elsie
       </a>
       ,
       <a class="sister" href="http://example.com/lacie" id="link2">
        Lacie
       </a>
       and
       <a class="sister" href="http://example.com/tillie" id="link3">
        Tillie
       </a>
       ;
    and they lived at the bottom of a well.
      </p>
      <p class="story">
       ...
      </p>
     </body>
    </html>
    

    #几种简单浏览结构化数据的方法:
    print(soup.title)#获取文档的title
    print(soup.title.name)#获取title的name属性
    print(soup.title.string)#获取title的内容
    print(soup.title.parent.name)#获取title的parent名称,也就是head,上一级.
    print(soup.p)#获取文档中第一个p节点
    print(soup.p['class'])#获取第一个p节点的class内容
    print(soup.a)#获取文档的第一个a节点
    print(soup.find_all('a'))#获取文档中所有的a节点,返回一个list
    soup.find(id='link3')#获取文档中id属性为link3的节点
    
    <title>The Dormouse's story</title>
    title
    The Dormouse's story
    head
    <p class="title"><b>The Dormouse's story</b></p>
    ['title']
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
    [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    
    
    
    
    
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
    
    for link in soup.find_all('a'):
        print(link.get('href'))#获取a节点的href属性
    
    http://example.com/elsie
    http://example.com/lacie
    http://example.com/tillie
    
    #print(soup.get_text())
    print(soup.text)#两种方式都可以返回获取的所有文本
    
    The Dormouse's story
    
    The Dormouse's story
    Once upon a time there were three little sisters; and their names were
    Elsie,
    Lacie and
    Tillie;
    and they lived at the bottom of a well.
    ...
    

    对象的种类

    其实HTML文档包含了很多的节点,这些节点一般可以归纳为4类,Tag,NavigableString,BeautifulSoup,Comment。

    Tag

    Tag就是html文档中的一个个标签。
    主要介绍Tag的name和attributes属性。

    soup = BeautifulSoup('<b class="boldest">Extremely bold</b>','html.parser')
    tag = soup.b
    type(tag)
    
    bs4.element.Tag
    
    #Name
    #属性通过.name来获取
    #如果改变tag的name,那么所有当前BS对象的HTML文档都会改变。
    print(tag.name)
    tag.name='blockquote'
    print(tag)
    
    b
    <blockquote class="boldest">Extremely bold</blockquote>
    
    #Attributes
    #获取方法比较简单,直接使用tag['attr_name']即可
    #或者直接tag.attrs,可以返回所有的属性组成的字典。
    print(tag['class'])
    print(tag.attrs)
    #tag的属性可以被删除或者修改,添加,与字典的操作方式一样
    tag['class']='verybold'
    tag['id']=1
    print(tag)
    #删除Tag的属性使用del方法
    del tag['id']
    
    verybold
    {'id': 1, 'class': 'verybold'}
    <blockquote class="verybold" id="1">Extremely bold</blockquote>
    
    #有时候一个属性可能存在多个值,比如class,那么就会返回一个list
    css_soup = BeautifulSoup('<p class="body strikeout"></p>','html.parser')
    print(css_soup.p['class'])
    
    ['body', 'strikeout']
    
    #将tag转换成字符串时,多值属性会合并为一个值;
    rel_soup = BeautifulSoup('<p>Back to the <a rel="index">homepage</a></p>','html.parser')
    rel_soup.a['rel'] = ['index', 'contents']
    print(rel_soup.p)
    #xml格式的文档不包含多值属性。
    
    <p>Back to the <a rel="index contents">homepage</a></p>
    

    可以遍历的字符串。
    字符串通常被包含在tag内,BS用NavigableString类来包装tag中的字符串。

    print(type(tag.string))#也就是tag的字符内容,<>string<>
    
    <class 'bs4.element.NavigableString'>
    
    #tag中的字符串不能编辑,但是可以替换成其他字符串
    tag.string.replace_with('No longer bold')
    print(tag)
    
    <blockquote class="verybold">No longer bold</blockquote>
    

    遍历文档数

    还拿之前的html_doc来举例,演示如何从一段内容找到另一段内容。

    soup=BeautifulSoup(html_doc,'html.parser')
    

    子节点

    一个tag可能包含多个字符串或者其他tag,都是这个tag的子节点。

    #如果想要获取当前名字的第一个tag,直接用.tag_name就可以实现
    print(soup.a)
    #如果想要获取当前名字的所有tag,需要用find_all('tag_name')才可以
    print(soup.find_all('a'))
    #tag的.contents属性可以将tag的子节点以-列表-的方式输出
    head_tag=soup.head
    print(head_tag.contents)
    #通过tag的.children生成器,可以对tag的子节点进行循环,(直接子节点)
    for child in head_tag.children:
        print(child)
    #.descendants属性可以对所有tag的子孙节点进行递归循环:
    for child in head_tag.descendants:
        print(child)
    #.string属性,如果tag只有一个NavigableString类型子节点,那么这个tag可以使用.string得到子节点:
    #如果包含多个子节点,tag就无法确定.string的方法应该调用哪个子节点,所以输出None。
    
    #如果tag中包含多个字符串,可以用.strings来循环获取,输出的字符串可能包含多个空格或空行,
    #使用.stripped_strings可以去除多余空白内容。
    for string in soup.stripped_strings:
        print(repr(string))
    

    父节点

    每个tag或字符串都由父节点,也就是包含在某个tag中。

    #.parent属性,用于获取某个元素的父节点,比如:
    title_tag=soup.title
    print(title_tag.parent)
    #文档title的字符串也有父节点,title标签
    #.parents,可以遍历tag到根节点的所有节点。
    
    <head><title>The Dormouse's story</title></head>
    

    兄弟节点

    一段文档以标准格式输出时,兄弟节点有相同的缩进级别.
    .next_sibling和.previous_sibling属性,用来查询兄弟节点:
    .next_siblings和.previous_siblings属性,可以对当前节点的兄弟节点迭代输出。

    回退和前进

    .next_element 和 .previous_element属性指向解析过程中的下一个或者上一个解析对象。
    .next_elements 和 .previous_elements属性,上或者下解析内容,列表。

    搜索文档树

    查找解析文档中的标签节点

    #1、传入字符串
    soup.find_all('b')#查找所有<b>标签
    #2、正则表达式
    import re
    for tag in soup.find_all(re.compile('^b')):
        print(tag.name)
    #3、传入列表参数
    soup.find_all(['a','b'])#查找所有的<a><b>标签
    #4、True参数,可以匹配任何值,
    #5、如果没有合适的过滤器,还可以定义一个方法,方法只接受一个元素参数,如果这个方法返回True,表示匹配到元素
    def has_class_but_no_id(tag):
        return tag.has_attr('class') and not tag.has_attr('id')
    #可以将上面方法传入find_all()方法
    soup.find_all(has_class_but_no_id)
    #通过一个方法来过滤一类-标签属性-的时候,这个方法的参数是要被过滤的属性的值,而不是这个标签。
    def not_lacie(href):
        return href and not re.compile('lacie').search(href)
    soup.find_all(href=not_lacie)#找出href属性不符合指定正则的标签。
    

    find_all()方法

    find_all( name , attrs , recursive , string , **kwargs )
    搜索当前tag的所有子节点,并且判断是否符合过滤器的条件

    #name参数,查找所有名字为name的tag,字符串对象被忽略。
    soup.find_all('title')
    #keyword参数,如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索。
    soup.find_al(id='link2')
    soup.find_all(href=re.compile('elsie'))
    #如果多个指定名字的参数可以同时过滤tag的多个属性:
    soup.find_all(href=re.compile('elsie'),id='link1')
    #有些tag属性在搜索不能使用,比如HTML5中的data*属性,但是可以通过find_all()的attrs参数定义一个字典来搜索:
    data_soup.find_all(attrs={'data-foo':'value'})
    

    按css搜索

    #BS4.1开始,可以通过class_参数搜索具有指定css类名的tag:
    soup.find_all('a',class_='sister')
    #接受通过类型的过滤器,比如正则表达式
    soup.find_all(class_=re.compile('it1'))
    

    string参数

    soup.find_all(string='Elsie')
    

    limit参数

    可以用来限制返回结果的数量

    recursive参数

    如果指向搜索tag的直接子节点,可以使用参数recursive=False。

    像调用find_all()一样来调用tag

    每个tag对象可以被当作一个方法来使用,与调用find_all()方法相同。

    soup.find_all('a')
    soup('a')#这两句代码时等价的
    

    find()方法

    与find_all()相同的用法,但是只能返回一个结果。

    CSS选择器,select方法

    soup.select('title')#选择title标签
    soup.select('p nth-of-type(3)')
    
    #通过tag标签逐层查找
    soup.select('body a')#查找body标签下面的a标签
    #找到某个tag标签下的直接子标签:
    soup.select('head>title')
    #通过id来查找:
    soup.select('#link1')
    #通过class来查找:
    soup.select('.sister')
    soup.select('[class~=sister]')
    #通过是否存在某个属性来查找:
    soup.select('a[href]')
    #通过属性的值来查找:
    soup.select('a[href="http://www.baidu.com"]')
    

    如果您觉得感兴趣的话,可以添加我的微信公众号:一步一步学Python

  • 相关阅读:
    pycharm快捷键
    Docker
    Go语言与Elasticsearch
    Celery与APScheduler
    爬虫入门到入狱
    数据分析
    后台管理
    Linux基础与自动化运维
    微信小程序
    Git
  • 原文地址:https://www.cnblogs.com/xingzhui/p/7852778.html
Copyright © 2011-2022 走看看