第14.12节 Python中使用BeautifulSoup解析http报文:使用select方法快速定位内容

2023-11-04

一、 引言
在《第14.10节 Python中使用BeautifulSoup解析http报文:html标签相关属性的访问》和《第14.11节 Python中使用BeautifulSoup解析http报文:使用查找方法快速定位内容》介绍了通过属性和查找方法定位HTML报文的内容的方法,除了这两种方法还有一种方法就是通过使用CSS选择器的语法找到tag,关于css选择器老猿在此不进行介绍,大家可以自行查找文档了解,老猿推荐W3School 的《CSS 选择器参考手册》。其实不了解也问题不大,本节的内容绝大部分还是很好理解的。

二、 select方法

  1. 语法调用:
    select(selector,namespace=None,limit=None,**kwargs)

  2. 语法释义
    1)参数selector为css选择器,关于CSS 选择器,请参考W3School 的《CSS 选择器参考手册》,具体应用方法请见第三部分;
    2)namespace:为一个映射css选择器名字空间到名字空间URIs的字典,老猿对css选择器没有研究过,使用时一般用缺省参数
    3)limit:限制查找到的内容个数,缺省不限制个数;
    4)kwargs:老猿没有查到相关资料,暂时不使用;
    5)返回值为一个列表,里面包含所有满足条件的html元素。

关于select的参数,官网上没有列出,只在举例中使用了第一个参数,老猿是通过help查出来的参数。不过也说明其他参数不重要,我们也就不关注了。

三、 使用select的几种场景及方法

  1. 本部分的html文本及BeatifulSoap对象定义如下:
>>> html='''<html><head><title>老猿Python</title></head>
<body><div>
    <h1 id="l1" class='t1' name="line1">老猿Python第1行</h1>
    <h2 id="l2" class='t2' name="line2">老猿Python第2行</h2>
    <h3 id="l3" class='t3' name="line3">老猿Python第3行</h3>
    <div>
       <h1 id="l4" class='t1' name="line4">LaoYuanPython第1行</h1>
       <h2 id="l5" class='t2' name="line5">LaoYuanPython第2行</h2>
       <h3 id="l6" class='t3' name="line6">LaoYuanPython第3行</h3>
   </div>
</div></body></html>'''
>>> soup = BeautifulSoup(html, 'lxml')
>>>
  1. 查找某个名称的所有标签
    要查找某个名称的所有标签,直接在BeatifulSoap对象下调用select,语法如下:
    select(“标签名”)
    如:
>>> soup.select('h1')
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h1 class="t1" id="l1" name="line1">LaoYuanPython第1行</h1>]
>>>

soup.select(‘h1’)效果与soup.find_all(‘h1’)相同。当然调用也可以从某个标签对象发起,这样是查的该标签对象下所有指定名称的标签。如:

>>> soup.div.div.select('h1')
[<h1 class="t1" id="l1" name="line1">LaoYuanPython第1行</h1>]
>>>
  1. 查找某个符合要求的所有标签
    这个功能是“查找某个名称的所有标签”的扩展,也可以说“查找某个名称的所有标签”是本功能的一个特例。

语法为:
select(“css选择器”)
其中css选择器可以是如下内容:
1)标签名:等同于功能“查找某个名称的所有标签”
2)css类名:查找css类名为指定类名的所有html元素,语法为:
select(”.类名”)
注意类名前有个小数点

>>> soup.select('.t1')
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h1 class="t1" id="l1" name="line1">LaoYuanPython第1行</h1>]
>>> 

3)属性名:查找存在属性为指定属性名的所有html元素,语法为:
select(”[属性名]”),如:

>>> soup.select('[class]')
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h2 class="t2" id="l2" name="line2">老猿Python第2行</h2>, <h3 class="t3" id="l3" name="line3">老猿Python第3行</h3>, <h1 class="t1" id="l1" name="line1">LaoYuanPython第1行</h1>, <h2 class="t2" id="l2" name="line2">LaoYuanPython第2行</h2>, <h3 class="t3" id="l3" name="line3">LaoYuanPython第3行</h3>]
>>> soup.select('[name]')
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h2 class="t2" id="l2" name="line2">老猿Python第2行</h2>, <h3 class="t3" id="l3" name="line3">老猿Python第3行</h3>, <h1 class="t1" id="l1" name="line1">LaoYuanPython第1行</h1>, <h2 class="t2" id="l2" name="line2">LaoYuanPython第2行</h2>, <h3 class="t3" id="l3" name="line3">LaoYuanPython第3行</h3>]
>>>

