写点什么

Python 爬虫:BeatifulSoap 解析 HTML 报文的三个实用技巧

用户头像
老猿Python
关注
发布于: 2021 年 04 月 26 日
Python爬虫:BeatifulSoap解析HTML报文的三个实用技巧

<center><a href="https://blog.csdn.net/LaoYuanPython/article/details/98245036"><img src="https://img-blog.csdnimg.cn/20210412224055543.png" ></a></center>

☞ ░ 老猿Python博文目录:https://blog.csdn.net/LaoYuanPython

一、BeautifulSoup 简介

BeautifulSoup 是 Python 爬虫应用解析 Html 的利器,是 Python 三方模块 bs4 中提供的进行 HTML 解析的类,可以认为是一个 HTML 解析工具箱,对 HTML 报文中的标签具有比较好的容错识别功能。lxml 是一款 html 文本解析器,BeautifulSoup 构建对象时需要指定 HTML 解析器,推荐使用 lxml。


BeautifulSoup 和 lxml 安装命令


pip install -i https://pypi.tuna.tsinghua.edu.cn/simple bs4pip install -i https://pypi.tuna.tsinghua.edu.cn/simple lxml
复制代码


加载 BeautifulSoup


from bs4 import BeautifulSoup
复制代码


BeatifulSoap 解析 HTML 报文的常用功能


  1. 通过 BeautifulSoup 对象可以访问标签对应的 html 元素、并进一步访问标签的名字、属性、html 元素标签对中的内容。案例


from bs4 import BeautifulSoupimport urllib.requestdef getURLinf(url):     header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36'}    req = urllib.request.Request(url=url,headers=header)    resp = urllib.request.urlopen(req,timeout=5)    html = resp.read().decode()      soup = BeautifulSoup(html,'lxml')    return (soup,req,resp)     soup,req ,resp  = getURLinf(r'https://blog.csdn.net/LaoYuanPython/article/details/111303395')
print(soup.p)print(soup.link)print(soup.title)print(soup.link.attrs)print(soup.link['rel'])
复制代码


  1. 通过标签的 contents 属性,可以访问其下嵌套的所有下级 HTML 元素,这些该标签下的子标签对应的 HTML 元素放到一个 contents 指向的列表中。如: print(soup.body.contents)

  2. 可以访问标签对应的父、子、兄弟及祖先标签信息;

  3. 使用 strings 属性迭代访问除标签外的所有内容;

  4. 可以使用 find、find_all、find_parent、find_parents 等系列方法查找满足特定条件的标签;

  5. 使用 select 通过 css 选择器定位特定标签。


具体的大家可以参考老猿博客的免费专栏《爬虫:https://blog.csdn.net/laoyuanpython/category_9103810.html》或付费专栏《Python爬虫入门:https://blog.csdn.net/laoyuanpython/category_10762553.html》的相关介绍。

二、一些解析技巧

在 HTML 解析时,如果通过简单的 tag、或单个 tag 属性(如 id、class)或文本一次搜索或 select 定位是最简单的,而有些情况需要使用组合方法才能处理。

2.1、通过标签的多个属性组合定位或查找

经常有些要定位的标签有很多,按单个属性查找也有很多,得使用多个属性查找。如:


<div id="article_content" class="article_content clearfix">......</div><div id="article_content" class="article_view">......</div><div id="article_view" class="article_view">......</div>
复制代码


上面的 html 文本中有多个 id 为 article_content 的 div 标签,如果使用:


>>> text="""```html<div id="article_content" class="article_content clearfix">......</div><div id="article_content" class="article_view">......</div><div id="article_view" class="article_view">......</div>""">>> s = BeautifulSoup(text,'lxml')>>> s.select('div#article_content')[<div class="article_content clearfix" id="article_content">......</div>, <div class="article_view" id="article_content">......</div>]>>>  
复制代码


就会返回两条记录。这时候就可以使用多标签属性定位的如下 4 种语句:


