BeautifulSoup 是一个用于解析HTML和XML文档的Python库,它提供了多种解析器和丰富的搜索功能。从BeautifulSoup的版本4.4.0开始,它支持使用CSS选择器来查找文档中的元素。
Beautiful Soup 4.12.0 文档
Beautiful Soup 当前支持的 CSS 选择器
一、CSS选择器类型
CSS选择器非常强大,支持多种类型的选择器。注意:CSS选择器是大小写不敏感的。
- 这些条件用“
,
”逗号分隔表示“或
”;直接相连使用表示“且
”。
1、 通用选择器:*
tag = soup.select('*') #匹配任何类型的元素
2、 ID选择器:#id
tag = soup.select('#my-id') #选择ID是 my-id 的标签
3、 类型选择器:标签
tag = soup.select('img') #选择所有<img>标签
tag = soup.select_one('img') #选择第一个<img>标签
4、 类名选择器:.类名
假设HTML多个类名:<input type="text" class="form-control search-text" name="keyword">
tag = soup.select('.col-3') #1. 选择类名是 col-3 的所有标签
tag = soup.select('div.col-3') #2. 选择类名是 col-3 的所有<div>标签
tag = soup.select('.col-3,.col-2') #3. 选择类名是col-3 或 col-2的所有标签
tag = soup.select('.form-control.search-text') #4. 选择具有多个类名,form-control和search-text的标签
tag = soup.select('img.logo[src$="logo2.png"]') #5. 选择类名是 logo,属性src以logo2.png结尾的<img>标签
5、 属性选择器:[属性=值]
tag = soup.select('[type]') #1. 具有type属性的所有标签
tag = soup.select('[type=""]') #2. type属性值为 空 的所有标签
tag = soup.select('[type="text"][name="keyword"]') #3. 具有多个属性的所有标签
tag = soup.select('input[disabled]') #4. 具有 disabled布尔属性 的<input>标签
tag = soup.select('input[type^="text"]') #5. ^= 属性值以 text 开头
tag = soup.select('input[type|="text"]') #6. |= 属性值以 text 开头,或正好是text
tag = soup.select('input[type$="text"]') #7. $= 属性值以 text 结尾
tag = soup.select('input[type*="text"]') #8. *= 属性值包含 text
tag = soup.select('input[type~="word1 word2" i]') #9. ~= 属性值包含 多个单词,i是伪类选择器忽略大小写
tag = soup.select('#parent > .child[class="target"]') #10. 特定父元素下,具有特定属性的直接子元素
tag = soup.select('input[type="text"] + label') #11.特定属性元素后,紧接的<label>兄弟元素
6、 后代选择器:空格
后代选择器,可以跨越层级选择后代,无论它们之间有多少层嵌套。
如果想要指定嵌套内的层级,可以使用多个“ ”空格符
链式使用,指定特定层级的元素。
#**********假设HTML文档**********
html_doc ='''
<div class="row">
<div class="col-3">
<a href="/index.php/serial/1">
<img src="http://img.qichedaquan.com/a.png" width="100%">
<p class="text-center"> 奥迪A3 </p>
</a>
</div>
<div class="col-3">
<a href="/index.php/serial/2">
<img src="http://img.qichedaquan.com/b.png" width="100%">
<p class="text-center"> 奥迪A4 </p>
</a>
</div>
</div>
'''
soup = BeautifulSoup(html_doc, "html.parser")
tag = soup.select('.row a') #跨越层级,获取.row类下的所有<a>标签
tag = soup.select('.row .col-3 a[href]') #层层指定,获取具有href属性的<a>标签。与第一句效果一样
tag = soup.select('.col-3 *') #获取.col-3类下的所有后代元素
后代选择器示例,打印结果:
- [<a href="/index.php/serial/1">
<img src="http://img.qichedaquan.com/a.png" width="100%"/>
<p class="text-center"> 奥迪A3 </p>
</a>, <a href="/index.php/serial/2">
<img src="http://img.qichedaquan.com/b.png" width="100%"/>
<p class="text-center"> 奥迪A4 </p>
</a>] - [<a href="/index.php/serial/1">
<img src="http://img.qichedaquan.com/a.png" width="100%"/>
<p class="text-center"> 奥迪A3 </p>
</a>, <a href="/index.php/serial/2">
<img src="http://img.qichedaquan.com/b.png" width="100%"/>
<p class="text-center"> 奥迪A4 </p>
</a>] - [<a href="/index.php/serial/1">
<img src="http://img.qichedaquan.com/a.png" width="100%"/>
<p class="text-center"> 奥迪A3 </p>
</a>, <img src="http://img.qichedaquan.com/a.png" width="100%"/>, <p class="text-center"> 奥迪A3 </p>, <a href="/index.php/serial/2">
<img src="http://img.qichedaquan.com/b.png" width="100%"/>
<p class="text-center"> 奥迪A4 </p>
</a>, <img src="http://img.qichedaquan.com/b.png" width="100%"/>, <p class="text-center"> 奥迪A4 </p>]
tag_list = soup.select('.row a')
for tag in tag_list:
print(tag.get('href')) #获取<a>标签的href属性值
print(tag.find('img').get('src')) #获取<a>标签下,第一个<img>标签的src属性值
p_tag=tag.find('p') #获取<a>标签下,第一个<p>标签
if p_tag is not None: #<p>标签不存在会报错,增加非空判断
print(p_tag.get_text().strip()) #<p>标签存在,get_text()获取文本,strip()去除空格,打印 “奥迪A3”
else:
print("<p> tag not found!")
获取属性值示例,打印结果:
/index.php/serial/1
http://img.qichedaquan.com/a.png
奥迪A3
/index.php/serial/2
http://img.qichedaquan.com/b.png
奥迪A4
7、 子选择器(直接后代):>
子选择器,只匹配指定父元素下符合条件的全部直接子级(不需要与父节点相邻)。不包含孙级或更深层次的后代。
如果想要精确指定层级,可以使用多个>
嵌套使用,指定特定层级的元素。
#********** 假设HTML文档 **********
html_doc ='''
<div class="parent">
<span>I am a span</span>
<div class="child">
<div class="child">I am 1st .child</div>
</div>
<div class="child">
<div class="child">I am 2nd .child</div>
</div>
</div>
'''
soup = BeautifulSoup(html_doc, "lxml")
tag = soup.select('.parent>.child') #选择.parent的直接.child后代,不包括孙级子元素
tag = soup.select('.parent>.child>.child') #选择.parent直接.child后代的,直接.child子元素
tag = soup.select('.parent .child') #选择.parent的所有.child后代,包括孙级子元素
打印结果:
①[<div class="child">
<div class="child">I am 1st .child</div>
</div>, <div class="child">
<div class="child">I am 2nd .child</div>
</div>]
②[<div class="child">I am 1st .child</div>, <div class="child">I am 2nd .child</div>]
③[<div class="child">
<div class="child">I am 1st .child</div>
</div>, <div class="child">I am 1st .child</div>, <div class="child">
<div class="child">I am 2nd .child</div>
</div>, <div class="child">I am 2nd .child</div>]
8、 兄弟选择器(直接相邻/通用):+或~
兄弟选择器,只会选择在指定元素之后,符合条件的同级元素。
- 相邻兄弟选择器
+
:选择指定元素之后,符合条件的直接相邻
同级元素。 - 通用兄弟选择器
~
:选择指定元素之后,符合条件的全部
同级元素。
#********** 假设HTML文档 **********
html_doc ='''
<div class="parent">
<div class="child">
<div class="child">I am 1st .child</div>
<div class="child">I am 2nd .child</div>
<p class="child">I am 3rd .child</p>
<span>I am a span</span>
<div class="child">I am the 4th .child</div>
</div>
</div>
'''
soup = BeautifulSoup(html_doc, "lxml")
tag = soup.select('p+.child') #获取<p>标签之后,且与之相邻的.child兄弟元素
tag = soup.select('p~.child') #获取<p>标签之后的所有.child兄弟元素
tag = soup.select('.child+.child') #获取.child之后,且与之相邻的.child兄弟元素
tag = soup.select('.child~.child') #获取.child之后的所有.child兄弟元素
tag = soup.select('.child+*') #获取.child之后,且与之相邻的所有兄弟元素(4th不与.child相邻)
tag = soup.select('.child~*') #获取.child之后的所有兄弟元素
tag = soup.select('.child+.child+.child+*') #获取.child+.child+.child之后,且与之相邻的所有兄弟元素
tag = soup.select('.child~.child~.child~*') #获取.child~.child~.child之后的所有兄弟元素
打印结果:
①[]
②[<div class="child">I am the 4th .child</div>]
③[<div class="child">I am 2nd .child</div>, <p class="child">I am 3rd .child</p>]
④[<div class="child">I am 2nd .child</div>, <p class="child">I am 3rd .child</p>, <div class="child">I am the 4th .child</div>]
⑤[<div class="child">I am 2nd .child</div>, <p class="child">I am 3rd .child</p>, <span>I am a span</span>]
⑥[<div class="child">I am 2nd .child</div>, <p class="child">I am 3rd .child</p>, <span>I am a span</span>, <div class="child">I am the 4th .child</div>]
⑦[<span>I am a span</span>]
⑧[<span>I am a span</span>, <div class="child">I am the 4th .child</div>]
9、 伪类选择器::符号
伪类选择器在CSS中用于根据元素的特定状态或行为选择元素,而不是根据它们的类型、类或ID。BeautifulSoup当前支持的 CSS 选择器,请查阅官方文档:CSS 伪类选择器
tag = soup.select('ul > li:first-child') # 选择每个<ul>的第一个<li>元素
tag = soup.select('ul li:nth-child(2)') # 选择每组的第二个<li>元素
tag = soup.select('div > p:nth-of-type(3)') # 选择每组的第三个<p>元素
tag = soup.select('p:not(.highlight)') # 选择不是.highlight类的<p>元素
tag = soup.select('div:has(a)') # 选择包含<a>元素的<div>元素
tag = soup.select('input:checked') # 选择被选中的<input>元素
tag = soup.select('input:enabled') # 选择可用的<input>元素
tag = soup.select('div:empty') # 选择没有子元素的<div>元素
二、选择器列表
CSS选择器可以返回一个列表,你可以遍历这个列表来处理每个元素:
for p in tag_list:
print(p.text)
三、获取属性的值
1. 使用.get()方法:
.get()
方法可以用来安全地获取属性值,如果属性不存在,它将返回None而不是抛出异常:
#获取img标签src的值
img=parent.select_one("img").get('src')
2.使用.attrs字典:
.attrs
属性是一个字典,它包含元素的所有属性。用来遍历全部属性,或获取特定的属性值:
#先获取tag标签的attrs属性字典,再取属性src的值
img=parent.select_one("img").attrs.get('src')
3. 不推荐“.
”直接访问属性:
如果属性名是Python的关键字,或者包含特殊字符(如冒号“:”),点操作符可能不起作用。使用.get()方法可以避免属性名中的特殊字符带来的问题。
img=parent.select_one("img")['src'] #打印结果正确
img=parent.select_one("img").src #使用.操作符未获取到src属性,打印结果是None