4)属性名+属性值查找:

>>> soup.select("[name='line5']")	
[<h2 class="t2" id="l5" name="line5">LaoYuanPython第2行</h2>]
>>>

属性名值支持首字符串(使用^符号)匹配、尾字符串匹配(使用$符号)和包含字符串(使用*符号)匹配:

>>> soup.select("[name^='line']") #属性名+属性值开始字符串匹配
		
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h2 class="t2" id="l2" name="line2">老猿Python第2行</h2>, <h3 class="t3" id="l3" name="line3">老猿Python第3行</h3>, <h1 class="t1" id="l4" name="line4">LaoYuanPython第1行</h1>, <h2 class="t2" id="l5" name="line5">LaoYuanPython第2行</h2>, <h3 class="t3" id="l6" name="line6">LaoYuanPython第3行</h3>]
>>> soup.select("[name$='e5']") #属性名+属性值尾字符串匹配
		
[<h2 class="t2" id="l5" name="line5">LaoYuanPython第2行</h2>]
>>> soup.select("[name*='e5']") #属性名+属性值字符串包含内容匹配
		
[<h2 class="t2" id="l5" name="line5">LaoYuanPython第2行</h2>]
>>>
>>>

5)id名:查找id为指定名字的所有html元素,语法为:
select(”#id名”),如:

>>> soup.select('#l1')
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h1 class="t1" id="l1" name="line1">LaoYuanPython第1行</h1>]
>>>

6)叠加标签:
上述第2-4种方法,可以在选择器前面叠加一个标签名,就可以实现在上述方法的基础上叠加需要满足标签名的要求的查找条件,如:

>>> soup.select("h1.t1") #标签名+css类名
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h1 class="t1" id="l4" name="line4">LaoYuanPython第1行</h1>]
>>> soup.select("h1[name]") #标签名+属性名
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h1 class="t1" id="l4" name="line4">LaoYuanPython第1行</h1>]
>>> soup.select("h1[name=line1]") #标签名+属性名+属性值
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>]
>>> soup.select("h1#l4") #标签名+id值
[<h1 class="t1" id="l4" name="line4">LaoYuanPython第1行</h1>]

注意以上条件组合时,如果标签和后面叠加内容要求是同一个标签下的内容时,标签和后面内容不能加空格,如果加了空格,就是到标签下的子标签中查找后面叠加内容的元素。如:

>>> soup.select("h1#l4") #查找标签为h1且id为l4的标签
[<h1 class="t1" id="l4" name="line4">LaoYuanPython第1行</h1>]
>>> soup.select("h1 #l4") #查找父标签为h1且其下id为l4的子孙标签
[]
>>> soup.select("div #l4") #查找父标签为div且其下id为l4的子孙标签
[<h1 class="t1" id="l4" name="line4">LaoYuanPython第1行</h1>]
>>>

属性名查找支持模糊查找

>>> soup.select("h3[class$='3']") #标签名+属性名1+属性名+属性值尾字符匹配
[<h3 class="t3" id="l3" name="line3">老猿Python第3行</h3>, <h3 class="t3" id="l6" name="line6">LaoYuanPython第3行</h3>]
>>> soup.select("h1[name^='line']") #标签名+属性名+属性值开始字符串匹配
 [<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h1 class="t1" id="l4" name="line4">LaoYuanPython第1行</h1>]
>>>

4. 在某个标签下查找所有子孙节点标签
其中的selector参数填写父标签和子标签名,使用空格分隔,selector参数的实参内容为:“父标签名 子孙标签1 … 子孙标签n”,每个标签鉴间用空格分隔。父标签可以从HTML报文的任意一个标签开始,子孙标签1可以是父标签的直接子标签也可以是更低层次的子孙标签,后面每个子孙标签都是前一个标签的直接子标签或更低层次的子孙标签。如:

