Selenium定位元素

Selenium提供多种find_element_by 方法用于定位页面元素。这些方法根据一定的标准去查找元素,如果元素被正常定位,那么WebElement实例将返回。反之,将抛出NoSuchElementException的异常。同时,Selenium还提供多种find_elements_by 方法去定位多个元素,这类方法根据所匹配的值,搜索并返回一个list数组(元素)。

Selenium提供8种find_element_by 方法用于定位元素。接下来的部分,我们将逐一介绍方法细节,如下表所示。

find_element_by 方法
方  法 描  述 参  数 示  例
ind_element_by_id(id) 通过元素的ID属性值来定位元素 id:元素的ID driver.find_element_by_id('search')
find_element_by_name(name) 通过元素的name属性值来定位元素 name:元素的name driver.find_element_by_name('q')
find_element_by_class_name(name) 通过元素的class名来定位元素 name:元素的类名 driver.find_element_by_class_name('input-text')
find_element_by_tag_name(name) 通过元素的tag name来定位元素 name:tag name driver.find_element_by_tag_name('input')
find_element_by_xpath(xpath) 通过XPath来定位元素 XPath:元素的XPath driver.find_element_by_xpath('//form[0]/div[0]/input[0]')
find_element_by_css_selector(css_selector) 通过CSS选择器来定位一组元素 css_selector:元素的CSS选择器 driver.find_element_by_css_selector('#search')
find_element_by_link_text(link_text) 通过元素标签对之间的文本信息来定位一组元素 link_text:文本信息 driver.find_element_by_link_text('Log In')
find_element_by_partial_link_text(link_text) 通过元素标签对之间的部分文本信息来定位一组元素 link_text:部分文本信息 driver.find_element_by_partial_link_text('Log')

通过ID查找元素是查找页面上元素的最佳方法。

find_element_by_id()和find_elements_by_id()方法返回与ID属性值匹配的一个元素或一组元素。
find_element_by_id()方法返回的是与ID属性值匹配的第一元素,如果没有元素与之匹配,则抛出NoSuchElementException异常。

如下图所示,我们尝试来定位搜索框。

通过查看HTML,我们可以看到搜索框的ID值被定义为search。

<input id="search" type="text" name="q" value="" 
 class="input-text" maxlength="128" autocomplete="off">

接下来我们使用find_element_by_id() 方法,id值为search来定位搜索框,同时检查maxlength的属性值。

def test_search_text_field_max_length(self):
 # get the search textbox
 search_field = self.driver.find_element_by_id("search")

 # check maxlength attribute is set to 128 
 self.assertEqual("128", search_field.get_attribute("maxlength"))

此外,如果使用find_elements_by_id() 方法,那么将返回匹配ID值的所有元素。

name定位 通过name定位是另外一个常用的查找元素的方式。

find_element_by_name() 和 find_elements_by_name()方法可以通过匹配name值来定位单个或一组元素。同样,name值匹配成功可返回定位的元素;反之,则抛出NoSuchElementException的异常。

回到之前的例子,我们可以用匹配name属性值的方式来替换ID值的匹配,同样可以定位到搜索框。

# get the search textbox
self.search_field = self.driver.find_element_by_name("q")

此外,如果使用find_elements_by_name() 方法,那么将返回匹配name值的所有元素。

class定位 除了使用ID和name属性,我们还可通过class属性来定位元素。class用来关联CSS中定义的属性。

find_element_by_class_name()和find_elements_by_class_name()方法可以通过匹配class属性来定位单个或一组元素。同样,class值匹配成功可返回定位的元素;反之,则抛出NoSuchElementException的异常。

通过对元素ID、name和class属性来查找元素是最为普遍和快捷的方法。此外,Selenium WebDriver还提供了其他一些方法用于定位元素,在接下来的段落中会有详细介绍。

我们可以尝试用find_element_by_class_name() 的方法来定位元素。

搜索按钮在HTML中是用<button>标签(元素)以及对应的class属性与属性值定义的,具体如下。

<button type="submit" title="Search"
 class="button"><span><span>Search</span></span></button>

