【问题标题】:Simplifying Complex XPath Expression in Selenium简化 Selenium 中的复杂 XPath 表达式
【发布时间】:2018-09-22 00:04:25
【问题描述】:

我有以下 HTML sn-p:

<div class="a-row a-spacing-micro">
<div class="a-column a-span4 a-spacing-none a-spacing-top-mini address-column">
<div id="ya-myab-display-address-block-2" class="a-box a-spacing-none normal-desktop-address-tile">
<div class="a-box-inner a-padding-none">
<div class="a-section address-section-no-default">
<div class="a-row a-spacing-small">
<ul class="a-unordered-list a-noStyle a-vertical">
<li>
<span class="a-list-item">
<h5 id="address-ui-widgets-FullName" class="id-addr-ux-search-text a-text-bold">XXX XXXXX</h5>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-AddressLineOne" class="id-addr-ux-search-text">DDD XXXX XX</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-CityXXatePoXXalCode" class="id-addr-ux-search-text">XXXXXXXX, XX DDDDD-DDDD</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-Country" class="id-addr-ux-search-text">United States</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-PhoneNumber" class="id-addr-ux-search-text">Phone number: DDDDDDDDDD</span>
</span>
</li>
</ul>
<script>P.when('A', 'ready').execute(function(A) {   var $ = A.$;   var localizedXXrings = A.XXate('address-ui-widgets-XXore-map-text-id');   $(".address-ui-widgets-map-link").click(function(event) {     event.preventDefault();     window.open(this.href, localizedXXrings["address_ui_widgets_XXore_address_map_header"], "width=600,height=450");   }) }); </script>
</div>
</div>
</div>
</div>
<div id="ya-myab-edit-address-desktop-row-2" class="a-row edit-address-desktop-link">
<a id="ya-myab-address-edit-btn-2" class="a-link-normal" href="/a/addresses/edit?ref=ya_address_book_edit_button&addressID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX">Edit            </a>
   |  
<a id="ya-myab-address-delete-btn-2" class="a-link-normal" href="#">
<span class="a-declarative" data-a-modal="{"name":"deleteAddressModal-2","width":"400","header":"Confirm Deletion"}" data-action="a-modal">Delete</span>
<div id="a-popover-deleteAddressModal-2" class="a-popover-preload">
<div class="a-section">
<div class="a-row a-spacing-small">
<ul class="a-unordered-list a-noStyle a-vertical">
<li>
<span class="a-list-item">
<h5 id="address-ui-widgets-FullName" class="id-addr-ux-search-text a-text-bold">XXX XXXXX</h5>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-AddressLineOne" class="id-addr-ux-search-text">DDD XXXX XX</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-CityXXatePoXXalCode" class="id-addr-ux-search-text">XXXXXXXX, XX DDDDD-DDDD</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-Country" class="id-addr-ux-search-text">United States</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-PhoneNumber" class="id-addr-ux-search-text">Phone number: 3472631425</span>
</span>
</li>
</ul>
<script>P.when('A', 'ready').execute(function(A) {   var $ = A.$;   var localizedXXrings = A.XXate('address-ui-widgets-XXore-map-text-id');   $(".address-ui-widgets-map-link").click(function(event) {     event.preventDefault();     window.open(this.href, localizedXXrings["address_ui_widgets_XXore_address_map_header"], "width=600,height=450");   }) }); </script>
</div>
<div class="a-row a-spacing-small">
<span class="a-size-small a-color-tertiary">
<span class="a-text-bold">Please note: </span>
Deleting this address will not delete any pending orders being shipped to this address. To ensure uninterrupted fulfillment of future orders, please update any wishliXXs, subscribe and save settings and periodical subscriptions using this address.
</span>
</div>
<div class="a-row a-spacing-none">
<hr class="a-divider-normal"/>
</div>
<div class="a-row">
<div class="a-column a-span6">
<div class="a-row">
<div class="a-column a-span3"/>
<div class="a-column a-span8">
<span id="deleteAddressModal-2-cancel-btn" class="a-button a-button-span12">
<span class="a-button-inner">
<button id="deleteAddressModal-2-cancel-btn-announce" class="a-button-text" type="button">No</button>
</span>
</span>
</div>
</div>
</div>
<div class="a-column a-span6 a-span-laXX">
<div class="a-row">
<div class="a-column a-span1"/>
<div class="a-column a-span8">
<form class="a-spacing-none" action="/a/addresses/delete" method="poXX">
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" name="addressID"/>
<input type="hidden" value="false" name="isXXoreAddress"/>
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXX" name="csrfToken"/>
<span id="deleteAddressModal-2-submit-btn" class="a-button a-button-span12 a-button-primary">
<span class="a-button-inner">
<input class="a-button-input" type="submit" aria-labelledby="deleteAddressModal-2-submit-btn-announce"/>
<span id="deleteAddressModal-2-submit-btn-announce" class="a-button-text" aria-hidden="true">Yes</span>
</span>
</span>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</a>
<form class="set-address-default" action="/a/addresses/set-default-address?ref=ya_address_book_set_default_button" method="poXX">
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXX" name="csrfToken"/>
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" name="addressID"/>
                  |  