>>>s.select('div#article_content[class="article_content clearfix"]')[<div class="article_content clearfix" id="article_content">......</div>]>>>s.select('div[id="article_content"][class="article_content clearfix"]')[<div class="article_content clearfix" id="article_content">......</div>]>>>s.find_all("div",id="article_content",class_='article_content clearfix')[<div class="article_content clearfix" id="article_content">......</div>]>>>s.find_all("div","#article_content",class_='article_content clearfix')[<div class="article_content clearfix" id="article_content">......</div>]
复制代码


以上四种方式是等价的,因为 id 可以用 #来标记,class 在查找时需要和 Python 关键字 class 区分,因此有上述不同方法,注意 select 的每个属性必须用中括号括起来,不同属性的中括号之间不能有空格,如果有空格表示的就不是查找同一标签的属性,空格后的属性表示前一个属性对应标签的子孙标签的属性。

2.2、利用 tag 标签关系定位内容

tag 标签关系包括父子、兄弟、祖先等关系,有时要查找或定位的内容本身不是很好定位,但结合其他标签关系(主要是父子、祖先关系)则可以唯一确认。案例:这是 CSDN 的博文中关于博主个人信息的部分报文:


<div class="data-info d-flex item-tiling">               <dl class="text-center" title="1055">                   <a href="https://blog.csdn.net/LaoYuanPython" data-report-click='{"mod":"1598321000_001","spm":"1001.2101.3001.4310"}' data-report-query="t=1">                       <dt><span class="count">1055</span></dt>                       <dd class="font">原创</dd>                   </a>               </dl>               <dl class="text-center" data-report-click='{"mod":"1598321000_002","spm":"1001.2101.3001.4311"}' title="22">                   <a href="https://blog.csdn.net/rank/writing_rank" target="_blank">                       <dt><span class="count">22</span></dt>                       <dd class="font">周排名</dd>                   </a>               </dl>           </div>
复制代码


以上报文中,如果要取博主的原创文章数和周排名,原创文章数和博主周排名的 tag 标签完全相同,二者都在 span 标签内,标签的属性及值都相同,只是 span 标签的父标签 dt 标签的兄弟标签 dd 标签的 string 的中文内容才能区分。对于这种情况,首先要通过祖先标签<div class="data-info d-flex item-tiling">定位到祖先标签,再在祖先标签内通过中文字符串定位到要访问属性的兄弟标签的子标签,然后通过该子标签找到其父标签的父标签,再通过该父标签的 dt 子标签的 span 子标签访问具体取值。


示例代码如下:


>>> text="""<div class="data-info d-flex item-tiling">               <dl class="text-center" title="1055">                   <a href="https://blog.csdn.net/LaoYuanPython" data-report-click='{"mod":"1598321000_001","spm":"1001.2101.3001.4310"}' data-report-query="t=1">                       <dt><span class="count">1055</span></dt>                       <dd class="font">原创</dd>                   </a>               </dl>               <dl class="text-center" data-report-click='{"mod":"1598321000_002","spm":"1001.2101.3001.4311"}' title="22">                   <a href="https://blog.csdn.net/rank/writing_rank" target="_blank">                       <dt><span class="count">22</span></dt>                       <dd class="font">周排名</dd>                   </a>               </dl>           </div>""">>> s = BeautifulSoup(text,'lxml')>>> subSoup = s.select('[class="data-info d-flex item-tiling"] [class="font"]')>>> for item in subSoup:           parent = item.parent           if item.string=='原创':               orignalNum = int(parent.select('.count')[0].string)           elif item.string=='周排名':               weekRank =  int(parent.select('.count')[0].string)
>>> print(orignalNum,weekRank)1055 22>>>
复制代码


注意:上面的 select 使用的也是标签的属性来定位标签,并且两个中括号之间有空格,表明后一个要查找的标签在前一个属性对应标签的子孙标签范围内。

2.3、分析前去除程序代码避免干扰

在解析 HTML 报文时,绝大多数情况是需要分析有用的标签信息,但作为技术文章,大部分的博文中都有代码,这些代码可能会对分析进行干扰。如本文中的代码含有一些分析的 HTML 报文,如果获取本文的完整 HTML 内容,这些报文在非代码部分也会出现,此时要排除代码的影响,可以将代码先从分析内容中去除再来分析。


