zoukankan      html  css  js  c++  java
  • 细品BeautifulSoup节点访问

    在前面的章节中,我们介绍了如何爬取单个网页和多个网页。所提取页面标签内容基本都是使用find方法。

    在本章节,我们将对访问页面标签、属性和值进行一个系统的介绍,使用的url是https://www.ppzuowen.com/book/antushengtonghua/7403.html

    1.使用绝对路径访问标签

    在前面我们已经介绍过,HTML页面本质上是一棵DOM树,形状结构如下图所示:

    使用绝对路径访问,就是从HTML页面的根结点html开始,按照顺序访问对应的标签位置。比如,我们需要访问上图中的h1标签,那么我们设置的绝对访问路径就为html.body.div.h1。
    根据上面的介绍,我们来做一个实际的练习。

    比如我们要访问目标页面中的h1标签,那么我们需要设置的访问路径就是html.body.div.div.h1,获取标签的文本内容使用get_text方法,获取属性的值使用xxTag.attrs[xx]。

    我们可以使用urllib包或requests包来抓包。

    urllib抓包代码实现如下:

    # 请求库
    from urllib.request import urlopen
    import requests
    # 解析库
    from bs4 import BeautifulSoup
    
    # 爬取的网页链接
    url=r"https://www.ppzuowen.com/book/antushengtonghua/7403.html"
    html=urlopen(url)
    html.encoding=None
    bs=BeautifulSoup(html.read(),'html.parser')
    # print(bs.html.title.get_text())
    print('标签:',bs.html.div.div.h1)
    print('class属性:',bs.html.div.div.h1.attrs['class'])
    print('标签值:',bs.html.div.div.h1.get_text())
    

    requests抓包代码实现如下:

    # 请求库
    from urllib.request import urlopen
    import requests
    # 解析库
    from bs4 import BeautifulSoup
    
    # 爬取的网页链接
    url=r"https://www.ppzuowen.com/book/antushengtonghua/7403.html"
    html=requests.get(url)
    html.encoding=None
    bs=BeautifulSoup(html.text,'html.parser')
    # print(bs.html.title.get_text())
    print('标签:',bs.html.div.div.h1)
    print('class属性:',bs.html.div.div.h1.attrs['class'])
    print('标签值:',bs.html.div.div.h1.get_text())
    

    得到的结果如下:

    虽然在实际应用中使用绝对路径访问任意标签都是可以做到的,但是万一碰到的页面非常复杂,那么通过这种绝对路径访问标签就显得非常笨重与麻烦,影响工作效率,这是一般会采用相对路径的方式进行访问。

    2.相对路径访问

    2.1 find() 和 findAll() 访问

    在相对路径访问中,BeautifulSoup 里的 find() 和 findAll() 可能是你最常用的两个函数。

    借助它们,你可以通过标签的不同属性轻松地过滤 HTML 页面,查找需要的标签组或单个标签。这两个函数非常相似,BeautifulSoup 文档里两者的定义就是这样:

    findAll(tag, attributes, recursive, text, limit, keywords)
    find(tag, attributes, recursive, text, keywords)
    
    • 标签参数 tag:可以传一个标签的名称或多个标签名称组成的 Python列表做标签参数。例如,下面的代码将返回一个包含 HTML 文档中所有标题标签的列表:
      .findAll({"h1","h2","h3","h4","h5","h6"})
    • 属性参数 attributes: 是用一个 Python 字典封装一个标签的若干属性和对应的属性值。例如,下面这个函数会返回 HTML 文档里红色与绿色两种颜色的 span 标签:
      .findAll("span", {"class":{"green", "red"}})
    • 递归参数 recursive: 是一个布尔变量。你想抓取 HTML 文档标签结构里多少层的信息?如果recursive 设置为 True,findAll 就会根据你的要求去查找标签参数的所有子标签,以及子标签的子标签。如果 recursive 设置为 False,findAll 就只查找文档的一级标签。findAll默认是支持递归查找的(recursive 默认值是 True);一般情况下这个参数不需要设置,除非你真正了解自己需要哪些信息,而且抓取速度非常重要,那时你可以设置递归参数。
    • 文本参数 text :它是用标签的文本内容去匹配,而不是用标签的属性。假如想查找前面网页中包含“丑小鸭”内容的标签数量,可以把之前的 findAll 方法换成下面的代码:
    name=bs.findAll(text='丑小鸭')
    print(len(name))
    
    • 范围限制参数 limit,显然只用于 findAll 方法。find 其实等价于 findAll 的 limit 等于1 时的情形。如果你只对网页中获取的前 n 项结果感兴趣,就可以设置它。但是要注意,这个参数设置之后,获得的前几项结果是按照网页上的顺序排序的,未必是你想要的那前几项。

    关键词参数 keyword:可以让你选择那些具有指定属性的标签。例如:
    bs.findAll(href="/book/")
    虽然关键词参数 keyword 在一些场景中很有用,但是,它是 BeautifulSoup 在技术上做的一个冗余功能。任何用关键词参数能够完成的任务,同样可以用其他技术解决。
    例如,下面两行代码是完全一样的:

    bs.findAll(href="/book/")
    bs.findAll("", {"href":"/book/"})
    

    另外,用 keyword 偶尔会出现问题,尤其是在用 class 属性查找标签的时候,因为 class 是 Python 中受保护的关键字。不过,你可以在 class 后面增加一个下划线解决:
    bs.findAll(class_="subNav")

    2.2 Tag访问

    除了通过find() 和 findAll() 方法查找,还可以通过标签查找。正如前面反复强调的,HTML本质是一棵DOM树,因此可以通过某个tag去访问它的父节点、兄弟节点和子节点。

    • 处理子标签和其他后代标签

    在 BeautifulSoup 库里,孩子(child)和后代(descendant)有显著的不同:子标签就是一个父标签的下一级,而后代标签是指一个父标签下面所有级别的标签。

    例如,tr 标签是 table标签的子标签,而 tr、th、td标签都是 table 标签的后代标签。所有的子标签都是后代标签,但不是所有的后代标签都是子标签。

    一般情况下,BeautifulSoup 函数总是处理当前标签的后代标签。
    bs.p
    如果你只想找出子标签,可以用 .children 标签。例如:

    ls=bs.find('ul',{'class':'globeNav'}).children
    for child in ls:
        print(child)
    
    • 处理兄弟标签
      next_sibling 和 previous_sibling 函数可以用来返回当前节点的后一个弟节点和前一个兄节点。与 next_siblings 和 previous_siblings的作用类似,只是它们返回的是一组标签,而不是单个标签。例如:
    brother=bs.find('div',{'class':'nav mt10'}).div.previous_siblings
    for bro in brother:
        print('兄节点:',bro)
    brother=bs.find('div',{'class':'nav mt10'}).ul.next_siblings
    for bro in brother:
        print('弟节点:',bro)
    
    • 父标签处理
      BeautifulSoup 的父标签查找函数,parent 和 parents。例如:
    parents=bs.find('div',{'class':'nav mt10'}).parents
    for parent in parents:
        print('父节点:',parent)
    

    2.3 通过CSS选择器获取Tag对象

    • 通过标签名查找:
      bs.select('a') #返回所有的a标签 list
    • 通过类名查找:
     bs.select('.sister') #返回所有包含class="sister"的标签  list
     bs.select('a.sister')
    
    • 通过 id 名查找:
    bs.select('#link1')  #返回所有包含 id="link1"的标签  list
    bs.select("p#link1")
    
    • 组合查找:
     bs.select('p #link1')  #查找所有 p 标签中,id 等于 link1的标签  注意区分soup.select('p#link1')
     bs.select("html head title") or bs.select("body a")   #逐层查找    
     bs.select("p > a")  #直接子标签查找  注意是子标签不是子孙标签
    
    • 通过是否存在某个属性和属性的值来查找:
     bs.select('a[href]')
     bs.select('a[href="http://example.com/elsie"]')
     bs.select('a[href^="Example Domain"]')    #  ^=  开头
     bs.select('a[href$="tillie"]')                #  $=  结尾
     bs.select('a[href*=".com/el"]')               #  *=  包含
    

    除此之外,有时查找的对象只需要满足某一类条件即可,这时可以结合正则表达式进行模糊查找。

    关于正则表达式的编写,可以参照前面python基础部分的内容,这里不再赘述。

  • 相关阅读:
    【原创】大叔经验分享(53)kudu报错unable to find SASL plugin: PLAIN
    【原创】大叔经验分享(52)ClouderaManager修改配置报错
    【原创】大数据基础之Impala(3)部分调优
    【原创】大数据基础之Kudu(3)primary key
    【原创】大叔经验分享(51)docker报错Exited (137)
    【原创】大数据基础之Logstash(5)监控
    【原创】大数据基础之Logstash(4)高可用
    【原创】Linux基础之vi&vim基础篇
    【原创】大叔经验分享(50)hue访问mysql(librdbms)
    【原创】大叔经验分享(49)hue访问hdfs报错/hue访问oozie editor页面卡住
  • 原文地址:https://www.cnblogs.com/turing09/p/13171809.html
Copyright © 2011-2022 走看看