<a id="ya-myab-set-default-shipping-btn-2" class="a-link-normal" href="#">Set as Default</a>
</form>
</div>
</div>
<div class="a-column a-span4 a-spacing-none a-spacing-top-mini address-column">
<div id="ya-myab-display-address-block-3" class="a-box a-spacing-none normal-desktop-address-tile">
<div class="a-box-inner a-padding-none">
<div class="a-section address-section-no-default">
<div class="a-row a-spacing-small">
<ul class="a-unordered-list a-noStyle a-vertical">
<li>
<span class="a-list-item">
<h5 id="address-ui-widgets-FullName" class="id-addr-ux-search-text a-text-bold">XXXXXXX XXXXX</h5>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-AddressLineOne" class="id-addr-ux-search-text">DDD XXXX XX</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-CityXXatePoXXalCode" class="id-addr-ux-search-text">XXXXXXXX, XX DDDDD</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-Country" class="id-addr-ux-search-text">United States</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-PhoneNumber" class="id-addr-ux-search-text">Phone number: 3472631425</span>
</span>
</li>
</ul>
<script>P.when('A', 'ready').execute(function(A) {   var $ = A.$;   var localizedXXrings = A.XXate('address-ui-widgets-XXore-map-text-id');   $(".address-ui-widgets-map-link").click(function(event) {     event.preventDefault();     window.open(this.href, localizedXXrings["address_ui_widgets_XXore_address_map_header"], "width=600,height=450");   }) }); </script>
</div>
</div>
</div>
</div>
<div id="ya-myab-edit-address-desktop-row-3" class="a-row edit-address-desktop-link">
<a id="ya-myab-address-edit-btn-3" class="a-link-normal" href="/a/addresses/edit?ref=ya_address_book_edit_button&addressID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX">Edit            </a>
   |  
<a id="ya-myab-address-delete-btn-3" class="a-link-normal" href="#">
<span class="a-declarative" data-a-modal="{"name":"deleteAddressModal-3","width":"400","header":"Confirm Deletion"}" data-action="a-modal">Delete</span>
<div id="a-popover-deleteAddressModal-3" class="a-popover-preload">
<div class="a-section">
<div class="a-row a-spacing-small">
<ul class="a-unordered-list a-noStyle a-vertical">
<li>
<span class="a-list-item">
<h5 id="address-ui-widgets-FullName" class="id-addr-ux-search-text a-text-bold">XXXXXXX XXXXX</h5>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-AddressLineOne" class="id-addr-ux-search-text">DDD XXXX XX</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-CityXXatePoXXalCode" class="id-addr-ux-search-text">XXXXXXXX, XX DDDDD</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-Country" class="id-addr-ux-search-text">United States</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-PhoneNumber" class="id-addr-ux-search-text">Phone number: DDDDDDDDDD</span>
</span>
</li>
</ul>
<script>P.when('A', 'ready').execute(function(A) {   var $ = A.$;   var localizedXXrings = A.XXate('address-ui-widgets-XXore-map-text-id');   $(".address-ui-widgets-map-link").click(function(event) {     event.preventDefault();     window.open(this.href, localizedXXrings["address_ui_widgets_XXore_address_map_header"], "width=600,height=450");   }) }); </script>
</div>
<div class="a-row a-spacing-small">
<span class="a-size-small a-color-tertiary">
<span class="a-text-bold">Please note: </span>
Deleting this address will not delete any pending orders being shipped to this address. To ensure uninterrupted fulfillment of future orders, please update any wishliXXs, subscribe and save settings and periodical subscriptions using this address.
</span>
</div>
<div class="a-row a-spacing-none">
<hr class="a-divider-normal"/>
</div>
<div class="a-row">
<div class="a-column a-span6">
<div class="a-row">
<div class="a-column a-span3"/>
<div class="a-column a-span8">
<span id="deleteAddressModal-3-cancel-btn" class="a-button a-button-span12">
<span class="a-button-inner">
<button id="deleteAddressModal-3-cancel-btn-announce" class="a-button-text" type="button">No</button>
</span>
</span>
</div>
</div>
</div>
<div class="a-column a-span6 a-span-laXX">
<div class="a-row">
<div class="a-column a-span1"/>
<div class="a-column a-span8">
<form class="a-spacing-none" action="/a/addresses/delete" method="poXX">
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" name="addressID"/>
<input type="hidden" value="false" name="isXXoreAddress"/>
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXX" name="csrfToken"/>
<span id="deleteAddressModal-3-submit-btn" class="a-button a-button-span12 a-button-primary">
<span class="a-button-inner">
<input class="a-button-input" type="submit" aria-labelledby="deleteAddressModal-3-submit-btn-announce"/>
<span id="deleteAddressModal-3-submit-btn-announce" class="a-button-text" aria-hidden="true">Yes</span>
</span>
</span>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</a>
<form class="set-address-default" action="/a/addresses/set-default-address?ref=ya_address_book_set_default_button" method="poXX">
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXX" name="csrfToken"/>
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" name="addressID"/>
                  |  