>>> soup.div.div.select('h1')
[<h1>LaoYuanPython第一行</h1>]
>>> soup.select('body h2')
[<h2>老猿Python第二行</h2>, <h2>老猿Python第三行</h2>, <h2>LaoYuanPython第二行</h2>, <h2>LaoYuanPython第三行</h2>]
>>> soup.select('body div h2 ')
[<h2>老猿Python第二行</h2>, <h2>老猿Python第三行</h2>, <h2>LaoYuanPython第二行</h2>, <h2>LaoYuanPython第三行</h2>]
>>> soup.select('body div div h2 ')
[<h2>LaoYuanPython第二行</h2>, <h2>LaoYuanPython第三行</h2>]

5. 在某个标签下查找所有直接子标签
其中的selector参数填写父标签和子标签名,使用大于号分隔,selector参数的实参内容为:“父标签名>子孙标签1> …> 子孙标签n”,每个标签鉴间用大于号分隔。父标签可以从HTML报文的任意一个标签开始,子孙标签1必须是父标签的直接子标签,后面每个子孙标签都是前一个标签的直接子标签。如:

>>> soup.select('body>div>h2 ')
[<h2>老猿Python第二行</h2>, <h2>老猿Python第三行</h2>]
>>>

6. 查找解析的某个标签后面的兄弟标签
此功能与《第14.10节 Python中使用BeautifulSoup解析http报文:html标签相关属性的访问》、《第14.11节 Python中使用BeautifulSoup解析http报文:使用查找方法快速定位内容
》介绍的兄弟标签有所不同。

语法如下:
BeautifulSoup.select(“css选择器1 ~ css选择器2”)
该方法是查找css选择器1确认的首个标签后,到该标签后面内容中的兄弟标签中查找满足css选择器2的兄弟标签。如:

>>> soup.select("[name^='line']")
		
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h2 class="t2" id="l2" name="line2">老猿Python第2行</h2>, <h3 class="t3" id="l3" name="line3">老猿Python第3行</h3>, <h1 class="t1" id="l4" name="line4">LaoYuanPython第1行</h1>, <h2 class="t2" id="l5" name="line5">LaoYuanPython第2行</h2>, <h3 class="t3" id="l6" name="line6">LaoYuanPython第3行</h3>]
>>> soup.select("[name^='line'] ~ [class='t2']")
		
[<h2 class="t2" id="l2" name="line2">老猿Python第2行</h2>, <h2 class="t2" id="l5" name="line5">LaoYuanPython第2行</h2>]
>>>

7. 一次查找多个标签
要查找的标签间用逗号分隔,如:

>>> soup.select("h3.t3,h1#l4")
		
[<h3 class="t3" id="l3" name="line3">老猿Python第3行</h3>, <h1 class="t1" id="l4" name="line4">LaoYuanPython第1行</h1>, <h3 class="t3" id="l6" name="line6">LaoYuanPython第3行</h3>]
>>>

四、 select查找的总结
上面罗列了很多html元素通过css选择器来查找的场景,老猿总结select的使用方法如下:
1、 select可以通过只传递一个”css选择器”参数来调用;
2、 ”css选择器”参数可以支持嵌套多个子选择器组合,每个子选择器的构成方式包括:
1)单个标签;
2)单个属性;
3)单个属性值;
4)单个css类;
5)单个id;
6)以上内容的组合,组合时多个组合项之间不能有空格,如:

>>> soup.select("h1#l1[name$='1'].t1")#标签+id+属性尾字符匹配+CSS类的组合查找
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>]
>>> soup.select("h1#l1[name$='1'] .t1") #css类前有空格,会认为是两个子选择器,且相互之间是祖先节点与孙节点的关系
[]
>>>

且这些子选择器每相邻的两个子选择器之间可以支持不同的关系组合,包括:
1)父子关系组合:不同的选择器之间用大于号(>)分隔,后一个选择器查找html元素时只能到前一个选择器定位的标签内的直接子节点内查找。如:

>>> soup.select("body>div>h1[class='t1']")
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>]
>>>

