Selenium可以驱动浏览器完成各种操作,比如模拟点击等。要想操作一个元素,首先应该识别这个元素。人有各种的特征(属性),我们可以通过其特征找到人,如通过身份证号、姓名、家庭住址。同理,一个元素会有各种的特征(属性),我们可以通过这个属性找到这对象。
目录
2.9.2 find_element和find_elements方法
元素:由标签头 + 标签尾 + 标签头和标签尾包括的文本内容;
元素的信息就是指元素的标签名及元素的属性;
元素的层级结构就是指元素之间相互嵌套的层级结构;
元素定位最终就是通过元素的信息或者元素的层级结构来进行元素定位;
在谷歌浏览器中,选中元素,右键点击“检查”,即可在“Elements"中查看元素信息。
以百度首页搜索框为例,查看元素信息如下图所示:

image-20220511102134911

image-20220510192728208
webdriver 提供了一系列的对象定位方法,常用的有以下8种:
| 定位一个元素 | 定位多个元素 | 含义 |
|---|---|---|
| find_element_by_id | find_elements_by_id | 通过元素id定位 |
| find_element_by_name | find_elements_by_name | 通过元素name定位 |
| find_element_by_xpath | find_elements_by_xpath | 通过xpath表达式定位 |
| find_element_by_link_text | find_elements_by_link_text | 通过完整超链接定位 |
| find_element_by_partial_link_text | find_elements_by_partial_link_text | 通过部分链接定位 |
| find_element_by_tag_name | find_elements_by_tag_name | 通过标签定位 |
| find_element_by_class_name | find_elements_by_class_name | 通过类名进行定位 |
| find_element_by_css_selector | find_elements_by_css_selector | 通过css选择器进行定位 |
我们创建浏览器对象并访问百度首页,以百度首页为例,讲解如何定位元素。
from selenium import webdriver
web = webdriver.Chrome()
web.get(r'https://www.baidu.com')
在HTML当中,id属性是唯一标识一个元素的属性,因此在selenium当中,通过id来进行元素的定位也作为首选。
百度搜索框的元素如图所示:

image-20220510192728208
百度搜索框元素html结构:
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
元素定位:
element = web.find_element_by_id("kw")
在HTML当中,name属性和id属性的功能基本相同,只是name属性并不是唯一的,如果遇到没有id标签的时候,我们可以考虑通过name标签来进行定位。
百度搜索框元素html结构:
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
元素定位:
element = web.find_element_by_name("wd")
我们也可以基于class属性来定位元素。通常当我们看到有多个并列的元素如list表单,class用的都是共用同一个。
百度搜索框元素html结构:
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
元素定位:
element = web.find_element_by_class_name('s_ipt')
若class的值中有空格,则需要借助CSS Selector处理。
HTML是通过tag来定义一类功能的,比如input是输入,table是表格,tbody是表格主体等。每个元素其实就是一个tag,由于一个tag用来定义一类功能,一个网页往往有很多同类tag,所以很难通过tag去区分不同的元素。

image-20220510193305826
百度搜索框元素html结构:
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
元素定位:
element = web.find_element_by_tag_name('input')
由于百度首页有很多标签名字都是”input",因此上述代码只会定位到网页的第一个“input”标签。
通过超链接的文本定位元素。
百度上方超链接”新闻“元素如图所示:

image-20220510195131010
百度上方超链接”新闻“元素元素html结构:
<a href="http://news.baidu.com" target="_blank" class="mnav c-font-normal c-color-t">新闻</a>
元素定位:
element = web.find_element_by_link_text('新闻')
有时候一个超链接的文本很长,我们如果全部输入,既麻烦,又显得代码很不美观,这时候我们就可以只截取一部分字符串,进行模糊匹配。
百度上方超链接”新闻“元素html结构:
<a href="http://news.baidu.com" target="_blank" class="mnav c-font-normal c-color-t">新闻</a>
元素定位:
element = web.find_element_by_partial_link_text('闻')
Xpath是一种在XML和HTML文档中查找信息的语言,通过Xpath路径来定位元素的时候也是分绝对路径和相对路径。
当我们想要描述某个地方时,我们常常用不同层次的节点名称串联起来,比如:你的收货地址是"江西省-南昌市-青山湖区-xx小区"。类似地,我们想要定位XML文档中某个节点时,也是这么层层递进。
绝对路径:表示页面元素在网页的HTML代码结构中,从根节点一层层地搜索到需要被定位的页面元素,绝对路径起始于正斜杠(/),每一步均被斜杠分割。
以百度搜索框元素为例,鼠标单机右键-Copy-Copy full XPath即可获取其XPath绝对路径