目前大多数技术平台的博文编辑器都支持对代码的标识,象 markdown 等编辑器代码的标签为 code 标检,如果有其他编辑器用不同标签的,只有确认了标签名,都可以按下面介绍的类似方式来处理。处理步骤如下


  1. 获取报文;

  2. 构建 BeatifulSoap 对象 soup;

  3. 通过 soup.code.extract()或 soup.code.decompose()方式就从 soup 对象中去除了代码部分,decompose 方法与 extract 方法的区别就是 decompose 直接删除对应对象数据而 extract 再删除时将删除对象单独返回。


关于这部分内容的案例可以参考《https://blog.csdn.net/LaoYuanPython/article/details/114729045 n行Python代码系列:四行程序分离HTML报文中的程序代码》的详细介绍。

三、小结

本文介绍了使用 BeatifulSoap 解析 HTML 报文的三个使用技巧,包括通过多属性组合查找或定位标签、通过结合多个标签关系来定位标签以及去除 html 报文中的代码标签来避免代码对解析的影响。


写博不易,敬请支持:


如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!


如对文章内容存在疑问请在评论区留言或在老猿 Python 微信公号提问。


关于老猿的付费专栏

  1. 付费专栏《https://blog.csdn.net/laoyuanpython/category_9607725.html 使用PyQt开发图形界面Python应用》专门介绍基于 Python 的 PyQt 图形界面开发基础教程,对应文章目录为《 https://blog.csdn.net/LaoYuanPython/article/details/107580932 使用PyQt开发图形界面Python应用专栏目录》;

  2. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10232926.html moviepy音视频开发专栏 )详细介绍 moviepy 音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,对应文章目录为《https://blog.csdn.net/LaoYuanPython/article/details/107574583 moviepy音视频开发专栏文章目录》;

  3. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10581071.html OpenCV-Python初学者疑难问题集》为《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的伴生专栏,是笔者对 OpenCV-Python 图形图像处理学习中遇到的一些问题个人感悟的整合,相关资料基本上都是老猿反复研究的成果,有助于 OpenCV-Python 初学者比较深入地理解 OpenCV,对应文章目录为《https://blog.csdn.net/LaoYuanPython/article/details/109713407 OpenCV-Python初学者疑难问题集专栏目录

  4. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10762553.html Python爬虫入门 》站在一个互联网前端开发小白的角度介绍爬虫开发应知应会内容,包括爬虫入门的基础知识,以及爬取 CSDN 文章信息、博主信息、给文章点赞、评论等实战内容。


前两个专栏都适合有一定 Python 基础但无相关知识的小白读者学习,第三个专栏请大家结合《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的学习使用。


对于缺乏 Python 基础的同仁,可以通过老猿的免费专栏《https://blog.csdn.net/laoyuanpython/category_9831699.html 专栏:Python基础教程目录)从零开始学习 Python。


如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

跟老猿学 Python!

☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython

发布于: 2021 年 04 月 26 日阅读数: 47
用户头像

老猿Python

关注

学问无遗力,功夫老始成。 2020.08.21 加入

CSDN 2020年博客之星季军、高级程序员、超50万行C语言项目开发经验 擅长领域:Python语言、PyQt界面程序开发、Moviepy音视频剪辑、OpenCV-Python图像处理、爬虫、5G、区块链、人工智能数学基础

评论 (4 条评论)

发布
用户头像
哈哈,为啥infoq人这么少,我都从csdn过来的

2021 年 04 月 29 日 17:10
回复
好像刚搞没多久,才一周年
2021 年 04 月 30 日 08:08
回复
用户头像
老猿,2.3中有个beautifulsoup打错了
2021 年 04 月 29 日 09:11
回复
谢谢指正!!!
2021 年 04 月 29 日 16:02
回复
没有更多了
Python爬虫:BeatifulSoap解析HTML报文的三个实用技巧