【Python】CSS选择器九种用法

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类下的所有后代元素

后代选择器示例,打印结果:

  1. [<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>]
  2. [<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>]
  3. [<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、 兄弟选择器(直接相邻/通用):+或~

兄弟选择器,只会选择在指定元素之后,符合条件的同级元素。

  1. 相邻兄弟选择器+:选择指定元素之后,符合条件的 直接相邻 同级元素。
  2. 通用兄弟选择器~:选择指定元素之后,符合条件的 全部 同级元素。
#********** 假设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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341