5、BeautifulSoup解析库详解

  • 本篇博文是自己在学习崔庆才的《Python3网络爬虫开发实战教程》的学习笔记系列

BeautifulSoup解析库详解

1、BeautifulSoup解析库简介

  • BeautifulSoup是Python的一个HTML或XML解析库,灵活又方便的网页解析库,处理高效,支持多种解析器。最主要的功能就是不用编写正则表达式即可方便的从网页爬取我们需要的数据。
  • BeautifulSoup将html解析为对象进行处理,全部页面转变为字典或者数组,相对于正则表达式的方式,可以大大简化处理过程。
  • Beautiful Soup3 目前已经停止开发,我们推荐在现在的项目中使用Beautiful Soup4。

2、BeautifulSoup安装

  • pip3 install BeautifulSoup4

3、BeautifulSoup用法讲解

1、解析器
解析器使用方法优势劣势
Python标准库BeautifulSoup(markup, “html.parser”)Python的内置标准库、执行速度适中 、文档容错能力强Python 2.7.3 or 3.2.2)前的版本中文容错能力差
lxml HTML 解析器(较常用)BeautifulSoup(markup, “lxml”)速度快、文档容错能力强需要安装C语言库(lxml库)
lxml XML 解析器)(有了lxml库就可以正常使用)BeautifulSoup(markup, “xml”)速度快、唯一支持XML的解析器需要安装C语言库
html5libBeautifulSoup(markup, “html5lib”)最好的容错性、以浏览器的方式解析文档、生成HTML5格式的文档(适用于目标代码杂乱的情况)速度慢、不依赖外部扩展
  • 注:lxml解析器有解析html和xml的功能,而且速度快,容错能力强,故推荐使用。
2、基本使用
2.1、使用方法
  • 导入模块——>爬取网页HTML信息(或者读取本地html文件信息)——>创建解析器——>输出网页内容——>提取网页标签中的内容>>
# 导入模块
from bs4 import BeautifulSoup
# 读取html文件信息(在真实代码中是爬取的网页信息)
f = open("./my.html",'r',encoding="utf-8")
content = f.read()
f.close()
# 创建解析器
soup = BeautifulSoup(content,"lxml")
# 输出网页内容:注:此内容已被缩进格式化(自动更正格式),其实这个在上一步实例化时就已完成
print(soup.prettify())
#输出网页中title标签中的内容
print(soup.title.string)
2.2、标签选择器(节点选择器)
  • 直接调用节点标签的名称就可以选择节点元素,再调用string属性就可以得到节点内的文本了,这种方式速度非常快。

  • ① 获取元素信息:

    • 将被bs4解析后的“soup”对象直接用soup.标签名的方式获取该标签信息,将返回带有标签字段的信息,并只返回匹配目标的第一个标签(类似于正则中的search()方法)。
    ...
    print(soup.title) #<title>我的网页</title>
    print(type(soup.title)) #<class 'bs4.element.Tag'>
    print(soup.head) #获取整个head元素,及内部元素
    print(soup.li) #获取第一个li元素(后面其他li不会获取)
    # <li class="item-0"><a class="bb" href="http://www.baidu.com">百度</a></li>
    
  • ② 提取信息(例如:标签名、标签属性、标签中间的文本内容等)

    ...
    print(soup.a) #获取第一个a元素标签: <a class="bb" href="http://www.baidu.com">百度</a>
    print(soup.a.name)    #获取标签名: a
    print(soup.a.attrs)    #获取所有属性:{'class': ['bb'], 'href': 'http://www.baidu.com'}
    print(soup.a.attrs['href']) #获取其中一个属性:http://www.baidu.com
    print(soup.a.string) # 获取元素标签中间的文本内容:百度
    
  • ③ 嵌套选择

  • 为更加精确的选择目标信息,使用标签之间层层迭代的方式嵌套,以“.”来连接标签名。

print(soup.li.a)   #获取网页中第一个li中的第一个a元素节点
#输出 <a class="bb" href="http://www.baidu.com">百度</a>
print(type(soup.body.h3))    #获取body中的第一个h3元素的类型:<class 'bs4.element.Tag'>
print(soup.body.h3.string)   #获取body中的第一个h3中的文本内容: 我的常用链接

④ 关联选择(子节点和子孙节点):

  • 我们在做选择的时候,难免有时候不能够一步就选到想要的节点元素。需要先选中某一个节点元素,然后再基于这些继续向下选择(子,父,兄弟)。
    # 子或子孙节点
    # 以下获取的节点列表都可以使用for...in遍历
    print(soup.ul.contents)    #获取ul下面的所有直接子节点,返回列表
    print(soup.ul.children)    #获取ul下面的所有直接子节点,返回一个(迭代器):<list_iterator object at 0x110346a20>
    print(soup.ul.descendants)   # 获取ul下的所有子孙节点,返回一个(迭代器)。
    for v in soup.ul.descendants:
        print("a:",v)
    # 父祖节点
    print(soup.a.parent)     #通过parent属性获取a的父节点 
    # print(list(soup.a.parents))   # 获取所有祖先节点
    #兄弟节点
    print(soup.li.next_siblings)    #获取指定li节点的所有后面的兄弟节点
    print(soup.li.previous_siblings)#获取指定li节点的所有前面的兄弟节点
    #for v in soup.li.next_siblings:
    #    print(v)
    