下面我们用class属性值来定位搜索按钮,代码如下。

def test_search_button_enabled(self):
  # get Search button
  search_button = self.driver.find_element_by_class_name 
   ("button")

  # check Search button is enabled 
  self.assertTrue(search_button.is_enabled())

此外,如果使用find_elements_by_class_name() 方法,那么将返回匹配class属性值的所有元素。

tag定位

find_element_by_tag_name()和find_elements_by_tag_name() 方法是通过对HTML页面中tag name匹配的方式来定位元素的。这些方法跟JavaScript中的DOM方法getElementsBy TagName()类似。同样,通过成功匹配tag name可以返回定位的元素;反之,则抛出NoSuchElementException的异常。

这个方法在某些特定的场景下格外有用,例如,我们可以通过<tr> 的tag name一次定位页面的table中所有的行数据(元素)。

如banner图,通过查看HTML代码,我们可以看出包含有<img>或者<ul>的标签。

这几张banner图采用无序列表标签<ul>内嵌图像标签<img>来实现。

<ul class="promos">
  <li>
    <a href="http://demo.magentocommerce.com/home-decor.html"> 
      <img src="/media/wysiwyg/homepage-three-column-promo-
       01B.png" alt="Physical & amp; Virtual Gift Cards">
    </a>
  </li>
  <li>
    <a href="http://demo.magentocommerce.com/vip.html">
      <img src="/media/wysiwyg/homepage-three-column-promo-
       02.png" alt="Shop Private Sales - Members Only">
    </a>
  </li>
  <li>
    <a href="http://demo.magentocommerce.com/accessories/ bags-luggage.html">
      <img src="/media/wysiwyg/homepage-three-column-
       promo-03.png" alt="Travel Gear for Every Occasion">
    </a>
  </li>
</ul>

我们使用find_elements_by_tag_name()方法来定位所有的banner图片。首先我们用find_element_by_class_name()方法定位这一组banner图,然后用find_elements_by_tag_name()方法去匹配<img>的tag name,最后把结果返回给banners对象。

def test_count_of_promo_banners_images(self):
  # get promo banner list
  banner_list = self.driver.find_element_by_class_name("promos")

  # get images from the banner_list
  banners = banner_list.find_elements_by_tag_name("img")

  # check there are 20 tags displayed on the page 
  self.assertEqual(2, len(banners))

XPath定位

XPath是一种在XML文档中搜索和定位元素的查询语言。几乎所有的浏览器都支持XPath。同样,Selenium也可以通过XPath的方式在Web页面上定位元素。

当我们发现通过ID、name或class属性值都无法定位元素时,不妨尝试用XPath的方式。我们可以灵活地运用绝对或相对路径定位,也可以通过除ID、name以外的其他属性来定位,甚至还可以通过属性值的一部分(如starts-with()、contains()和ends-with())来帮助我们定位。

了解更多关于XPath的知识,可访问相关网站了解。

想要了解更多关于XPath定位的知识,可以参考《Selenium Testing Tools Cookbook》,Packt Publishing。

我们可以使用find_element_by_xpath()和find_elements_by_xpath() 方法来定位元素了。例如,我们通过之前的广告banner图,单击banner图片进入对应的页面。

名为“Shop Private Sales”的banner图,在<img> 的tag下,其中代码并不包含ID、name或class属性等信息,且这个页面还包含很多其他的<img>,所以我们不能通过传统的方法如findby tag_name()简单地定位了。

<ul class="promos">
  ...
  <li>
    <a href="http://demo.magentocommerce.com/vip.html"> 
     <img src="/media/wysiwyg/homepage-three-column-
      promo-02.png" alt="Shop Private Sales - Members Only">
    </a>
  </li>
  ...
</ul>

我们尝试使用find_element_by_xpath()方法,用<img>标签下的 alt 属性值来定位我们要找的元素。

代码如下。

def test_vip_promo(self):
  # get vip promo image 
  vip_promo = self.driver.\
   find_element_by_xpath("//img[@alt='Shop Private Sales - Members Only']")

  # check vip promo logo is displayed on home page 
  self.assertTrue(vip_promo.is_displayed())
  # click on vip promo images to open the page
  vip_promo.click()
  # check page title
  self.assertEqual("VIP", self.driver.title)

