Python Selenium:如何在预期条件下应用“与”逻辑运算符

Posted

技术标签:

【中文标题】Python Selenium:如何在预期条件下应用“与”逻辑运算符【英文标题】:Python Selenium: How to apply "And" logical operator in expected condition 【发布时间】:2021-02-09 18:49:56 【问题描述】:

基本上,我想做的是搜索https://www.s-s-rn.com/index.cfm/en/ 的名称,然后单击一些部分匹配的名称。例如,我想搜索“John Doe”。 s-s-rN 将返回在其作者列表中包含 John Doe 的论文列表。下面是我尝试这样做的代码。

name = "John Doe"
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, name.split(' ', 1)[0])) and
        EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, name.split(' ', 1)[1]))
    )
    # I want the element to be clicked only if both the first name and last name appear.
    element.click()
except:
    print("No result")

如果 John Doe 完全匹配,即作者列表看起来像 (John Doe, x, y, z),则此方法有效。如果 John Doe 是部分匹配并且没有其他部分匹配,则它有效,即作者列表看起来像 (John M. Doe, x, y, z)。但是,如果有多个部分匹配,它会中断。例如,如果列表看起来像 (Jane Doe, John Doe, y, z)。然后,我的代码将选择 Jane Doe。我想我想要类似于 Java 的 EC.and() 的东西,但我不确定如何实现它,或者是否有更好的方法来做到这一点。谢谢!

【问题讨论】:

.until 应该返回哪个元素?因为您实际上是在尝试找到 2 个元素 我希望元素与“John”和“Doe”都匹配。因此,如果有意义的话,可能是 John M. Doe 或 John Jack Doe 或 John Doe。 【参考方案1】:

sn-p

EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, name.split(' ', 1)[0])) and
EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, name.split(' ', 1)[1]))

只计算为

EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, name.split(' ', 1)[1]))

所以它总是只检查那个条件和那个条件,即它总是只试图找到Doe,完全忽略John。这就是为什么您会找到 Jane Doe,因为它之前出现过。

这不是您检查多个条件的方式,您需要将一个类似函数的对象传递给.until,它可以检查多个条件并返回一个真假值。

对于您的特定需求,该功能可能看起来像-

def presence_of_element_with_both(driver):
    name = "John Doe"
    first = EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, name.split(' ', 1)[0]))(driver)
    second = EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, name.split(' ', 1)[1]))(driver)
    if first == second:
        # Both elements exist and they are the same
        return first
    else:
        return False    

这将尝试查找带有部分链接文本“John”的元素,然后它将尝试查找带有部分链接文本“Doe”的元素 - 如果两个元素都找到并且都指向同一个元素 - 你'重金。

你可以在你的直到像这样使用它-

WebDriverWait(driver, 10).until(presence_of_element_with_both)

但是,您可能会发现将其概括起来很方便-

def presence_of_element_with_all(locators):
    def inner(driver):
        # Get all the elements that match each given locator
        results = [EC.presence_of_element_located(locator)(driver) for locator in locators]
        # Check if all the elements are the same
        # If they are, all the conditions have been met
        # If they are not, all the conditions did not meet
        return results[0] if len(set(results)) == 1 else False
    return inner

这将找到满足所有给定定位器的奇异元素。

你可以这样使用-

first_name, last_name = "John Doe".split(' ')
WebDriverWait(driver, 10).until(presence_of_element_with_all([(By.PARTIAL_LINK_TEXT, first_name), (By.PARTIAL_LINK_TEXT, last_name)]))

请注意,我正在使用闭包模式来执行此操作。在内部,selenium 使用 class__init____call__ 函数来做同样的事情 - 这被称为类似对象的函数,如果你愿意,你也可以使用它-

class presence_of_element_with_all:
    def __init__(self, locators):
        self.locators = locators
    def __call__(self, driver):
        results = [EC.presence_of_element_located(locator)(driver) for locator in self.locators]
        # Check if all the elements are the same
        # If they are, all the conditions have been met
        # If they are not, all the conditions did not meet
        return results[0] if len(set(results)) == 1 else False

您可以使用与闭包模式完全相同的方式。

【讨论】:

非常感谢您提供如此详尽的回答!它确实有效。我也一直在尝试涉足一些更复杂的东西,您的回答也对此有所帮助。

以上是关于Python Selenium:如何在预期条件下应用“与”逻辑运算符的主要内容,如果未能解决你的问题,请参考以下文章

Python+selenium之跳过测试和预期失败

Selenium 预期条件,等到元素可交互?

当 Selenium 中的预期条件失败时,不遵守 waitTime

Python+Selenium笔记:使用unittest

selenium.common.exceptions.InvalidArgumentException:消息:无效参数:“使用”必须是使用等待和预期条件的字符串

WebDriverWait 预期条件中的逻辑运算符