Selenium css选择元素,元素验证

3.4 通过CSS选择器选择

W3CCSS是定义HTML页面样式的语言。它决定页面元素显示的效果,比如一段文本的字体,大小,间距等等。当然,要修饰一个元素,首先它也要指定修饰的是哪个元素。所以CSS规范里面定义一种选择页面元素的语法。正好Selenium可以用它来定位页面元素。CSS选择器就是这种语法的使用。CSS选择器选择功能强大,不仅可以通过上述的属性选择,还可以根据元素的父子兄弟关系,子元素的顺序,其他的任意元素属性的有无或者属性值,输入焦点,等等。总之非常的强大,特别适用于上面方法都不好定位的时候使用。假如有如下的html片段。

  • 根据 tag 名 选择
p {color: red;} #表示选择所有的 p 元素 
  • 根据 id ,前面加个#号
#food {color: blue;} #表示选择ID为 food的 元素 
  • 3.根据class 选择,前面加个“.”
.special  {color: red;}#表示选择class为 special 的 元素 ,

注意有的元素有两个class 值:

<span class="vegetable good">黄瓜</span>

我们可以看到这个calss中间有一个空格,他不是整体是一个class而是说这个元素有两个class属性,是vegetablegood我们可以这样写:

.good  {color: red;}#表示选择class为 good 的所有 元素 
.vegetable {color: blue;} #表示选择所有的 class为 vegetable所有 的元素 

如果要选择class属性同时具有vegetablegood 的,可以这样:

.vegetable.good

假如有如下的html片段:

<div id="food" style="margin-top:10px;color:red">
    <span class="vegetable good">黄瓜</span>
    <span class="meat">牛肉</span>
    <p class="vegetable">南瓜</p>
    <p class="vegetable">青菜</p>
</div>

<div id="food2" style="margin-top:10px">
    <span class="vegetable">黄瓜2</span>
    <span class="meat">牛肉3</span>
</div>

<select id="choose_car">
    <option value="volvo">沃尔沃</option>
    <option value="corolla">卡罗拉</option>
    <option value="fiat">菲亚特</option>
    <option value="audi">奥迪</option>
</select>

通过css选择的方式如下:

  • 根据tag名,选中第一个span节点
find_element_by_css_selector('span')

选中所有的span节点

find_elements_by_css_selector('span')
  • 根据id名
#选中所有id为food2的节点
find_elements_by_css_selector('#food2')

根据class

#选中所有class属性为vegetable的节点
find_elements_by_css_selector('.vegetable')

讲到这里大家会想这些根据id,class,tag去找元素我们之前不是说过吗,比如find_elements_by_id()、find_elements_by_class_name()这只是我们已前知识的另一种用法而已,我们为什么要学它呢?这里就介绍它的强大之处,它有后代选择的能力。

比如大家看这个表达式:

#food p

中间有个空格,刚才有说到空格在css里面不能乱加有特殊的含义,这个空格就是你要找的节点,注意一定是找空格最后一个节点,就是p节点,空格前面是这个节点的上层节点的特性,这个表达式我们可以这样理解:我们要找一个标签名是p的,然后这个标签有一个限制,他是在idfood 元素的内部 ,我们要找idfood 里面的所有p,空格就是后代的意思。

看一个例子:

div span

就是查找所有 div 元素 里面的 span 元素。

发现spandiv的直接子元素, 就算不是直接子元素也可以,只要是内部的就一样可以。


3.4.1子元素选择