此外,如果使用find_elements_by_xpath() 方法,那么将返回匹配XPath查询到的所有元素。

CSS选择器定位

CSS(层叠样式表)是一种用于页面设计(HTML)与表现的文件样式,是一种计算机语言,能灵活地为页面提供各种样式风格。CSS使用选择器为页面元素绑定属性(如ID、class、type、attribute、value等)。

类似XPath,Selenium也可以利用CSS选择器的特性,用于帮助我们来定位元素。如果想进一步了解关于CSS选择器的一些知识,请访问相关网站了解。

下面介绍find_element_by_css_selector()和find_elements_by_css_selector()两种方法。

回到首页的例子,可以看到购物车按钮,单击这个按钮,将进入购物车页面。如果此时没有添加任何商品,那么系统会提示“你还没有添加商品到购物车”

HTML代码如下。

<div class="minicart-wrapper">
<p class="block-subtitle">
  Recently added item(s)
  <a class="close skip-link-close" href="#" title="Close">
   ×</a>
</p>
  <p class="empty">You have no items in your shopping cart.
   </p>
</div>

我们设计测试程序来校验这个提示信息。首先我们将使用CSS选择器来定位购物车按钮,然后单击它,紧接着定位即将弹出的信息。

def test_shopping_cart_status(self): 
  # check content of My Shopping Cart block on Home page 
  # get the Shopping cart icon and click to open the 
  # Shopping Cart section 
  shopping_cart_icon = self.driver.\ 
    find_element_by_css_selector("div.header-minicart span.icon")
  shopping_cart_icon.click() 

  # get the shopping cart status 
  shopping_cart_status = self.driver.\ 
    find_element_by_css_selector("p.empty").text 
  self.assertEqual("You have no items in your shopping cart.", shopping_cart_status)
  # close the shopping cart section 
  close_button = self.driver.\ 
    find_element_by_css_selector("div.minicart-wrapper a.close")
  close_button.click()

从上面的测试脚本可以看出,我们使用了元素tag和class name来缩小获取购物车按钮的范围。

shopping_cart_icon = self.driver.\ 
    find_element_by_css_selector("div.header-minicart span.icon")

首先定位到tag 名为<div>的元素,然后接着“.header-minicart”的类名,其下面的标签<span>下又有“.icon”的类名。

想要了解更多关于CSS选择器的知识,请参考《Selenium Testing Tools Cookbook》,Packt Publishing。

Link定位

find_element_by_link_text() 和 find_elements_by_link_text()方法是通过文本链接来定位元素。如下示例。
(1)定位首页上的Account链接,如下图所示,我们可以使用find_element_by_link_text()方法。
(2)查看对应的HTML代码,具体如下。
<a href="#header-account" class="skip-link skip-account">
 <span class="icon"></span>
 <span class="label">Account</span> 
</a>
(3)编写测试脚本,先通过文本定位Account链接,然后单击查看是否能显示。
def test_my_account_link_is_displayed(self): 
  # get the Account link 
  account_link = 
   self.driver.find_element_by_link_text("ACCOUNT") 

  # check My Account link is displayed/visible in 
  # the Home page footer 
  self.assertTrue(account_link.is_displayed())

此外,如果使用find_elements_by_link_text()方法,那么将返回匹配文本的所有元素。

Partial link定位

find_element_by_partial_link_text()和find_elements_by_partial_link_text()两个方法是通过文本链接的一部分文本来定位元素的方法。如下示例。
(1)同样是首页,有两个链接可以查看个人账户(Account)页面,一个是页面标头(header)部分的Account文字链接,另外一个是页脚(footer)部分的My Account文字链接。
(2)我们使用find_elements_by_partial_link_text()方法,通过部分文本信息“Account”来定位,验证页面中的两个文本链接是否都能定位到(断言)。代码如下。
def test_account_links(self): 
  # get the all the links with Account text in it 
  account_links = self.driver.\ 
    find_elements_by_partial_link_text("ACCOUNT") 

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