通过Selenium,Python中的xpath检测用户可见元素(仅在视口中)

问题描述:

我试图仅单击实际上对用户可见的元素,即不要单击我当前在网站上滚动到的位置之外的元素.

I am trying to only click on elements that would actually be visible to a user, i.e. don't click on elements outside the where I am currently scrolled to on a website.

我设法检测出所有隐藏的元素,但是如何获取普通用户只能看到的元素列表.

I manage to detect all the ones that are hidden, but how to get a list of only elements a normal user would be able to see.

如果我对您的理解正确,那么您正在查找一堆这样的元素:

If I right understand you, you are locating a bunch of elements like this:

elements = driver.find_elements_by_xpath("//a")

它将为您提供元素列表.这些元素中有些是可见的,有些则不可见.要证明这一点,您可以使用以下方法:

it will give you a list of elements. Some of this elements are visible, some of them not. To prove it you can use this:

for element in elements:
    print(element.is_displayed()) # prints true if displayed, otherwise false

尝试以下代码段:

driver = webdriver.Chrome("C:\\path\\to\\chromedriver.exe")
url = "https://*.com/"
driver.get(url)

elements = driver.find_elements_by_xpath("//a") # finds all elements by given xPath
for element in elements: # for every element in elements list
    print(element.is_displayed()) # print 'true' if displayed, or 'false' if not

print("DONE")

输出:

False
True
False
True
True
True
True
True
True
False
False
False
False
...
DONE

注意:这只是一个示例,通常必须等到页面完全加载才能正确定位所有元素并获得正确的状态.

NOTE: it is only an example, normally you have to wait until the page fully loads to locate all elements correctly and also get the correct state of them.

我在此

I have found a nice solution in this question and the sample code in this case would be like this:

driver = webdriver.Chrome("C:\\path\\to\\chromedriver.exe")
url = "https://*.com/"
driver.get(url)

time.sleep(3)
elements = driver.find_elements_by_xpath("//span")

def element_in_viewport(driver, elem):
    elem_left_bound = elem.location.get('x')
    elem_top_bound = elem.location.get('y')
    elem_width = elem.size.get('width')
    elem_height = elem.size.get('height')
    elem_right_bound = elem_left_bound + elem_width
    elem_lower_bound = elem_top_bound + elem_height

    win_upper_bound = driver.execute_script('return window.pageYOffset')
    win_left_bound = driver.execute_script('return window.pageXOffset')
    win_width = driver.execute_script('return document.documentElement.clientWidth')
    win_height = driver.execute_script('return document.documentElement.clientHeight')
    win_right_bound = win_left_bound + win_width
    win_lower_bound = win_upper_bound + win_height

    return all((win_left_bound <= elem_left_bound,
                win_right_bound >= elem_right_bound,
                win_upper_bound <= elem_top_bound,
                win_lower_bound >= elem_lower_bound)
               )

for element in elements:
    print(element_in_viewport(driver, element))

print("DONE")

输出:

True
True
True
True
True
True
True
True
True
True
True
True
True
False
True
True
True
True
False
False
False
False
False
False
False
...
DONE

在我看来,此代码段效果很好.

In my perspective this code snippet works good.