<a id="ya-myab-set-default-shipping-btn-3" class="a-link-normal" href="#">Set as Default</a>
</form>
</div>
</div>
<div class="a-column a-span4 a-spacing-none a-spacing-top-mini address-column a-span-laXX">
<div id="ya-myab-display-address-block-4" class="a-box a-spacing-none normal-desktop-address-tile">
<div class="a-box-inner a-padding-none">
<div class="a-section address-section-no-default">
<div class="a-row a-spacing-small">
<ul class="a-unordered-list a-noStyle a-vertical">
<li>
<span class="a-list-item">
<h5 id="address-ui-widgets-FullName" class="id-addr-ux-search-text a-text-bold">XXXXXXX XXXXX</h5>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-AddressLineOne" class="id-addr-ux-search-text">DDD XXXX XX</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-CityXXatePoXXalCode" class="id-addr-ux-search-text">XXXXXXXX, XX DDDDD</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-Country" class="id-addr-ux-search-text">United States</span>
</span>
</li>
</ul>
<script>P.when('A', 'ready').execute(function(A) {   var $ = A.$;   var localizedXXrings = A.XXate('address-ui-widgets-XXore-map-text-id');   $(".address-ui-widgets-map-link").click(function(event) {     event.preventDefault();     window.open(this.href, localizedXXrings["address_ui_widgets_XXore_address_map_header"], "width=600,height=450");   }) }); </script>
</div>
</div>
</div>
</div>
<div id="ya-myab-edit-address-desktop-row-4" class="a-row edit-address-desktop-link">
<a id="ya-myab-address-edit-btn-4" class="a-link-normal" href="/a/addresses/edit?ref=ya_address_book_edit_button&addressID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX">Edit            </a>
   |  
<a id="ya-myab-address-delete-btn-4" class="a-link-normal" href="#">
<span class="a-declarative" data-a-modal="{"name":"deleteAddressModal-4","width":"400","header":"Confirm Deletion"}" data-action="a-modal">Delete</span>
<div id="a-popover-deleteAddressModal-4" class="a-popover-preload">
<div class="a-section">
<div class="a-row a-spacing-small">
<ul class="a-unordered-list a-noStyle a-vertical">
<li>
<span class="a-list-item">
<h5 id="address-ui-widgets-FullName" class="id-addr-ux-search-text a-text-bold">XXXXXXX XXXXX</h5>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-AddressLineOne" class="id-addr-ux-search-text">DDD XXXX XX</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-CityXXatePoXXalCode" class="id-addr-ux-search-text">XXXXXXXX, XX DDDDD</span>
</span>
</li>
<li>
<span class="a-list-item">
<span id="address-ui-widgets-Country" class="id-addr-ux-search-text">United States</span>
</span>
</li>
</ul>
<script>P.when('A', 'ready').execute(function(A) {   var $ = A.$;   var localizedXXrings = A.XXate('address-ui-widgets-XXore-map-text-id');   $(".address-ui-widgets-map-link").click(function(event) {     event.preventDefault();     window.open(this.href, localizedXXrings["address_ui_widgets_XXore_address_map_header"], "width=600,height=450");   }) }); </script>
</div>
<div class="a-row a-spacing-small">
<span class="a-size-small a-color-tertiary">
<span class="a-text-bold">Please note: </span>
Deleting this address will not delete any pending orders being shipped to this address. To ensure uninterrupted fulfillment of future orders, please update any wishliXXs, subscribe and save settings and periodical subscriptions using this address.
</span>
</div>
<div class="a-row a-spacing-none">
<hr class="a-divider-normal"/>
</div>
<div class="a-row">
<div class="a-column a-span6">
<div class="a-row">
<div class="a-column a-span3"/>
<div class="a-column a-span8">
<span id="deleteAddressModal-4-cancel-btn" class="a-button a-button-span12">
<span class="a-button-inner">
<button id="deleteAddressModal-4-cancel-btn-announce" class="a-button-text" type="button">No</button>
</span>
</span>
</div>
</div>
</div>
<div class="a-column a-span6 a-span-laXX">
<div class="a-row">
<div class="a-column a-span1"/>
<div class="a-column a-span8">
<form class="a-spacing-none" action="/a/addresses/delete" method="poXX">
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" name="addressID"/>
<input type="hidden" value="false" name="isXXoreAddress"/>
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXX" name="csrfToken"/>
<span id="deleteAddressModal-4-submit-btn" class="a-button a-button-span12 a-button-primary">
<span class="a-button-inner">
<input class="a-button-input" type="submit" aria-labelledby="deleteAddressModal-4-submit-btn-announce"/>
<span id="deleteAddressModal-4-submit-btn-announce" class="a-button-text" aria-hidden="true">Yes</span>
</span>
</span>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</a>
<form class="set-address-default" action="/a/addresses/set-default-address?ref=ya_address_book_set_default_button" method="poXX">
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXX" name="csrfToken"/>
<input type="hidden" value="XXXXXXXXXXXXXXXXXXXXXXX" name="addressID"/>
                  |  