2)子孙关系组合:不同的选择器之间用空格分隔,后一个选择器查找html元素时只能到前一个选择器定位的首个标签的子孙节点内查找。如:

>>> soup.select("body div>h1[class='t1']")
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h1 class="t1" id="l4" name="line4">LaoYuanPython第1行</h1>]
>>>

3)兄弟关系组合:不同的选择器之间用波浪线(~)分隔,后一个选择器查找html元素时只能到前一个选择器定位的首个标签的后面的兄弟节点内查找。如:

>>> soup.select("div>h1~#l3") #查找div节点的直接子节点h1的后面的id为l3兄弟节点
[<h3 class="t3" id="l3" name="line3">老猿Python第3行</h3>]
>>> soup.select("div h1~[class='t3']")  #查找div节点的子孙节点h1后面的class属性值为t3的兄弟节点
[<h3 class="t3" id="l3" name="line3">老猿Python第3行</h3>, <h3 class="t3" id="l6" name="line6">LaoYuanPython第3行</h3>]
>>>

4)并列关系组合:不同的选择器之间用逗号(,)分隔,查找时两个选择器之间是或的关系,即只要满足任意一个选择器的条件都认为符合查找要求。

>>> soup.select("div>h1#l1,div>div>h3.t3")
[<h1 class="t1" id="l1" name="line1">老猿Python第1行</h1>, <h3 class="t3" id="l6" name="line6">LaoYuanPython第3行</h3>]
>>>

五、 select_one
除了使用select找出所有满足条件的html元素外,select还有一个姊妹方法select_one,使用方法与select是一样的,只是返回值不同,select_one返回第一个满足条件的html元素,而不是一个列表。

本节详细介绍了使用BeautifulSoup的select方法解析html报文的各种场景,并在介绍各种场景的基础上老猿将select支持的css选择器模式进行了归类总结,包括单个子选择器的组成方式以及多个子选择器两两之间的关系进行了分类。通过这些知识总结,就算对css选择器不熟悉的人也能熟练掌握BeautifulSoup的select解析方法。

老猿Python,跟老猿学Python!
博客地址:https://blog.csdn.net/LaoYuanPython

