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

一、 引言
在《第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
请大家多多支持,点赞、评论和加关注!谢谢!

原文地址:https://www.cnblogs.com/LaoYuanPython/p/11931756.html