我在 Java 中使用 WebDriver。
我想从下面的金额字段中获取所有金额值,因此我计划循环遍历每个表行,并查找是否选中了复选框,将金额设置为定义的数字。
示例源代码可以在这里找到: http://eric-lin.net/upload/index.php
我使用以下Java方法来查找金额字段值:
public void fillInAllAmountForSelectedItems() {
List<WebElement> allItems = driver
.findElements(By
.xpath("//table[@id = 'bulkPaymentForm:itemTable']//tbody[@id = 'bulkPaymentForm:itemTable:tbody_element']//tr[contains(@class, 'handCursor row-border tranItemRow')]"));
System.out.println(allItems.size());
//return 3, expected
waitTimer(2, 1000);
for (WebElement item : allItems) {
System.out.println(item.findElement(By.xpath("//td[4]"))
.getAttribute("Value"));
}
}
大多数时候,foreach循环会因为陈旧元素异常而失败。我不明白,因为 DOM 没有改变。
当它工作时,foreach 循环不会打印任何内容,因此看起来它没有正确找到元素。
我该如何解决这个问题?我需要做什么才能实现此功能的目的,为所有选中的项目填写金额值?
提前非常感谢。
处理
StaleElementException
通常是一个尝试重试,直到成功的故事。 DOM 可能会因多种原因而刷新,从而导致元素变得陈旧。
处理元素列表时有时使用且通常有效的策略是逐项获取每个项目。 here发布了一个很好的解决方案,示例代码如下。
您将需要构建 xpath /css 选择器来相应地引用所需的表格单元格。请注意,该值将从
input
内的金额 td
字段中检索 - 如果您尝试从 td
获取文本,它将是空白的,就像您现在看到的那样。
//get the number of items that are required
int size = driver.findElements(By.cssSelector("table#mytable>tbody>tr>td[4]/input")).size();
//now work with each one individually, rather than with a list
for(int i = 1; i <= size; i++) {
String locator = String.format("table#mytable>tbody>tr[%d]>td[4]/input", i);
WebElement inputField = driver.findElement(By.cssSelector(locator));
//get or set the value of the input element
System.out.println(inputField.getAttribute("value"));
}
您的初始目标 (
variable
) 制作了 HTML 外观的本地副本。当 DOM 更改时(例如,您转到下一页),它仍然具有相同的初始状态,这被认为是陈旧的。
修复非常简单,您所要做的就是再次重新定位/重新分配该目标。这是考虑到您有多个页面和相同的目标 HTML 标记,但您不想每次都刷新页面,这是浪费时间。 在
for
循环中重定向 HTML 标签的示例
我打赌你们一定在使用 python,我很抱歉删除了 javascript 代码。
for (let x = 0; x <= totalPages; x++) {
// Skip clicking the next page if x is 0 [first page]
if (x > 0) {
await driver
.wait(
until.elementLocated(By.xpath("input your next button xpath")),
patience, // input your time in milliseconds
)
.click();
// time taken to get to next page
await driver.sleep(5000);
}
// this is your target, this will retarget everytime the loop runs
const tableBody = await driver.wait(
until.elementsLocated(By.tagName("tbody")),
patience,
);
// write your other business logic as you like
}