老猿Python博客文章目录:https://blog.csdn.net/LaoYuanPython/article/details/98245036
请大家多多支持,点赞、评论和加关注!谢谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第14.12节 Python中使用BeautifulSoup解析http报文:使用select方法快速定位内容 的相关文章

  • Python:在列表理解本身中引用列表理解?

    这个想法刚刚出现在我的脑海中 假设您出于某种原因想要通过 Python 中的列表理解来获取列表的唯一元素 i if i in created comprehension else 0 for i in 1 2 1 2 3 1 2 0 0 3
  • Django 代理模型的继承和多态性

    我正在开发一个我没有启动的 Django 项目 我面临着一个问题遗产 我有一个大模型 在示例中简化 称为MyModel这应该代表不同种类的物品 的所有实例对象MyModel应该具有相同的字段 但方法的行为根据项目类型的不同而有很大差异 到目
  • 通过 Scrapy 抓取 Google Analytics

    我一直在尝试使用 Scrapy 从 Google Analytics 获取一些数据 尽管我是一个完全的 Python 新手 但我已经取得了一些进展 我现在可以通过 Scrapy 登录 Google Analytics 但我需要发出 AJAX
  • SQLAlchemy 通过关联对象声明式多对多自连接

    我有一个用户表和一个朋友表 它将用户映射到其他用户 因为每个用户可以有很多朋友 这个关系显然是对称的 如果用户A是用户B的朋友 那么用户B也是用户A的朋友 我只存储这个关系一次 除了两个用户 ID 之外 Friends 表还有其他字段 因此
  • 使 django 服务器可以在 LAN 中访问

    我已经安装了Django服务器 可以如下访问 http localhost 8000 get sms http 127 0 0 1 8000 get sms 假设我的IP是x x x x 当我这样做时 从同一网络下的另一台电脑 my ip
  • 如何在flask中使用g.user全局

    据我了解 Flask 中的 g 变量 它应该为我提供一个全局位置来存储数据 例如登录后保存当前用户 它是否正确 我希望我的导航在登录后在整个网站上显示我的用户名 我的观点包含 from Flask import g among other
  • 使用 matplotlib 绘制时间序列数据并仅在年初显示年份

    rcParams date autoformatter month b n Y 我正在使用 matpltolib 来绘制时间序列 如果我按上述方式设置 rcParams 则生成的图会在每个刻度处标记月份名称和年份 我怎样才能将其设置为仅在每
  • 如何使用Conda下载python包并随后离线安装?

    我知道通过 pip 我可以使用以下命令下载 Python 包 但 pip install 破坏了我的内部包依赖关系 当我做 pip download
  • 如何使用 Ansible playbook 中的 service_facts 模块检查服务是否存在且未安装在服务器中?

    我用过service facts检查服务是否正在运行并启用 在某些服务器中 未安装特定的软件包 现在 我如何知道这个特定的软件包没有安装在该特定的服务器上service facts module 在 Ansible 剧本中 它显示以下错误
  • 使用 on_bad_lines 将 pandas.read_csv 中的无效行写入文件

    我有一个 CSV 文件 我正在使用 Python 来解析该文件 我发现文件中的某些行具有不同的列数 001 Snow Jon 19801201 002 Crom Jake 19920103 003 Wise Frank 19880303 l
  • 以编程方式停止Python脚本的执行? [复制]

    这个问题在这里已经有答案了 是否可以使用命令在任意行停止执行 python 脚本 Like some code quit quit at this point some more code that s not executed sys e
  • 使用 Tkinter 显示 numpy 数组中的图像

    我对 Python 缺乏经验 第一次使用 Tkinter 制作一个 UI 显示我的数字分类程序与 mnist 数据集的结果 当图像来自 numpy 数组而不是我的 PC 上的文件路径时 我有一个关于在 Tkinter 中显示图像的问题 我为
  • AWS EMR Spark Python 日志记录

    我正在 AWS EMR 上运行一个非常简单的 Spark 作业 但似乎无法从我的脚本中获取任何日志输出 我尝试过打印到 stderr from pyspark import SparkContext import sys if name m
  • 如何在ipywidget按钮中显示全文?

    我正在创建一个ipywidget带有一些文本的按钮 但按钮中未显示全文 我使用的代码如下 import ipywidgets as widgets from IPython display import display button wid
  • Flask如何获取请求的HTTP_ORIGIN

    我想用我自己设置的 Access Control Allow Origin 标头做出响应 而弄清楚请求中的 HTTP ORIGIN 参数在哪里似乎很混乱 我在用着烧瓶 0 10 1 以及HTTP ORIGIN似乎是这个的特点之一object
  • 在Python中获取文件描述符的位置

    比如说 我有一个原始数字文件描述符 我需要根据它获取文件中的当前位置 import os psutil some code that works with file lp lib open path to file p psutil Pro
  • 使用 \r 并打印一些文本后如何清除控制台中的一行?

    对于我当前的项目 有一些代码很慢并且我无法使其更快 为了获得一些关于已完成 必须完成多少的反馈 我创建了一个进度片段 您可以在下面看到 当你看到最后一行时 sys stdout write r100 80 n I use 80覆盖最终剩余的
  • 如何在Python中对类别进行加权随机抽样

    给定一个元组列表 其中每个元组都包含一个概率和一个项目 我想根据其概率对项目进行采样 例如 给出列表 3 a 4 b 3 c 我想在 40 的时间内对 b 进行采样 在 python 中执行此操作的规范方法是什么 我查看了 random 模
  • Python 类继承 - 诡异的动作

    我观察到类继承有一个奇怪的效果 对于我正在处理的项目 我正在创建一个类来充当另一个模块的类的包装器 我正在使用第 3 方 aeidon 模块 用于操作字幕文件 但问题可能不太具体 以下是您通常如何使用该模块 project aeidon P
  • 导入错误:没有名为 site 的模块 - mac

    我已经有这个问题几个月了 每次我想获取一个新的 python 包并使用它时 我都会在终端中收到此错误 ImportError No module named site 我不知道为什么会出现这个错误 实际上 我无法使用任何新软件包 因为每次我

随机推荐