2.3 方法选择器
  • 单纯的使用标签选择器对于解析网页来说是远远不够的,所以需要加上方法选择器。
    • ① find_all() (类似于正则中的“findall”属性)

      • 定义:传入属性或文本,以列表形式返回所有符合条件的元素

      • 格式:find_all(name,attrs,recursive,text, **kwargs ),可根据标签名、属性、内容查找文档

      • a、以标签名来查找信息:

      • 格式:find_all(name=“标签名”) #以字典格式传入目标id信息

      • 等价于:find_all(“标签名”)

        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html, 'lxml')
        for ul in soup.find_all('ul'):     
            print(ul.find_all('li'))
        
      • 输出:输出

      • b、以属性信息来查找信息:

      • 格式:find_all(attrs={‘id’: ‘id名’}) #以字典格式传入目标id信息

      • 等价于:find_all(id=‘id名’) #此方法中如果以class属性查找,“class”需要加上“_”。

        # 通过attrs指定属性来获取所有元素节点
        lilist = soup.find_all(attrs={"class":"aa"})
        lilist = soup.find_all(class_="aa")    #和上行代码等价
        lilist = soup.find_all(class_="shop")    #class属性值中包含shop的所有节点
        lilist = soup.find_all(id="hid")       #<h3 id="hid">我的常用链接</h3>
        
      • C、通过文本内容查找

      • 格式:find_all(text=“”) #返回列表结果

        lilist = soup.find_all(text='百度') # 百度
        lilist = soup.find_all(text=re.compile('张')) # 张翠山 张无忌
        for i in lilist:
            print(i)
        
    • ② find()

      • 定义:传入属性或文本,返回所有符合条件的第一个元素,若没有匹配值,返回None
      • 注:和fing_all()用法一致,不过只返回第一个匹配值;类似于标签选择器。
    • ③其他选择函数

      • 1、find_parents()、 find_parent()
      • find_parents()返回所有祖先节点,find_parent()返回直接父节点。
      • 2、find_next_siblings() find_next_sibling()
      • find_next_siblings()返回后面所有兄弟节点,find_next_sibling()返回后面第一个兄弟节点。
      • 3、find_previous_siblings() find_previous_sibling()
      • find_previous_siblings()返回前面所有兄弟节点,find_previous_sibling()返回前面第一个兄弟节点。
      • 4、find_all_next() find_next()
      • find_all_next()返回节点后所有符合条件的节点, find_next()返回第一个符合条件的节点
      • 5、find_all_previous() 和 find_previous()
      • find_all_previous()返回节点后所有符合条件的节点, find_previous()返回第一个符合条件的节点
2.4、CSS选择器
  • 通过select()直接传入CSS选择器即可完成选择(可以通过选择"标签名"、".class名"、"#id"等来查找信息)。
  • 获取信息:
    • 获取属性值:a[“id”] 等价于 a.attrs[‘href’]
    • 获取文本信息:a.string 等价于 a.get_text()
    # 创建解析器
    soup = BeautifulSoup(content,"lxml")
    print(soup.select("ul li a"))     #获取ul里面li下面的a元素节点
    print(soup.select("#hid"))      #获取id属性值为hid的元素节点
    print(soup.select("li.shop a"))    #获取class属性为shop的li元素里面所有的a元素节点
    # 套用选择解析器
    blist = soup.select("ul li")
    for li in blist:
        a = li.select("a")[0] #获取每个li里面的a元素节点
        print(a)
        print(a['href'])       #获取属性href的值
        # print(a.attrs['href'])      #等价 同上 获取属性值
        print(a.get_text()) #等价 print(a.string)     获取元素节点的文本内容
    
2.5 总结
  • 推荐使用lxml解析库,必要时(代码非常混乱时)使用html.parser
  • 标签选择筛选功能弱但是速度快
  • 建议使用find()、find_all() 查询匹配单个结果或者多个结果
  • 如果对CSS选择器熟悉建议使用select()

3、补充知识点

  • 针对部分不完整的目标解析文档,使用“prettify()”方法进行格式化(比如标签未闭合等缺陷)
    soup = BeautifulSoup(content,"lxml")
    # 输出网页内容:注:此内容已被缩进格式化(自动更正格式)
    print(soup.prettify())
    
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值