<a id="ya-myab-set-default-shipping-btn-4" class="a-link-normal" href="#">Set as Default</a>
</form>
</div>
</div>
</div>

大致对应如下布局/设计:

如上图所示,每个框都包含一个名称和地址,可以选择编辑、删除或设置为默认值。

仅给出地址或名称 - 如何为相应地址(或名称)单击“设为默认值”?

到目前为止,唯一有效的 XPath 是基于链接多个 /parent::*/ 表达式,如下所示。

.//*[contains (text(),'123 XYZ AVE')]/parent::*/parent::*/parent::*/parent::*/parent::*/parent::*/parent::*/parent::*/form/input (selects based on address)

.//*[contains (text(),'NAME')]/parent::*/parent::*/parent::*/parent::*/parent::*/parent::*/parent::*/parent::*/form/input (selects based on name)

前面的表达式所做的是告诉 Selenium 找到名称或地址 (.//*[contains (text(),'NAME')]),然后向上/向后移动几级,直到到达包含所有子元素的元素(包括 Edit、Delete 和 Set as默认选项),然后找到具有/form/input 值的元素。

虽然这可行,但如果父元素的 any 的结构/数量发生变化,它会非常庞大​​且笨拙且容易损坏。

如何简化此表达式,以便给定地址或名称(假设所有地址/名称都是唯一的)我可以识别并单击相关的“设置为默认值”选项而无需爬上层次结构?

谢谢!

【问题讨论】:

  • addressID的值是否唯一?
  • 根据您共享的 xpaths,我看不到任何带有 123 XYZ AVENAME 文本的节点b>,我错过了什么吗?
  • LuisMuñoz:是的,但我正在假设这些值不知道只有名称/地址 @DebanjanB 123 XYZ AVE 或 NAME 只是虚拟值..

标签: java html selenium selenium-webdriver xpath


【解决方案1】:

首先通过人名找到整个地址段属于一个人,然后在该段内找到Edit/Delete/Set as Default按钮:

private WebElement findAddressSection(customerName) {
    String xpathExp = "//div[contains(@class, 'a-column a-span4')]" +
           "[div//h5[text()='"+ customerName+"']]";

    return driver.findElement(By.xpath(xpathExp));
}

public void clickAddressEditBtn(customerName) {
    WebElement section = findAddressSection(customerName);

    section.findElement(By.cssSelector("a[id*='ya-myab-address-edit-btn']"))
           .click();
}

public void clickAddressDeleteBtn(customerName) {
    WebElement section = findAddressSection(customerName);

    section.findElement(By.cssSelector("a[id*='ya-myab-address-delete-btn']"))
           .click();
}

public void clickAddressSetDefaultBtn(customerName) {
    WebElement section = findAddressSection(customerName);

    section.findElement(By.cssSelector("a[id*='ya-myab-set-default-shipping-btn']"))
           .click();
}

【讨论】:

  • 作品和赞成的答案但是我很好奇是否有某种方法可以在不使用 OP 中使用的复杂表达式的情况下将子元素与祖父元素相关联?
【解决方案2】:

示例 HTML 包含几个错误(重复 ID 等),但下面的 xpath 应该有助于获取值

'//*[contains(.,"abcdert")]/descendant::form/input'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-09
    • 1970-01-01
    • 2020-08-15
    • 2013-07-24
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多