image-20220510211910536
xpath定位表达式:
/html/body/div[1]/div[2]/div[5]/div[1]/div/form/span[1]/input
Python通过xpath定位语句:
element = web.find_element_by_xpath('/html/body/div[1]/div[2]/div[5]/div[1]/div/form/span[1]/input')
上述xpath定位表达式从html dom树的根节点(html节点)开始逐层查找,最后定位到“input”节点。
特点:路径唯一,但是容易受页面改动影响,即便页面代码结构只发生了微小的变化,也可能会造成原先有效的xpath定位表达式定位失败
相对路径:从匹配选择的当前节点开始选择文档中的节点,而不考虑它们的位置,起始于双斜杠(//)。
以百度搜索框元素为例,鼠标单机右键-Copy-Copy XPath即可获取其XPath相对路径

image-20220510211834245
xpath定位表达式:
//*[@id="kw"]
Python通过xpath定位语句:
element = web.find_element_by_xpath('//*[@id="kw"]')
相对路径的xpath定位表达式更加简洁,推荐使用相对路径的xpath表达式。
在Selenium官网当中是更加推荐Css Selector()方法来进行页面元素的定位的,Css定位可以通过id选择器、class选择器、标签选择器和属性选择器。
通过 # 来定义,通过元素的id属性来定位
百度搜索框元素html结构:
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
元素定位:
element = web.find_element_by_css_selector("#kw")
通过 .来定义,通过元素的class属性来定位
百度搜索框元素html结构:
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
元素定位:
element = web.find_element_by_css_selector(".s_ipt")
通过标签的名字来定位元素
百度搜索框元素html结构:
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
元素定位:
element = web.find_element_by_css_selector("input")
根据标签中的属性来定位元素, 格式: [属性名=”属性值”],或标签名[属性名=属性值]。如果属性是唯一的,那么标签名可以不用写。
百度搜索框元素html结构:
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
元素定位:
element = web.find_element_by_css_selector('[id="kw"]')
element = web.find_element_by_css_selector('input[id="kw"]')
2.8.4.1 定位带空格的复合class属性
定位带空格的复合class属性一般采用css selector定位方法。
以百度上方栏目元素为例,其class属性带有空格。
class="s-top-left-new s-isindex-wrap"

image-20220511115348420
class属性带空格,如果直接通过class属性定位是会报错的,需要通过css selector按class属性定位。
element=web.find_element_by_class_name('s-top-left-new s-isindex-wrap')
直接通过class属性定位是会报错的。
no such element: Unable to locate element: {"method":"css selector","selector":".s-top-left-new s-isindex-wrap"}
(Session info: chrome=99.0.4844.51)
通过css selector按class属性定位,代码如下:
element=web.find_element_by_css_selector('[class="s-top-left-new s-isindex-wrap"]')
css selector可以直接在浏览器中复制,鼠标单机右键-Copy-Copy selector即可获取。

image-20220511102825357
• 当页面元素有id属性时,尽量用id来定位;
• 当有链接需要定位时,可以考虑link text或partial link text方式;
• 当要定位一组元素相同元素时,可以考虑用tag name或class name;
• css selector定位速度比较快,效率高。
• 一般id>name>css>XPath
| find_element_by_xx | find_elements_by_xx | |
|---|---|---|
| 没有匹配到元素 | 执行报错 | 返回空列表 |
| 匹配到一个元素 | 返回元素 | 返回包含一个元素的列表 |
| 匹配到多个元素 | 返回第一个元素 | 返回包含所有匹配元素列表 |
除了上述的8种定位方法,Selenium还提供了一个通用的方法find_element()和find_elements(),这个方法有两个参数:定位方式和定位值。
使用的时候需要导入By模块
from selenium.webdriver.common.by import By
以定位一个元素为例,两种定位方法写法差异如下:
| 定位元素 | find_element_by_* | find_element() |
|---|---|---|
| 通过元素id定位 | find_element_by_id(x) | find_element(By.ID,x) |
| 通过元素name定位 | find_element_by_name(x) | find_element(By.NAME,x) |
| 通过xpath表达式定位 | find_element_by_xpath(x) | find_element(By.XPATH,x) |
| 通过完整超链接定位 | find_element_by_link_text(x) | find_element(By.LINK_TEXT,x) |
| 通过部分链接定位 | find_element_by_partial_link_text(x) | find_element(By.PARTIAL_LINK_TEXT,x) |
| 通过标签定位 | find_element_by_tag_name(x) | find_element(By.TAG_NAME,x) |
| 通过类名进行定位 | find_element_by_class_name(x) | find_element(By.CLASS_NAME,x) |
| 通过css选择器进行定位 | find_element_by_css_selector(x) | find_element(By.CSS_SELECTOR,x) |
定位多个元素,就是把上述element后面多了复数标识s,变为elements,其他操作一致。
以上的操作可以等同于以下:
from selenium.webdriver.common.by import By
element = web.find_element(By.ID,'kw')
element = web.find_element(By.NAME,'wd')
element = web.find_element(By.CLASS_NAME,'s_ipt')
element = web.find_element(By.TAG_NAME,'input')
element = web.find_element(By.LINK_TEXT,'新闻')
element = web.find_element(By.PARTIAL_LINK_TEXT,'闻')
element = web.find_element(By.XPATH,'//*[@id="kw"]')
element = web.find_element(By.CSS_SELECTOR,'#kw')
element = web.find_element(By.CSS_SELECTOR,'[id="kw"]')
element = web.find_element(By.CSS_SELECTOR,'input[id="kw"]')
目前,由于selenium版本升级,使用find_element_by_*,会提示弃用警告,建议使用find_element()。
DeprecationWarning: find_element_by_* commands are deprecated. Please use find_element()
警告错误提示不会影响代码的执行,可以忽略。
如果需要彻底解决,可以指定安装低版本的selenium,如安装3.3.0版本,Anaconda Prompt命令行输入:
pip install selenium==3.3.0
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)