前面我们学习了后代选择器,比如后代选择器:#choose_car option。选择 id choose_car 的所有 option子元素,不管它们是否是直接子节点。如果您希望缩小范围,只选择某个元素的直接子节点元素,请使用子元素选择器(Child selector)。

  • 子元(child)选择器
    选择元素的子元素,和后代选择器不同(#food p )比如:
#choose_car > option 大于号表示你最终要选择的option 元素是前面的这个元素的直接子节点
  • 可以是很多级
ul > ol > li > em

方法是可以混合使用的比如div li > #abc这个表达式意思就是div里面tag名为liidabc的直接子元素。

3.4.2 组(group)选择

组选择 同时选择多个元素,逗号隔开,语法:

语法 <s1>,<s2>

比如:
p,button 选择所有的p元素和所有的button元素
#food , .cheese 选择所有idfood的元素和classcheese的元素。

选择 idfood的所有span子元素 和 所有的p(包括非food的子元素)逗号的优先级要比后代的优先级低,逗号是最后算的。

#food > span,p

选择 idfood的 所有span子元素 和 idfood的 所有的p元素:

#food > span ,#food > p

可以这样选择idfood的的所有子元素:

#food > *

*代表所有元素的意思

p buttonp ,button大家能区分清楚吗,p button意思是p元素里面所有的button元素,p ,button意思是所有的p和所有的button

selenium也可以用这样的语法:

eles = driver.find_elements_by_css_selector('p, button')

3.4.3 兄弟节点选择

我们说过了 后代元素选择、子元素选择,现在我们说下相邻兄弟选择器。下面有这样一段html

<div id="food2" style="margin-top:10px">
    <span class="vegetable">黄瓜2</span>
    <span class="meat">牛肉3</span>
</div>

<select id="choose_car">
    <option value="volvo">沃尔沃</option>
    <option value="corolla">卡罗拉</option>
    <option value="fiat">菲亚特</option>
    <option value="audi">奥迪</option>
</select>

选择紧接在另一个元素后的元素,而且二者有相同的父元素。注意:两个条件 紧接在后面、相同父元素 .这个表达式就是找到idfood2紧跟着的兄弟节点select节点:

#food2 + select 

如果我们想选择的 只是在另一个元素后的兄弟元素,不一定要紧挨着,二者有相同的父元素 ,用下面的语法。

#food2 ~ select 

大家注意“+”“~”都是选择后面的元素,#food + div 表示idfood的紧跟着的div,#food ~ div不一定要紧接着,我们可以联合其他语法使用,比如:

#many > div > p.special + p

选择 #many 的子元素 div 里面的 子元素 p (类型为special) 的后面的兄弟节点。最后选中的元素是:

image.png

3.4.4 属性选择

比如:选择所有具有style属性的元素

*[style]

又比如:选择P节点具有spec值为 len2 的元素,加引号一般用在 属性值中间有空格的情况,如果没有空格可以不加引号。这里有个特别要注意的地方,属性选择必须要完全一样

p[spec='len2']

看下面的截图,标红的部分是不会被选中的。

image.png

属性选择还有一种写法,如果要选择只要spec属性包含len2的就被选择那要怎么写呢,在“=”前面加个“*”号就可以

p[spec*='len2']
或者
a[href*="baidu.com"]

len2开头的:

p[spec^='len2']

len2结尾的:

p[spec$='len2']

同时满足两种属性的:

p[class=special][name=p1] 

CSS选择器有很多的语法, 详细的大家可以参考 这里http://www.w3school.com.cn/cssref/css_selectors.asp

我们css选择器还有一种常用的方法:nth-child(n)比如p:nth-child(2)意思是首先选择所有的p节点,冒号表示一个限定,就是p必须是父元素的第二个子元素,这就是nth-child(2),注意不是说第二个p类型的子元素而就是第二个p元素比我我们看个例子:


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>定位网页元素</title>

<style>
    #choose_car option {color: blue;}
</style>

</head>

<body>
    <div style="">
      <h3>This is a heading</h3>
      <p>This is a paragraph.</p>
    </div>

    <button name='button'>按钮1</button>
    <button name='button'>按钮2</button>

    <div class="cheese"><span>Cheddar</span></div>
    <div class="cheese"><span>Gouda</span></div>

    <a href="http://www.163.com" id="baidulink">转到百度</a>

    <div id="food" style="margin-top:10px;color:red">
        <span class="vegetable good">黄瓜</span>
        <span class="meat">牛肉</span>
        <p class="vegetable">南瓜</p>
        <p class="vegetable">青菜</p>
    </div>

    <div id="food2" style="margin-top:10px">
        <span class="vegetable">黄瓜2</span>
        <span class="meat">牛肉3</span>
    </div>

    <select id="choose_car">
        <option value="volvo">沃尔沃</option>
        <option value="corolla">卡罗拉</option>
        <option value="fiat">菲亚特</option>
        <option value="audi">奥迪</option>
    </select>

    <footer>
        <div>
            <p>test1</p>
        </div>
    </footer>

    <p>test2</p>
    <div id="many">
        <div>
            <p class="special" name="p1">one</p>
            <p>two</p>
            <p class="special3">three</p>
        </div>
    </div>

    <p spec="len">test3</p>
    <p spec="len2">test4</p>
    <p spec="len2 len3">test5</p>


</body>
</html>

id等于food的下面有几个p元素,是不是2个?

#food > p:nth-child(2)

这个表达式是什么意思呢?属于其父元素的第二个子元素,并且要是p ,我们这里第二个子元素是span,所以上面这个表达式是找不到的。

比如:

#food > p:nth-child(3)

这个表达式的意思是,属于其父元素的第3个子元素,并且要是p,这就可以找到。这是正数第3个我们还可以倒数nth-last-child(n),还有一种按照类型排序的方法nth-of-type()p:nth-of-type()p:nth-child()区别是:p:nth-child(2)必须是父节点的第二个子节点,p:nth-of-type(2)第二个p类型的子节点。

比如:属于其父元素的倒数第二个子元素,并且是p

#food > p:nth-last-child(2) 

找到的是:


image.png

比如:属于其父元素的第二个p 类型的子元素

#food > p:nth-of-type(2) 

找到的是:


image.png

比如:属于其父元素的倒数第二个p 类型的子元素

#food > p:nth-last-of-type(2)

找到的是:


image.png

还有一种选择元素的方式:not(p),选择非 <p> 元素的每个元素。

比如:

#food > :not(p)

找到的是:


image.png

3.4.5 利用浏览器开发工具获取 css seletor

对于不太好找的CSS selector的元素,我们可以通过浏览器开发工具帮助我们定位。在chrom浏览器里,按F12,打开开发工具窗口,点击element标签,然后,在网页窗口里面 点选我们要 选择的元素,开发工具窗口会高亮显示该元素对应的html tag代码。这时,我们可以 用鼠标右键 点击该代码,在弹出的对话框中,依次选择Copy --> Copy selector,如下图所示,这样,该元素的CSS selector就被拷贝到剪贴板了。

image.png

3.4.6 验证css表达式

当我们要写的自动化脚本比较复杂的时候,每次到python代码中调试CSS选择器(看看我们的css选择器是否能选中元素)会非常的麻烦。因为很慢,我们可以利用浏览器的开发工具,直接在浏览器中进行测试,看看我们写的CSS选择器是否能正确找到我们要的web元素。

两种方法, 一种是chrome浏览器,按F12,打开开发窗口,点击元素标签(英文叫Element),按contrl + f,直接输入css选择器即可。选中的元素会高亮显示。

image.png

这种方法优点, 填入内容完全就是 css 选择器, 缺点: 也会做 字符匹配, 让人有点迷糊。

另一种是:
chrome浏览器,按F12,打开开发窗口,点击控制台标签(英文叫console),在里面执行$$(‘css selector’),其中css selector 就是css选择器字符串。chrom界面如下所示:

image.png

如果能找到对象,返回的结果就不是空数组,就表示能找到web元素。而且鼠标放在数组元素上,会高亮显示对应的web元素。这种方法 优点, 不会做 字符串匹配, 很清晰。缺点: 要多输入点内容。

下面是一次作业,可以用今天讲的知识做一下
登录 51job:http://www.51job.com
输入搜索关键词 "python", 地区选择 "杭州"(注意,如果所在地已经选中其他地区,要去掉),搜索最新发布的职位, 抓取页面信息。 得到如下的格式化信息:
Python开发工程师 | 杭州纳帕科技有限公司 | 杭州 | 0.8-1.6万/月 | 04-27
Python高级开发工程师 | 中浙信科技咨询有限公司 | 杭州 | 1-1.5万/月 | 04-27
高级Python开发工程师 | 杭州新思维计算机有限公司 | 杭州-西湖区 | 1-1.5万/月 | 04-27

解析:这里面就只有一个难点,怎么只保证选择 杭州 呢,我们可以定位一下选中的元素有什么特征,我们发现 class="on" 就是选中,如果不选中就没有class="on" 的值,确保只有杭州是选中的,这里要综合使用 pythonSelenium 的知识,我们可以先把所有的城市过一遍,如果他是杭州 class值不等于 on 我们就 click 一下,如果选中了就不动他,如果是其他城市是反之,选中了就 click 下没选中就不管它。

#从selenium里面导入webdriver
from selenium import webdriver

#指定chrom的驱动
#执行到这里的时候Selenium会到指定的路径将chrome driver程序运行起来
driver = webdriver.Chrome('E:\ChromDriver\chromdriver2.43\chromedriver.exe')
driver.implicitly_wait(10)

driver.get('https://www.51job.com/')
#根据id找到输入框,输入python
driver.find_element_by_id('kwdselectid').send_keys('python')
#点击工作地点
driver.find_element_by_id('work_position_input').click()

import time
time.sleep(2)

#用css方法找到所有的城市
cityEles = driver.find_elements_by_css_selector('#work_position_click_center_right_list_000000 em')

#遍历元素,一个个城市去找
for one in cityEles:
    #城市名
    cityname = one.text
    #用之前学过的attribute方法获取class的值
    cassvalue = one.get_attribute('class')
    #
    if cityname == '杭州':
        if cassvalue != 'on':
            one.click()
    elif cityname != '杭州':
        if cassvalue == 'on':
            one.click()
#点击确定按钮
driver.find_element_by_id('work_position_click_bottom_save').click()
#点击搜索按钮
driver.find_element_by_css_selector('div.ush.top_wrap button').click()
#找职位
jobs = driver.find_elements_by_css_selector('#resultList div.el')

for job in jobs[1:]:
    #span是一个列表
    spans = job.find_elements_by_tag_name('span')
    #列表生成式
    fields = [span.text for span in spans]
    print(fields)

#退出
driver.quit()

代码里为什么有 sleep?我们执行到 cityEles = driver.find_elements_by_css_selector('#work_position_click_center_right_list_000000 em') 的时候其实界面不是一下子呈现出来的,导致我们去找 em 的时候状态没来的急更新,有没有选中是动态更新的,他在定位城市的时候前端的 js 动态的获取了一些信息,然后再把这些城市有没有选中呈现出来,这样就导致了当前获取的东西并不是过了一段时间后更新的状态,就是不是稳定的状态,之前一个临时的状态,这里我们就得 sleep 等待一下,有人会有疑问不是有 implicitly_wait 吗,implicitly_wait 是找不到才会等待这里是可以找到 em ,只是这里过了一段时间才刷新的,大家可以好好看下这段代码。

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

推荐阅读更多精彩内容

  • 1.class 和 id 的使用场景? 两者都能选取DOM节点并给DOM节点添加样式,但是W3C标准里规定页面中只...
    饥人谷_米弥轮阅读 386评论 0 1
  • class 和 id 的使用场景? class属性: 指定标签的类名,CSS操作中,把一些特定的样式放到一个类中,...
    我要认真学前端阅读 1,004评论 0 0
  • id与class的使用场景 id选择器,匹配特定id的元素类选择器,匹配class包含(不是等于)特定类的元素id...
    姚小帅阅读 311评论 0 0
  • 一、CSS选择器常见的有几种? 基本选择器 通配选择器~选择文档中所有的html元素,用一个*表示 元素选择器~选...
    dengpan阅读 959评论 0 3
  • 其实平时用得多的选择器无非也就是那么几个,时间久了,许多不常用的选择器就慢慢忘记了。为了不让自己忘记这些选择器,今...
    盛夏晚清风阅读 1,810评论 0 5