标签归档:selenium-webdriver

如何在python中使用Selenium Webdriver滚动网页?

问题:如何在python中使用Selenium Webdriver滚动网页?

我目前正在使用Selenium Webdriver通过Facebook用户朋友页面进行解析,并从AJAX脚本中提取所有ID。但是我需要向下滚动才能得到所有的朋友。如何在Selenium中向下滚动。我正在使用python。

I am currently using selenium webdriver to parse through facebook user friends page and extract all ids from the AJAX script. But I need to scroll down to get all the friends. How can I scroll down in Selenium. I am using python.


回答 0

您可以使用

driver.execute_script("window.scrollTo(0, Y)") 

其中Y是高度(在全高清显示器上为1080)。(感谢@lukeis)

您也可以使用

driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

滚动到页面底部。

如果您想滚动到无限加载的页面,例如社交网络页面,facebook等(感谢@Cuong Tran)

SCROLL_PAUSE_TIME = 0.5

# Get scroll height
last_height = driver.execute_script("return document.body.scrollHeight")

while True:
    # Scroll down to bottom
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

    # Wait to load page
    time.sleep(SCROLL_PAUSE_TIME)

    # Calculate new scroll height and compare with last scroll height
    new_height = driver.execute_script("return document.body.scrollHeight")
    if new_height == last_height:
        break
    last_height = new_height

另一种方法(感谢Juanse)是,选择一个对象,然后

label.sendKeys(Keys.PAGE_DOWN);

You can use

driver.execute_script("window.scrollTo(0, Y)") 

where Y is the height (on a fullhd monitor it’s 1080). (Thanks to @lukeis)

You can also use

driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

to scroll to the bottom of the page.

If you want to scroll to a page with infinite loading, like social network ones, facebook etc. (thanks to @Cuong Tran)

SCROLL_PAUSE_TIME = 0.5

# Get scroll height
last_height = driver.execute_script("return document.body.scrollHeight")

while True:
    # Scroll down to bottom
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

    # Wait to load page
    time.sleep(SCROLL_PAUSE_TIME)

    # Calculate new scroll height and compare with last scroll height
    new_height = driver.execute_script("return document.body.scrollHeight")
    if new_height == last_height:
        break
    last_height = new_height

another method (thanks to Juanse) is, select an object and

label.sendKeys(Keys.PAGE_DOWN);

回答 1

如果要向下滚动到无限页面的底部(例如linkedin.com),可以使用以下代码:

SCROLL_PAUSE_TIME = 0.5

# Get scroll height
last_height = driver.execute_script("return document.body.scrollHeight")

while True:
    # Scroll down to bottom
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

    # Wait to load page
    time.sleep(SCROLL_PAUSE_TIME)

    # Calculate new scroll height and compare with last scroll height
    new_height = driver.execute_script("return document.body.scrollHeight")
    if new_height == last_height:
        break
    last_height = new_height

参考:https : //stackoverflow.com/a/28928684/1316860

If you want to scroll down to bottom of infinite page (like linkedin.com), you can use this code:

SCROLL_PAUSE_TIME = 0.5

# Get scroll height
last_height = driver.execute_script("return document.body.scrollHeight")

while True:
    # Scroll down to bottom
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

    # Wait to load page
    time.sleep(SCROLL_PAUSE_TIME)

    # Calculate new scroll height and compare with last scroll height
    new_height = driver.execute_script("return document.body.scrollHeight")
    if new_height == last_height:
        break
    last_height = new_height

Reference: https://stackoverflow.com/a/28928684/1316860


回答 2

您可以send_keys用来模拟END(或PAGE_DOWN)按键(通常会滚动页面):

from selenium.webdriver.common.keys import Keys
html = driver.find_element_by_tag_name('html')
html.send_keys(Keys.END)

You can use send_keys to simulate an END (or PAGE_DOWN) key press (which normally scroll the page):

from selenium.webdriver.common.keys import Keys
html = driver.find_element_by_tag_name('html')
html.send_keys(Keys.END)

回答 3

如图相同的方法在这里

在python中,您可以使用

driver.execute_script("window.scrollTo(0, Y)")

(Y是您要滚动到的垂直位置)

same method as shown here:

in python you can just use

driver.execute_script("window.scrollTo(0, Y)")

(Y is the vertical position you want to scroll to)


回答 4

element=find_element_by_xpath("xpath of the li you are trying to access")

element.location_once_scrolled_into_view

当我尝试访问不可见的“ li”时,这很有帮助。

element=find_element_by_xpath("xpath of the li you are trying to access")

element.location_once_scrolled_into_view

this helped when I was trying to access a ‘li’ that was not visible.


回答 5

出于我的目的,我想向下滚动更多,同时牢记窗口的位置。我的解决方案是相似的,并使用window.scrollY

driver.execute_script("window.scrollTo(0, window.scrollY + 200)")

它将转到当前的y滚动位置+ 200

For my purpose, I wanted to scroll down more, keeping the windows position in mind. My solution was similar and used window.scrollY

driver.execute_script("window.scrollTo(0, window.scrollY + 200)")

which will go to the current y scroll position + 200


回答 6

这是您向下滚动网页的方式:

driver.execute_script("window.scrollTo(0, 1000);")

This is how you scroll down the webpage:

driver.execute_script("window.scrollTo(0, 1000);")

回答 7

我发现解决该问题的最简单方法是选择一个标签,然后发送:

label.sendKeys(Keys.PAGE_DOWN);

希望它能起作用!

The easiest way i found to solve that problem was to select a label and then send:

label.sendKeys(Keys.PAGE_DOWN);

Hope it works!


回答 8

这些答案都不适合我,至少不是向下滚动Facebook搜索结果页面有效,但经过大量测试,我发现此解决方案:

while driver.find_element_by_tag_name('div'):
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    Divs=driver.find_element_by_tag_name('div').text
    if 'End of Results' in Divs:
        print 'end'
        break
    else:
        continue

None of these answers worked for me, at least not for scrolling down a facebook search result page, but I found after a lot of testing this solution:

while driver.find_element_by_tag_name('div'):
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    Divs=driver.find_element_by_tag_name('div').text
    if 'End of Results' in Divs:
        print 'end'
        break
    else:
        continue

回答 9

使用youtube时,浮动元素的滚动高度为“ 0”,因此请不要使用“ return document.body.scrollHeight”,而是尝试使用此“ return document.documentElement.scrollHeight” ,根据您的互联网调整滚动暂停时间速度,否则它将只运行一次,然后在此之后中断。

SCROLL_PAUSE_TIME = 1

# Get scroll height
"""last_height = driver.execute_script("return document.body.scrollHeight")

this dowsnt work due to floating web elements on youtube
"""

last_height = driver.execute_script("return document.documentElement.scrollHeight")
while True:
    # Scroll down to bottom
    driver.execute_script("window.scrollTo(0,document.documentElement.scrollHeight);")

    # Wait to load page
    time.sleep(SCROLL_PAUSE_TIME)

    # Calculate new scroll height and compare with last scroll height
    new_height = driver.execute_script("return document.documentElement.scrollHeight")
    if new_height == last_height:
       print("break")
       break
    last_height = new_height

When working with youtube the floating elements give the value “0” as the scroll height so rather than using “return document.body.scrollHeight” try using this one “return document.documentElement.scrollHeight” adjust the scroll pause time as per your internet speed else it will run for only one time and then breaks after that.

SCROLL_PAUSE_TIME = 1

# Get scroll height
"""last_height = driver.execute_script("return document.body.scrollHeight")

this dowsnt work due to floating web elements on youtube
"""

last_height = driver.execute_script("return document.documentElement.scrollHeight")
while True:
    # Scroll down to bottom
    driver.execute_script("window.scrollTo(0,document.documentElement.scrollHeight);")

    # Wait to load page
    time.sleep(SCROLL_PAUSE_TIME)

    # Calculate new scroll height and compare with last scroll height
    new_height = driver.execute_script("return document.documentElement.scrollHeight")
    if new_height == last_height:
       print("break")
       break
    last_height = new_height

回答 10

我正在寻找一种滚动浏览动态网页的方法,并在到达页面末尾并发现该线程时自动停止。

@Cuong Tran的帖子进行了主要修改,是我正在寻找的答案。我认为其他人可能会发现此修改很有用(它对代码的工作方式有明显影响),因此,本文发布了。

修改是移动捕获循环最后一页高度的语句(以便使每项检查都与上一页高度进行比较)。

因此,下面的代码:

连续向下滚动动态网页(.scrollTo()),仅在一次迭代中页面高度保持不变时停止。

(还有另一种修改,其中break语句位于另一个可以删除的条件内(如果页面为“ sticks”)。

    SCROLL_PAUSE_TIME = 0.5


    while True:

        # Get scroll height
        ### This is the difference. Moving this *inside* the loop
        ### means that it checks if scrollTo is still scrolling 
        last_height = driver.execute_script("return document.body.scrollHeight")

        # Scroll down to bottom
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

        # Wait to load page
        time.sleep(SCROLL_PAUSE_TIME)

        # Calculate new scroll height and compare with last scroll height
        new_height = driver.execute_script("return document.body.scrollHeight")
        if new_height == last_height:

            # try again (can be removed)
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

            # Wait to load page
            time.sleep(SCROLL_PAUSE_TIME)

            # Calculate new scroll height and compare with last scroll height
            new_height = driver.execute_script("return document.body.scrollHeight")

            # check if the page height has remained the same
            if new_height == last_height:
                # if so, you are done
                break
            # if not, move on to the next loop
            else:
                last_height = new_height
                continue

I was looking for a way of scrolling through a dynamic webpage, and automatically stopping once the end of the page is reached, and found this thread.

The post by @Cuong Tran, with one main modification, was the answer that I was looking for. I thought that others might find the modification helpful (it has a pronounced effect on how the code works), hence this post.

The modification is to move the statement that captures the last page height inside the loop (so that each check is comparing to the previous page height).

So, the code below:

Continuously scrolls down a dynamic webpage (.scrollTo()), only stopping when, for one iteration, the page height stays the same.

(There is another modification, where the break statement is inside another condition (in case the page ‘sticks’) which can be removed).

    SCROLL_PAUSE_TIME = 0.5


    while True:

        # Get scroll height
        ### This is the difference. Moving this *inside* the loop
        ### means that it checks if scrollTo is still scrolling 
        last_height = driver.execute_script("return document.body.scrollHeight")

        # Scroll down to bottom
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

        # Wait to load page
        time.sleep(SCROLL_PAUSE_TIME)

        # Calculate new scroll height and compare with last scroll height
        new_height = driver.execute_script("return document.body.scrollHeight")
        if new_height == last_height:

            # try again (can be removed)
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

            # Wait to load page
            time.sleep(SCROLL_PAUSE_TIME)

            # Calculate new scroll height and compare with last scroll height
            new_height = driver.execute_script("return document.body.scrollHeight")

            # check if the page height has remained the same
            if new_height == last_height:
                # if so, you are done
                break
            # if not, move on to the next loop
            else:
                last_height = new_height
                continue

回答 11

该代码滚动到底部,但不需要您每次都等待。它会不断滚动,然后在底部停止(或超时)

from selenium import webdriver
import time

driver = webdriver.Chrome(executable_path='chromedriver.exe')
driver.get('https://example.com')

pre_scroll_height = driver.execute_script('return document.body.scrollHeight;')
run_time, max_run_time = 0, 1
while True:
    iteration_start = time.time()
    # Scroll webpage, the 100 allows for a more 'aggressive' scroll
    driver.execute_script('window.scrollTo(0, 100*document.body.scrollHeight);')

    post_scroll_height = driver.execute_script('return document.body.scrollHeight;')

    scrolled = post_scroll_height != pre_scroll_height
    timed_out = run_time >= max_run_time

    if scrolled:
        run_time = 0
        pre_scroll_height = post_scroll_height
    elif not scrolled and not timed_out:
        run_time += time.time() - iteration_start
    elif not scrolled and timed_out:
        break

# closing the driver is optional 
driver.close()

这比每次等待0.5-3秒等待响应要快得多,因为该响应可能需要0.1秒

This code scrolls to the bottom but doesn’t require that you wait each time. It’ll continually scroll, and then stop at the bottom (or timeout)

from selenium import webdriver
import time

driver = webdriver.Chrome(executable_path='chromedriver.exe')
driver.get('https://example.com')

pre_scroll_height = driver.execute_script('return document.body.scrollHeight;')
run_time, max_run_time = 0, 1
while True:
    iteration_start = time.time()
    # Scroll webpage, the 100 allows for a more 'aggressive' scroll
    driver.execute_script('window.scrollTo(0, 100*document.body.scrollHeight);')

    post_scroll_height = driver.execute_script('return document.body.scrollHeight;')

    scrolled = post_scroll_height != pre_scroll_height
    timed_out = run_time >= max_run_time

    if scrolled:
        run_time = 0
        pre_scroll_height = post_scroll_height
    elif not scrolled and not timed_out:
        run_time += time.time() - iteration_start
    elif not scrolled and timed_out:
        break

# closing the driver is optional 
driver.close()

This is much faster than waiting 0.5-3 seconds each time for a response, when that response could take 0.1 seconds


回答 12

滚动加载页面。示例:中,定额等

last_height = driver.execute_script("return document.body.scrollHeight")
    while True:
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight-1000);")
        # Wait to load the page.
        driver.implicitly_wait(30) # seconds
        new_height = driver.execute_script("return document.body.scrollHeight")
    
        if new_height == last_height:
            break
        last_height = new_height
        # sleep for 30s
        driver.implicitly_wait(30) # seconds
    driver.quit()

scroll loading pages. Example: medium, quora,etc

last_height = driver.execute_script("return document.body.scrollHeight")
    while True:
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight-1000);")
        # Wait to load the page.
        driver.implicitly_wait(30) # seconds
        new_height = driver.execute_script("return document.body.scrollHeight")
    
        if new_height == last_height:
            break
        last_height = new_height
        # sleep for 30s
        driver.implicitly_wait(30) # seconds
    driver.quit()

回答 13

如果要在特定视图/框架(WebElement)中滚动,则只需将“ body”替换为要在其中滚动的特定元素。我在下面的示例中通过“ getElementById”获得该元素:

self.driver.execute_script('window.scrollTo(0, document.getElementById("page-manager").scrollHeight);')

例如,在YouTube上就是这种情况。

if you want to scroll within a particular view/frame (WebElement), what you only need to do is to replace “body” with a particular element that you intend to scroll within. i get that element via “getElementById” in the example below:

self.driver.execute_script('window.scrollTo(0, document.getElementById("page-manager").scrollHeight);')

this is the case on YouTube, for example…


回答 14

ScrollTo()功能不再起作用。这是我使用的,效果很好。

driver.execute_script("document.getElementById('mydiv').scrollIntoView();")

The ScrollTo() function doesn’t work anymore. This is what I used and it worked fine.

driver.execute_script("document.getElementById('mydiv').scrollIntoView();")

回答 15

driver.execute_script("document.getElementById('your ID Element').scrollIntoView();")

它适合我的情况。

driver.execute_script("document.getElementById('your ID Element').scrollIntoView();")

it’s working for my case.


WebDriver click()与JavaScript click()

问题:WebDriver click()与JavaScript click()

故事:

在StackOverflow上,我看到用户报告他们无法通过selenium WebDriver“单击”命令单击元素,并且可以通过执行脚本来解决JavaScript单击问题。

Python中的示例:

element = driver.find_element_by_id("myid")
driver.execute_script("arguments[0].click();", element)

WebDriverJS /量角器中的示例:

var elm = $("#myid");
browser.executeScript("arguments[0].click();", elm.getWebElement());

问题:

为什么在常规WebDriver单击不起作用时单击“通过JavaScript”有效?这到底是什么时候发生的,这种解决方法(如果有)的缺点是什么?

我个人使用此变通办法时并未完全理解为什么必须这样做以及它可能导致什么问题。

The Story:

Here on StackOverflow, I’ve seen users reporting that they cannot click an element via selenium WebDriver “click” command and can work around it with a JavaScript click by executing a script.

Example in Python:

element = driver.find_element_by_id("myid")
driver.execute_script("arguments[0].click();", element)

Example in WebDriverJS/Protractor:

var elm = $("#myid");
browser.executeScript("arguments[0].click();", elm.getWebElement());

The Question:

Why is clicking “via JavaScript” works when a regular WebDriver click does not? When exactly is this happening and what is the downside of this workaround (if any)?

I personally used this workaround without fully understanding why I have to do it and what problems it can lead to.


回答 0

当前接受的答案所暗示的相反,关于PhantomJS并没有特定于WebDriver单击和使用JavaScript的区别。

区别

两种方法之间的本质区别是所有浏览器都共有的,可以很简单地解释一下:

  • WebDriver:当WebDriver进行单击时,它会尽可能地尝试模拟真实用户使用浏览器时发生的情况。假设您有一个元素A,它是一个表示“单击我”的按钮,一个元素B是一个div透明的元素,但具有其尺寸和zIndex设置,使其完全覆盖A。然后,您告诉WebDriver单击A。WebDriver将模拟点击,使B 首先获得点击。为什么?因为B涵盖了A,并且如果用户尝试单击A,则B将首先获得该事件。A是否最终会获得click事件取决于B如何处理该事件。无论如何,在这种情况下,WebDriver的行为与真实用户尝试单击A时的行为相同。

  • JavaScript:现在,假设您使用JavaScript来做A.click()这种单击方法不能重现用户尝试单击A时实际发生的情况。JavaScript将click事件直接发送给A,而B将不会获得任何事件。

为什么在WebDriver单击不起作用时JavaScript单击有效?

正如我上面提到的,WebDriver会尽可能地模拟真实用户使用浏览器时发生的情况。事实是,DOM可以包含用户无法与之交互的元素,并且WebDriver不允许您单击这些元素。除了我提到的重叠情况之外,这还意味着无法单击不可见元素。我在“堆栈溢出”问题中看到的一个常见案例是某人试图与DOM中已经存在的GUI元素进行交互,但只有在处理了其他某些元素后才可见。有时在下拉菜单中会发生这种情况:您必须先单击按钮,然后弹出菜单,然后才能选择菜单项。如果有人尝试在菜单可见之前单击菜单项,如果此人随后尝试使用JavaScript进行操作,那么它将起作用,因为事件是直接传递给元素的,而与可见性无关。

什么时候应该使用JavaScript进行点击?

如果您使用Selenium来测试应用程序,那么我对这个问题的回答是“几乎不会”。总的来说,您的Selenium测试应该重现用户对浏览器的操作。以下拉菜单为例:测试应单击首先显示下拉菜单的按钮,然后单击菜单项。如果由于按钮不可见而导致GUI出现问题,或者按钮无法显示菜单项或类似内容,则测试将失败并且您将检测到该错误。如果使用JavaScript单击鼠标,则将无法通过自动测试检测到这些错误。

我说“几乎从不”是因为使用JavaScript可能会有exceptions。但是,它们应该很少见。

如果您使用Selenium 抓取站点,则尝试重现用户行为并不那么重要。因此,使用JavaScript绕过GUI并不是什么大问题。

Contrarily to what the currently accepted answer suggests, there’s nothing specific to PhantomJS when it comes to the difference between having WebDriver do a click and doing it in JavaScript.

The Difference

The essential difference between the two methods is common to all browsers and can be explained pretty simply:

  • WebDriver: When WebDriver does the click, it attempts as best as it can to simulate what happens when a real user uses the browser. Suppose you have an element A which is a button that says “Click me” and an element B which is a div element which is transparent but has its dimensions and zIndex set so that it completely covers A. Then you tell WebDriver to click A. WebDriver will simulate the click so that B receives the click first. Why? Because B covers A, and if a user were to try to click on A, then B would get the event first. Whether or not A would eventually get the click event depends on how B handles the event. At any rate, the behavior with WebDriver in this case is the same as when a real user tries to click on A.

  • JavaScript: Now, suppose you use JavaScript to do A.click(). This method of clicking does not reproduce what really happens when the user tries to click A. JavaScript sends the click event directly to A, and B will not get any event.

Why a JavaScript Click Works When a WebDriver Click Does Not?

As I mentioned above WebDriver will try to simulate as best it can what happens when a real user is using a browser. The fact of the matter is that the DOM can contain elements that a user cannot interact with, and WebDriver won’t allow you to click on these element. Besides the overlapping case I mentioned, this also entails that invisible elements cannot be clicked. A common case I see in Stack Overflow questions is someone who is trying to interact with a GUI element that already exists in the DOM but becomes visible only when some other element has been manipulated. This sometimes happens with dropdown menus: you have to first click on the button the brings up the dropdown before a menu item can be selected. If someone tries to click the menu item before the menu is visible, WebDriver will balk and say that the element cannot be manipulated. If the person then tries to do it with JavaScript, it will work because the event is delivered directly to the element, irrespective of visibility.

When Should You Use JavaScript for Clicking?

If you are using Selenium for testing an application, my answer to this question is “almost never”. By and large, your Selenium test should reproduce what a user would do with the browser. Taking the example of the drop down menu: a test should click on the button that brings up the drop down first, and then click on the menu item. If there is a problem with the GUI because the button is invisible, or the button fails to show the menu items, or something similar, then your test will fail and you’ll have detected the bug. If you use JavaScript to click around, you won’t be able to detect these bugs through automated testing.

I say “almost never” because there may be exceptions where it makes sense to use JavaScript. They should be very rare, though.

If you are using Selenium for scraping sites, then it is not as critical to attempt to reproduce user behavior. So using JavaScript to bypass the GUI is less of an issue.


回答 1

驱动程序执行的单击尝试在JavaScript HTMLElement.click()click事件执行默认操作时,即使元素不可交互,也尽可能模拟真实用户的行为。

不同之处在于:

  • 驱动程序通过将元素滚动到视图中来确保该元素可见,并检查该元素是否可交互

    驱动程序将引发错误:

    • 当点击坐标顶部的元素不是目标元素或后代时
    • 当元素没有正尺寸或完全透明时
    • 当元素是禁用的输入或按​​钮(属性/属性disabledtrue)时
    • 当元素的鼠标指针被禁用(CSS pointer-eventsnone)时


    HTMLElement.click()如果元素被禁用, JavaScript 将始终执行默认操作,或者至多只会静默失败。

  • 如果元素是可聚焦的,则希望驾驶员将其聚焦。

    JavaScript HTMLElement.click()不会。

  • 希望驱动程序像真实用户一样发出所有事件(mousemove,mousedown,mouseup,click等)。

    JavaScript HTMLElement.click()仅发出click事件。该页面可能依赖于这些额外的事件,并且如果未发出这些事件,它们的行为可能会有所不同。

    这些是驱动程序发出的单击Chrome的事件:

    mouseover {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mousemove {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mousedown {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mouseup {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    click {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }

    这是JavaScript注入发出的事件:

    click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
  • JavaScript发出的事件.click() 不受信任,并且默认操作不能被调用:

    https://developer.mozilla.org/zh/docs/Web/API/Event/isTrusted
    https://googlechrome.github.io/samples/event-istrusted/index.html

    请注意,某些驱动程序仍在生成不受信任的事件。从2.1版开始,PhantomJS就是这种情况。

  • JavaScript发出的事件.click() 没有click的坐标

    属性clientX, clientY, screenX, screenY, layerX, layerY设置为0。该页面可能依赖于它们,并且可能会有所不同。


可以使用JavaScript .click()抓取一些数据,但这不是在测试环境中。由于它无法模拟用户的行为,因此无法达到测试的目的。因此,如果来自驱动程序的单击失败,则实际用户很可能也将在相同条件下无法执行相同的单击。


是什么使驱动程序在我们期望成功时无法单击元素?

  • 由于延迟或过渡效果,目标元素尚不可见/不可交互。

    一些例子 :

    https://developer.mozilla.org/fr/docs/Web(下拉导航菜单) http://materializecss.com/side-nav.html(下拉侧栏)

    工作环境:

    添加服务员以等待可见性,最小尺寸或稳定位置:

    // wait visible
    browser.wait(ExpectedConditions.visibilityOf(elem), 5000);
    
    // wait visible and not disabled
    browser.wait(ExpectedConditions.elementToBeClickable(elem), 5000);
    
    // wait for minimum width
    browser.wait(function minimumWidth() {
        return elem.getSize().then(size => size.width > 50);
    }, 5000);

    重试单击直到成功:

    browser.wait(function clickSuccessful() {
        return elem.click().then(() => true, (ex) => false);
    }, 5000);

    添加与动画/过渡的持续时间匹配的延迟:

    browser.sleep(250);


  • 目标元素最终被浮动元素覆盖一旦滚动到视图中:

    驱动程序自动将元素滚动到视图中以使其可见。如果页面包含浮动/粘滞元素(菜单,广告,页脚,通知,Cookie策略..),则该元素可能最终被覆盖,将不再可见/不可交互。

    示例:https//twitter.com/?lang = zh-CN

    解决方法:

    将窗口的大小设置为较大的大小,以避免滚动或浮动元素。

    Y将鼠标移到具有负偏移量的元素上,然后单击它:

      browser.actions()
         .mouseMove(elem, {x: 0, y: -250})
         .click()
         .perform();

    单击之前,将元素滚动到窗口的中心:

    browser.executeScript(function scrollCenter(elem) {
      var win = elem.ownerDocument.defaultView || window,
        box = elem.getBoundingClientRect(),
        dy = box.top - (win.innerHeight - box.height) / 2;
      win.scrollTo(win.pageXOffset, win.pageYOffset + dy);
    }, element);
    
    element.click();

    如果无法避免,请隐藏浮动元素:

    browser.executeScript(function scrollCenter(elem) {
      elem.style.display = 'none';
    }, element);

The click executed by the driver tries to simulate the behavior of a real user as close as possible while the JavaScript HTMLElement.click() performs the default action for the click event, even if the element is not interactable.

The differences are:

  • The driver ensures that the element is visible by scrolling it into the view and checks that the element is interactable.

    The driver will raise an error:

    • when the element on top at the coordinates of the click is not the targeted element or a descendant
    • when the element doesn’t have a positive size or if it is fully transparent
    • when the element is a disabled input or button (attribute/property disabled is true)
    • when the element has the mouse pointer disabled (CSS pointer-events is none)


    A JavaScript HTMLElement.click() will always perform the default action or will at best silently fail if the element is a disabled.

  • The driver is expected to bring the element into focus if it is focusable.

    A JavaScript HTMLElement.click() won’t.

  • The driver is expected to emit all the events (mousemove, mousedown, mouseup, click, …) just like like a real user.

    A JavaScript HTMLElement.click() emits only the click event. The page might rely on these extra events and might behave differently if they are not emitted.

    These are the events emitted by the driver for a click with Chrome:

    mouseover {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mousemove {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mousedown {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mouseup {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    click {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    

    And this is the event emitted with a JavaScript injection:

    click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
    
  • The event emitted by a JavaScript .click() is not trusted and the default action may not be invoked:

    https://developer.mozilla.org/en/docs/Web/API/Event/isTrusted
    https://googlechrome.github.io/samples/event-istrusted/index.html

    Note that some of the drivers are still generating untrusted events. This is the case with PhantomJS as of version 2.1.

  • The event emitted by a JavaScript .click() doesn’t have the coordinates of the click.

    The properties clientX, clientY, screenX, screenY, layerX, layerY are set to 0. The page might rely on them and might behave differently.


It may be ok to use a JavaScript .click() to scrap some data, but it is not in a testing context. It defeats the purpose of the test since it doesn’t simulate the behavior of a user. So, if the click from the driver fails, then a real user will most likely also fail to perform the same click in the same conditions.


What makes the driver fail to click an element when we expect it to succeed?

  • The targeted element is not yet visible/interactable due to a delay or a transition effect.

    Some examples :

    https://developer.mozilla.org/fr/docs/Web (dropdown navigation menu) http://materializecss.com/side-nav.html (dropdown side bar)

    Workarrounds:

    Add a waiter to wait for the visibility, a minimum size or a steady position :

    // wait visible
    browser.wait(ExpectedConditions.visibilityOf(elem), 5000);
    
    // wait visible and not disabled
    browser.wait(ExpectedConditions.elementToBeClickable(elem), 5000);
    
    // wait for minimum width
    browser.wait(function minimumWidth() {
        return elem.getSize().then(size => size.width > 50);
    }, 5000);
    

    Retry to click until it succeeds :

    browser.wait(function clickSuccessful() {
        return elem.click().then(() => true, (ex) => false);
    }, 5000);
    

    Add a delay matching the duration of the animation/transition :

    browser.sleep(250);
    


  • The targeted element ends-up covered by a floating element once scrolled into the view:

    The driver automatically scrolls the element into the view to make it visible. If the page contains a floating/sticky element (menu, ads, footer, notification, cookie policy..), the element may end-up covered and will no longer be visible/interactable.

    Example: https://twitter.com/?lang=en

    Workarounds:

    Set the size of the window to a larger one to avoid the scrolling or the floating element.

    Mover over the element with a negative Y offset and then click it:

      browser.actions()
         .mouseMove(elem, {x: 0, y: -250})
         .click()
         .perform();
    

    Scroll the element to the center of the window before the click:

    browser.executeScript(function scrollCenter(elem) {
      var win = elem.ownerDocument.defaultView || window,
        box = elem.getBoundingClientRect(),
        dy = box.top - (win.innerHeight - box.height) / 2;
      win.scrollTo(win.pageXOffset, win.pageYOffset + dy);
    }, element);
    
    element.click();
    

    Hide the floating element if it can’t be avoided:

    browser.executeScript(function scrollCenter(elem) {
      elem.style.display = 'none';
    }, element);
    

回答 2

注意:我们将“点击”称为最终用户点击。“ js click”是通过JS点击的

为什么在常规WebDriver单击不起作用时单击“通过JavaScript”有效?

有两种情况会发生这种情况:

I. 如果您正在使用PhamtomJS

这是的最常见的已知行为PhantomJS。例如,某些元素有时不可单击<div>。这是因为PhantomJS最初是用来模拟浏览器引擎的(例如初始HTML + CSS->计算CSS->呈现)。但这并不意味着要以最终用户的方式进行交互(查看,单击,拖动)。因此PhamtomJS,最终用户交互仅部分支持。

JS为什么点击工作?至于任一点击,它们都是平均点击。它就像带有1个枪管2个扳机的枪。视口中的一个,JS中的一个。由于可以PhamtomJS很好地模拟浏览器的引擎,因此JS单击应该可以很好地工作。

二。“ click”的事件处理程序必须在糟糕的时间内绑定。

例如,我们得到了一个 <div>

  • ->我们做一些计算

  • ->然后将click事件绑定到<div>

  • ->加上一些错误的角度编码(例如,不能正确处理示波器的周期)

我们可能最终得到相同的结果。单击将不起作用,因为WebdriverJS在没有单击事件处理程序的情况下会尝试单击该元素。

JS为什么点击工作?JS单击就像将JS直接注入浏览器。可能有2种方式,

拳头是通过devtools控制台(是的,WebdriverJS确实与devtools的控制台进行通信)。

其次是将<script>标记直接注入HTML。

对于每个浏览器,其行为将有所不同。但是无论如何,这些方法比单击按钮更复杂。Click正在使用已经存在的内容(最终用户单击),js click正在通过后门。

对于js,单击将显示为异步任务。这与一个复杂的主题“ 浏览器异步任务和CPU任务调度 ”相关(一会儿再读也找不到文章)。简而言之,这主要是因为js click需要等待CPU任务调度周期,并且在click事件绑定后运行速度会变慢。 (当您发现元素有时可单击,有时却不可单击时,您可能会知道这种情况。)

这到底是什么时候发生的,这种解决方法(如果有)的缺点是什么?

=>如上所述,两者都意味着一个目的,但是关于使用哪个入口:

  • 点击:使用默认情况下提供的浏览器。
  • JS click:正在通过后门。

=>对于性能,很难说,因为它依赖于浏览器。但通常:

  • 单击:并不意味着更快,而只是在CPU执行任务的计划列表中签名更高的位置。
  • JS单击:并不意味着速度较慢,而仅是它登录到CPU任务计划列表的最后位置。

=>缺点:

  • 点击:除了您使用PhamtomJS之外,似乎没有其他缺点。
  • JS单击:对健康非常不利。您可能不小心单击了视图中没有的内容。使用此功能时,请确保该元素在那里并且可供查看,然后单击以作为最终用户的观点。

PS,如果您正在寻找解决方案。

  • 使用PhantomJS?我建议改用无头的Chrome。是的,您可以在Ubuntu上无头设置Chrome。事物的运行方式与Chrome一样,但它没有视图,并且像PhantomJS一样没有虫子。
  • 不使用PhamtomJS但仍然有问题吗?我建议使用带有browser.wait()(分度器的ExpectedCondition)(检查此以获得更多信息

(我想简短一点,但结局很糟。与理论有关的任何事情都难以解释…)

NOTE: let’s call ‘click’ is end-user click. ‘js click’ is click via JS

Why is clicking “via JavaScript” works when a regular WebDriver click does not?

There are 2 cases for this to happen:

I. If you are using PhamtomJS

Then this is the most common known behavior of PhantomJS . Some elements are sometimes not clickable, for example <div>. This is because PhantomJS was original made for simulating the engine of browsers (like initial HTML + CSS -> computing CSS -> rendering). But it does not mean to be interacted with as an end user’s way (viewing, clicking, dragging). Therefore PhamtomJS is only partially supported with end-users interaction.

WHY DOES JS CLICK WORK? As for either click, they are all mean click. It is like a gun with 1 barrel and 2 triggers. One from the viewport, one from JS. Since PhamtomJS great in simulating browser’s engine, a JS click should work perfectly.

II. The event handler of “click” got to bind in the bad period of time.

For example, we got a <div>

  • -> We do some calculation

  • -> then we bind event of click to the <div>.

  • -> Plus with some bad coding of angular (e.g. not handling scope’s cycle properly)

We may end up with the same result. Click won’t work, because WebdriverJS trying to click on the element when it has no click event handler.

WHY DOES JS CLICK WORK? Js click is like injecting js directly into the browser. Possible with 2 ways,

Fist is through devtools console (yes, WebdriverJS does communicate with devtools’ console).

Second is inject a <script> tag directly into HTML.

For each browser, the behavior will be different. But regardless, these methods are more complicating than clicking on the button. Click is using what already there (end-users click), js click is going through backdoor.

And for js click will appear to be an asynchronous task. This is related a with a kinda complex topic of ‘browser asynchronous task and CPU task scheduling‘ (read it a while back can’t find the article again). For short this will mostly result as js click will need to wait for a cycle of task scheduling of CPU and it will be ran a bit slower after the binding of the click event. (You could know this case when you found the element sometimes clickable, sometimes not. )

When exactly is this happening and what is the downside of this workaround (if any)?

=> As mention above, both mean for one purpose, but about using which entrance:

  • Click: is using what providing by default of browser.
  • JS click: is going through backdoor.

=> For performance, it is hard to say because it relies on browsers. But generally:

  • Click: doesn’t mean faster but only signed higher position in schedule list of CPU execution task.
  • JS click: doesn’t mean slower but only it signed into the last position of schedule list of CPU task.

=> Downsides:

  • Click: doesn’t seem to have any downside except you are using PhamtomJS.
  • JS click: very bad for health. You may accidentally click on something that doesn’t there on the view. When you use this, make sure the element is there and available to view and click as the point of view of end-user.

P.S. if you are looking for a solution.

  • Using PhantomJS? I will suggest using Chrome headless instead. Yes, you can set up Chrome headless on Ubuntu. Thing runs just like Chrome but it only does not have a view and less buggy like PhantomJS.
  • Not using PhamtomJS but still having problems? I will suggest using ExpectedCondition of Protractor with browser.wait() (check this for more information)

(I want to make it short, but ended up badly. Anything related with theory is complicated to explain…)


如何使用python在Selenium中以编程方式使Firefox无头?

问题:如何使用python在Selenium中以编程方式使Firefox无头?

我正在使用python,selenium和firefox运行此代码,但仍获得firefox的“ head”版本:

binary = FirefoxBinary('C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe', log_file=sys.stdout)
binary.add_command_line_options('-headless')
self.driver = webdriver.Firefox(firefox_binary=binary)

我还尝试了一些二进制的变体:

binary = FirefoxBinary('C:\\Program Files\\Nightly\\firefox.exe', log_file=sys.stdout)
        binary.add_command_line_options("--headless")

I am running this code with python, selenium, and firefox but still get ‘head’ version of firefox:

binary = FirefoxBinary('C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe', log_file=sys.stdout)
binary.add_command_line_options('-headless')
self.driver = webdriver.Firefox(firefox_binary=binary)

I also tried some variations of binary:

binary = FirefoxBinary('C:\\Program Files\\Nightly\\firefox.exe', log_file=sys.stdout)
        binary.add_command_line_options("--headless")

回答 0

要不费吹灰之力地调用Firefox浏览器,可以headless通过以下Options()类设置属性:

from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.headless = True
driver = webdriver.Firefox(options=options, executable_path=r'C:\Utility\BrowserDrivers\geckodriver.exe')
driver.get("http://google.com/")
print ("Headless Firefox Initialized")
driver.quit()

还有另一种方法可以完成无头模式。如果你需要禁用或启用Firefox中的无头模式,而无需修改代码,您可以设置环境变量MOZ_HEADLESS,以什么,如果你想Firefox的运行无头,或根本不设置它。

例如,在使用持续集成并且希望在服务器中运行功能测试但仍能够在PC上以正常模式运行测试时,此功能非常有用。

$ MOZ_HEADLESS=1 python manage.py test # testing example in Django with headless Firefox

要么

$ export MOZ_HEADLESS=1   # this way you only have to set it once
$ python manage.py test functional/tests/directory
$ unset MOZ_HEADLESS      # if you want to disable headless mode

奥托罗

如何配置ChromeDriver通过Selenium以无头模式启动Chrome浏览器?

To invoke Firefox Browser headlessly, you can set the headless property through Options() class as follows:

from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.headless = True
driver = webdriver.Firefox(options=options, executable_path=r'C:\Utility\BrowserDrivers\geckodriver.exe')
driver.get("http://google.com/")
print ("Headless Firefox Initialized")
driver.quit()

There’s another way to accomplish headless mode. If you need to disable or enable the headless mode in Firefox, without changing the code, you can set the environment variable MOZ_HEADLESS to whatever if you want Firefox to run headless, or don’t set it at all.

This is very useful when you are using for example continuous integration and you want to run the functional tests in the server but still be able to run the tests in normal mode in your PC.

$ MOZ_HEADLESS=1 python manage.py test # testing example in Django with headless Firefox

or

$ export MOZ_HEADLESS=1   # this way you only have to set it once
$ python manage.py test functional/tests/directory
$ unset MOZ_HEADLESS      # if you want to disable headless mode

Outro

How to configure ChromeDriver to initiate Chrome browser in Headless mode through Selenium?


回答 1

第一个答案不再起作用。

这对我有用:

from selenium.webdriver.firefox.options import Options as FirefoxOptions
from selenium import webdriver

options = FirefoxOptions()
options.add_argument("--headless")
driver = webdriver.Firefox(options=options)
driver.get("http://google.com")

The first answer does’t work anymore.

This worked for me:

from selenium.webdriver.firefox.options import Options as FirefoxOptions
from selenium import webdriver

options = FirefoxOptions()
options.add_argument("--headless")
driver = webdriver.Firefox(options=options)
driver.get("http://google.com")

回答 2

我的答案:

set_headless(headless=True) is deprecated. 

https://seleniumhq.github.io/selenium/docs/api/py/webdriver_firefox/selenium.webdriver.firefox.options.html

options.headless = True

为我工作

My answer:

set_headless(headless=True) is deprecated. 

https://seleniumhq.github.io/selenium/docs/api/py/webdriver_firefox/selenium.webdriver.firefox.options.html

options.headless = True

works for me


回答 3

只是为以后可能会发现此问题的人提供的注释(并希望使用java的方法来实现此目的);FirefoxOptions还能够启用无头模式:

FirefoxOptions firefoxOptions = new FirefoxOptions();
firefoxOptions.setHeadless(true);

Just a note for people who may have found this later (and want java way of achieving this); FirefoxOptions is also capable of enabling the headless mode:

FirefoxOptions firefoxOptions = new FirefoxOptions();
firefoxOptions.setHeadless(true);

回答 4

Used below code to set driver type based on need of Headless / Head for both Firefox and chrome:

// Can pass browser type 

if brower.lower() == 'chrome':
    driver = webdriver.Chrome('..\drivers\chromedriver')
elif brower.lower() == 'headless chrome':
    ch_Options = Options()
    ch_Options.add_argument('--headless')
    ch_Options.add_argument("--disable-gpu")
    driver = webdriver.Chrome('..\drivers\chromedriver',options=ch_Options)
elif brower.lower() == 'firefox':
    driver = webdriver.Firefox(executable_path=r'..\drivers\geckodriver.exe')
elif brower.lower() == 'headless firefox':
    ff_option = FFOption()
    ff_option.add_argument('--headless')
    ff_option.add_argument("--disable-gpu")
    driver = webdriver.Firefox(executable_path=r'..\drivers\geckodriver.exe', options=ff_option)
elif brower.lower() == 'ie':
    driver = webdriver.Ie('..\drivers\IEDriverServer')
else:
    raise Exception('Invalid Browser Type')
Used below code to set driver type based on need of Headless / Head for both Firefox and chrome:

// Can pass browser type 

if brower.lower() == 'chrome':
    driver = webdriver.Chrome('..\drivers\chromedriver')
elif brower.lower() == 'headless chrome':
    ch_Options = Options()
    ch_Options.add_argument('--headless')
    ch_Options.add_argument("--disable-gpu")
    driver = webdriver.Chrome('..\drivers\chromedriver',options=ch_Options)
elif brower.lower() == 'firefox':
    driver = webdriver.Firefox(executable_path=r'..\drivers\geckodriver.exe')
elif brower.lower() == 'headless firefox':
    ff_option = FFOption()
    ff_option.add_argument('--headless')
    ff_option.add_argument("--disable-gpu")
    driver = webdriver.Firefox(executable_path=r'..\drivers\geckodriver.exe', options=ff_option)
elif brower.lower() == 'ie':
    driver = webdriver.Ie('..\drivers\IEDriverServer')
else:
    raise Exception('Invalid Browser Type')

Python Selenium访问HTML源

问题:Python Selenium访问HTML源

如何使用Selenium模块和Python在变量中获取HTML源代码?

我想做这样的事情:

from selenium import webdriver

browser = webdriver.Firefox()
browser.get("http://example.com")
if "whatever" in html_source:
    # Do something
else:
    # Do something else

我怎样才能做到这一点?我不知道如何访问HTML源。

How can I get the HTML source in a variable using the Selenium module with Python?

I wanted to do something like this:

from selenium import webdriver

browser = webdriver.Firefox()
browser.get("http://example.com")
if "whatever" in html_source:
    # Do something
else:
    # Do something else

How can I do this? I don’t know how to access the HTML source.


回答 0

您需要访问page_source属性:

from selenium import webdriver

browser = webdriver.Firefox()
browser.get("http://example.com")

html_source = browser.page_source
if "whatever" in html_source:
    # do something
else:
    # do something else

You need to access the page_source property:

from selenium import webdriver

browser = webdriver.Firefox()
browser.get("http://example.com")

html_source = browser.page_source
if "whatever" in html_source:
    # do something
else:
    # do something else

回答 1

借助Selenium2Library,您可以使用 get_source()

import Selenium2Library
s = Selenium2Library.Selenium2Library()
s.open_browser("localhost:7080", "firefox")
source = s.get_source()

With Selenium2Library you can use get_source()

import Selenium2Library
s = Selenium2Library.Selenium2Library()
s.open_browser("localhost:7080", "firefox")
source = s.get_source()

回答 2

driver.page_source将帮助您获取页面源代码。您可以检查页面源中是否存在文本。

from selenium import webdriver
driver = webdriver.Firefox()
driver.get("some url")
if "your text here" in driver.page_source:
    print('Found it!')
else:
    print('Did not find it.')

如果要将页面源存储在变量中,请在driver.get之后添加以下行:

var_pgsource=driver.page_source

并将if条件更改为:

if "your text here" in var_pgsource:

driver.page_source will help you get the page source code. You can check if the text is present in the page source or not.

from selenium import webdriver
driver = webdriver.Firefox()
driver.get("some url")
if "your text here" in driver.page_source:
    print('Found it!')
else:
    print('Did not find it.')

If you want to store the page source in a variable, add below line after driver.get:

var_pgsource=driver.page_source

and change the if condition to:

if "your text here" in var_pgsource:

回答 3

通过使用页面源,您将获得完整的HTML代码。
因此,首先确定需要检索数据或单击元素的代码或标记块。

options = driver.find_elements_by_name_("XXX")
for option in options:
    if option.text == "XXXXXX":
        print(option.text)
        option.click()

您可以按名称,XPath,ID,链接和CSS路径找到元素。

By using the page source you will get the whole HTML code.
So first decide the block of code or tag in which you require to retrieve the data or to click the element..

options = driver.find_elements_by_name_("XXX")
for option in options:
    if option.text == "XXXXXX":
        print(option.text)
        option.click()

You can find the elements by name, XPath, id, link and CSS path.


回答 4

要回答有关获取用于urllib 的URL的问题,只需执行以下JavaScript代码:

url = browser.execute_script("return window.location;")

To answer your question about getting the URL to use for urllib, just execute this JavaScript code:

url = browser.execute_script("return window.location;")

回答 5

您可以简单地使用该WebDriver对象,并通过其@property字段访问页面源代码page_source

试试这个代码片段:-)

from selenium import webdriver
driver = webdriver.Firefox('path/to/executable')
driver.get('https://some-domain.com')
source = driver.page_source
if 'stuff' in source:
    print('found...')
else:
    print('not in source...')

You can simply use the WebDriver object, and access to the page source code via its @property field page_source

Try this code snippet :-)

from selenium import webdriver
driver = webdriver.Firefox('path/to/executable')
driver.get('https://some-domain.com')
source = driver.page_source
if 'stuff' in source:
    print('found...')
else:
    print('not in source...')

回答 6

from bs4 import BeautifulSoup
from selenium import webdriver

driver = webdriver.Chrome()
html_source_code = driver.execute_script("return document.body.innerHTML;")
html_soup: BeautifulSoup = BeautifulSoup(html_source_code, 'html.parser')

现在您可以应用BeautifulSoup函数来提取数据…

from bs4 import BeautifulSoup
from selenium import webdriver

driver = webdriver.Chrome()
html_source_code = driver.execute_script("return document.body.innerHTML;")
html_soup: BeautifulSoup = BeautifulSoup(html_source_code, 'html.parser')

Now you can apply BeautifulSoup function to extract data…


回答 7

我建议使用urllib获取源代码,如果要解析,请使用Beautiful Soup之类的东西。

import urllib

url = urllib.urlopen("http://example.com") # Open the URL.
content = url.readlines() # Read the source and save it to a variable.

I’d recommend getting the source with urllib and, if you’re going to parse, use something like Beautiful Soup.

import urllib

url = urllib.urlopen("http://example.com") # Open the URL.
content = url.readlines() # Read the source and save it to a variable.

Selenium:FirefoxProfile异常无法加载配置文件

问题:Selenium:FirefoxProfile异常无法加载配置文件

对于这个先前的问题,我将Selenium更新到了2.0.1版本,但是现在我又遇到了另一个错误,即使配置文件位于以下位置/tmp/webdriver-py-profilecopy

  在执行中,文件“ /home/sultan/Repository/Django/monitor/app/request.py”,第236行
    浏览器= Firefox(配置文件)
  __init__中的文件“ /usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/webdriver.py”,第46行
    self.binary,超时),
  __init__中的文件“ /usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/extension_connection.py”,第46行
    self.binary.launch_browser(self.profile)
  在launch_browser中的第44行,文件“ /usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/firefox_binary.py”
    self._wait_until_connectable() 
  _wait_until_connectable中的文件“ /usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/firefox_binary.py”,第87行
    引发WebDriverException(“无法加载配置文件。配置文件目录:%s”%self.profile.path)
selenium.common.exceptions.WebDriverException:无法加载配置文件。个人档案目录:/ tmp / webdriver-py-profilecopy

怎么了?我该如何解决这个问题?

Per this previous question I updated Selenium to version 2.0.1 But now I have another error, even when the profile files exist under /tmp/webdriver-py-profilecopy:

  File "/home/sultan/Repository/Django/monitor/app/request.py", line 236, in perform
    browser = Firefox(profile)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/webdriver.py", line 46, in __init__
    self.binary, timeout),
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/extension_connection.py", line 46, in __init__
    self.binary.launch_browser(self.profile)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/firefox_binary.py", line 44, in launch_browser
    self._wait_until_connectable() 
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/firefox_binary.py", line 87, in _wait_until_connectable
    raise WebDriverException("Can't load the profile. Profile Dir : %s" % self.profile.path)
selenium.common.exceptions.WebDriverException: Can't load the profile. Profile Dir : /tmp/webdriver-py-profilecopy

What is wrong? How can I resolve this issue?


回答 0

更新:

硒团队已修复最新版本。对于几乎所有环境,修复程序都是:

点安装-U硒

尚不清楚它是在哪个版本上修复的(显然是r13122),但肯定是在2.26.0(更新时为最新)上已修复。


此错误意味着_wait_until_connectable超时,因为某些原因,代码无法连接到已加载到firefox中的webdriver扩展。

我刚刚向selenium报告了一个错误,在此我收到此错误,因为我正尝试使用代理,并且firefox接受了配置文件中4个配置的更改中的2个,因此未配置该代理与扩展名。不知道为什么会这样…

https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/2061

Update:

Selenium team fixed in latest version. For almost all environments the fix is:

pip install -U selenium

Unclear at which version it was fixed (apparently r13122), but certainly by 2.26.0 (current at time of update) it is fixed.


This error means that _wait_until_connectable is timing out, because for some reason, the code cannot connect to the webdriver extension that has been loaded into the firefox.

I have just reported an error to selenium where I am getting this error because I’m trying to use a proxy and only 2 of the 4 configured changes in the profile have been accepted by firefox, so the proxy isn’t configured to talk to the extension. Not sure why this is happening…

https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/2061


回答 1

将Ubuntu升级到12.04后,我遇到了同样的问题。

该问题在软件包方面,已在库的最新版本中修复。只需更新硒库。对于几乎所有的Python环境,这是:

pip install -U selenium

I had the same issue after upgrading Ubuntu to 12.04.

The issue was on the package side and has been fixed in the latest version of the library. Just update the selenium library. For almost all Python environments this is:

pip install -U selenium

回答 2

我遇到了FF 32.0和Selenium selenium-2.42.1-py2.7.egg相同的问题。试图更新硒,但是它已经是最新版本。解决方案是将Firefox降级到版本30。过程如下:

#Download version 30 for Linux (This is the 64 bit)
wget http://ftp.mozilla.org/pub/mozilla.org/firefox/releases/30.0/linux-x86_64/en-US/firefox-30.0.tar.bz2

tar -xjvf firefox-30.0.tar.bz2
#Remove the old version
sudo rm -rf /opt/firefox*
sudo mv firefox /opt/firefox30.0
#Create a permanent link
sudo ln -sf /opt/firefox30.0/firefox /usr/bin/firefox

这样就解决了所有问题,并且这种组合效果更好!

I faced the same problem with FF 32.0 and Selenium selenium-2.42.1-py2.7.egg. Tried to update selenium, but it is already the latest version. The solution was to downgrade Firefox to version 30. Here is the process:

#Download version 30 for Linux (This is the 64 bit)
wget http://ftp.mozilla.org/pub/mozilla.org/firefox/releases/30.0/linux-x86_64/en-US/firefox-30.0.tar.bz2

tar -xjvf firefox-30.0.tar.bz2
#Remove the old version
sudo rm -rf /opt/firefox*
sudo mv firefox /opt/firefox30.0
#Create a permanent link
sudo ln -sf /opt/firefox30.0/firefox /usr/bin/firefox

This solved all the problems, and this combination works better !


回答 3

作为对Jeff Hoye答案的扩展,一种更“ Pythonic”的方式将是webdriver.firefox.firefox_profile.FirefoxProfile如下子类化:

class CygwinFirefoxProfile(FirefoxProfile):
    @property
    def path(self):
        path = self.profile_dir
        # Do stuff to the path as described in Jeff Hoye's answer
        return path

然后,创建驱动程序:

driver = webdriver.Firefox(firefox_profile=CygwinFirefoxProfile())

As an extension to Jeff Hoye‘s answer, a more ‘Pythonic’ way would be to subclass webdriver.firefox.firefox_profile.FirefoxProfile as follows:

class CygwinFirefoxProfile(FirefoxProfile):
    @property
    def path(self):
        path = self.profile_dir
        # Do stuff to the path as described in Jeff Hoye's answer
        return path

Then, to create your driver:

driver = webdriver.Firefox(firefox_profile=CygwinFirefoxProfile())

回答 4

如果pip install -U selenium不起作用(就我而言,它不起作用),请尝试将Firefox降级到以前的版本。

我安装了Firefox 49.0,并降级到45.0,以确保selenium支持该版本。那时,它工作得很好。

这是降级到Firefox 45.0的快速方法:

sudo apt-get install firefox=45.0.2+build1-0ubuntu1

希望这可以帮助。

If pip install -U selenium doesn’t work (it didn’t, in my case), try downgrading your Firefox to a previous version.

I had Firefox 49.0 and downgraded to 45.0 to make sure the version is supported by selenium. It worked perfectly then.

Here’s a fast way to downgrade to Firefox 45.0:

sudo apt-get install firefox=45.0.2+build1-0ubuntu1

Hope this helps.


回答 5

如果您从cygwin运行webdriver,则问题在于配置文件的路径仍为POSIX格式,这会混淆Windows程序。我的解决方案使用cygpath将其转换为Windows格式。

在此文件/方法中:selenium.webdriver.firefox.firefox_binary.launch_browser():

更换:

    self._start_from_profile_path(self.profile.path)

与:

    from subprocess import Popen, PIPE
    proc = Popen(['cygpath','-d',self.profile.path], stdout=PIPE, stderr=PIPE)
    stdout, stderr = proc.communicate()
    path = stdout.split('\n', 1)[0]

    self._start_from_profile_path(path)
    #self._start_from_profile_path(self.profile.path)

由于Python甚至与我的主要编程语言都不接近,因此如果有人可以推荐一种更Python化的方法,也许我们可以将其推入发行版。如果它在开箱即用的Cygwin中工作肯定会很方便。

If you are running webdriver from cygwin, the problem is that the path to the profile is still in POSIX format which confuses windows programs. My solution uses cygpath to convert it into Windows format.

in this file/method: selenium.webdriver.firefox.firefox_binary.launch_browser():

replace:

    self._start_from_profile_path(self.profile.path)

with:

    from subprocess import Popen, PIPE
    proc = Popen(['cygpath','-d',self.profile.path], stdout=PIPE, stderr=PIPE)
    stdout, stderr = proc.communicate()
    path = stdout.split('\n', 1)[0]

    self._start_from_profile_path(path)
    #self._start_from_profile_path(self.profile.path)

Since Python is not even close to my primary programming language, if someone can recommend a more pythonic approach maybe we can push it into the distribution. It sure would be handy if it worked in cygwin right out of the box.


回答 6

我遇到了同样的问题,并认为这是硒/ Firefox的错误组合。原来,我的.mozilla /文件夹权限仅可由root用户访问。做的chmod 770 ~/.mozilla/did俩。我建议在进一步排除故障之前确保这不是问题。

I had the same problem and believed it was the wrong combo of selenium / Firefox. Turned out that my .mozilla/ folder permissions were only accessible to the root user. Doing chmod 770 ~/.mozilla/ did the trick. I would suggest making sure this is not the issue before troubleshooting further.


回答 7

pip install -U selenium

我遇到了相同的问题,Firefox 34.0.5 (Dec 1, 2014)并将Selenium从升级2.42.12.44.0解决了我的问题。

但是,此后我又看到了这个问题,我认为是2.44.0,并进行了另一次升级。因此,我想知道是否可以通过简单地卸载然后重新安装来解决该问题。如果是这样,我不确定那将表明潜在的问题是什么。

pip install -U selenium

I had this same issue with Firefox 34.0.5 (Dec 1, 2014) and upgrading Selenium from 2.42.1 to 2.44.0 resolved my issue.

However, I’ve have since seen this issue again, I think with 2.44.0, and another upgrade fixed it. So I’m wondering if it might be fixed by simply uninstalling and then re-installing. If so, I’m not sure what that would indicate the underlying problem is.


回答 8

我正在使用硒2.53和55.0版的Firefox。我安装了较旧版本的firefox(46.0.1)解决了此问题,因为硒2.53不适用于47.0及更高版本的firefox。

I was using selenium 2.53 and firefox version 55.0. I solved this issue by installing the older version of firefox (46.0.1) since selenium 2.53 will not work for firefox version 47.0 & above.


回答 9

这不是一个适当的解决方案,但对我有用,如果有人可以改善,我将很高兴知道。我只是以root用户身份运行脚本sudo python myscript.py。我想我可以通过更改配置文件默认文件或目录来解决。

This is not a proper solution but worked for me, if somebody can improve I would be glad to know. I just run my script as root: sudo python myscript.py. I guess I can solve by changing the profile default file or directory could work.


获取Selenium中Javascript代码的返回值

问题:获取Selenium中Javascript代码的返回值

我正在使用Selenium2对我的网站进行一些自动化测试,并且希望能够获得一些Javascript代码的返回值。如果我的foobar()网页中有Javascript函数,并且想调用该函数并将返回值获取到我的Python代码中,该怎么做?

I’m using Selenium2 for some automated tests of my website, and I’d like to be able to get the return value of some Javascript code. If I have a foobar() Javascript function in my webpage and I want to call that and get the return value into my Python code, what can I call to do that?


回答 0

要返回值,只需return在传递给execute_script()方法的字符串中使用JavaScript关键字,例如

>>> from selenium import webdriver
>>> wd = webdriver.Firefox()
>>> wd.get("http://localhost/foo/bar")
>>> wd.execute_script("return 5")
5
>>> wd.execute_script("return true")
True
>>> wd.execute_script("return {foo: 'bar'}")
{u'foo': u'bar'}
>>> wd.execute_script("return foobar()")
u'eli'

To return a value, simply use the return JavaScript keyword in the string passed to the execute_script() method, e.g.

>>> from selenium import webdriver
>>> wd = webdriver.Firefox()
>>> wd.get("http://localhost/foo/bar")
>>> wd.execute_script("return 5")
5
>>> wd.execute_script("return true")
True
>>> wd.execute_script("return {foo: 'bar'}")
{u'foo': u'bar'}
>>> wd.execute_script("return foobar()")
u'eli'

回答 1

即使您没有像下面的示例代码中那样将代码的片段作为函数编写,也可以通过return var;在最后添加var是要返回的变量的方式来返回值。

result = driver.execute_script('''cells = document.querySelectorAll('a');
URLs = []
console.log(cells);
[].forEach.call(cells, function (el) {
    if(el.text.indexOf("download") !== -1){
    //el.click();
    console.log(el.href)
    //window.open(el.href, '_blank');
    URLs.push(el.href)
    }
});
return URLs''')

result将包含在URLs这种情况下的数组。

You can return values even if you don’t have your snipped of code written as a function like in the below example code, by just adding return var; at the end where var is the variable you want to return.

result = driver.execute_script('''
cells = document.querySelectorAll('a');
URLs = [];
[].forEach.call(cells, function (el) {
    URLs.push(el.href)
});
return URLs
''')

result will contain the array that is in URLs this case.


如何在Selenium Webdriver 2 Python中获取当前URL?

问题:如何在Selenium Webdriver 2 Python中获取当前URL?

我试图在Selenium中进行一系列导航后获取当前的URL。我知道红宝石有一个名为getLocation的命令,但是我找不到Python的语法。

I’m trying to get the current url after a series of navigations in Selenium. I know there’s a command called getLocation for ruby, but I can’t find the syntax for Python.


回答 0

使用current_url元素。例:

print browser.current_url

Use current_url element for Python 2:

print browser.current_url

For Python 3 and later versions of selenium:

print(driver.current_url)

回答 1

根据此文档(一个放置好东西的地方:)):

driver.current_url

或者,请参阅官方文档:https : //seleniumhq.github.io/docs/site/en/webdriver/browser_manipulation/#get-current-url

According to this documentation (a place full of goodies:)):

driver.current_url

or, see official documentation: https://seleniumhq.github.io/docs/site/en/webdriver/browser_manipulation/#get-current-url


回答 2

Selenium2Library具有get_location():

import Selenium2Library
s = Selenium2Library.Selenium2Library()
url = s.get_location()

Selenium2Library has get_location():

import Selenium2Library
s = Selenium2Library.Selenium2Library()
url = s.get_location()

回答 3

另一种方法是检查chrome中的网址栏,找到该元素的id,让WebDriver单击该元素,然后使用selenium中的通用键功能发送用于复制和粘贴的键,然后打印出来或将其存储为变量等。

Another way to do it would be to inspect the url bar in chrome to find the id of the element, have your WebDriver click that element, and then send the keys you use to copy and paste using the keys common function from selenium, and then printing it out or storing it as a variable, etc.


用硒清除textarea中的文本

问题:用硒清除textarea中的文本

我进行了一些测试,这些测试用于检查某些字段中的文本无效时是否出现了正确的错误消息。有效性检查之一是某个textarea元素不为空。

如果此文本区域中已经有文本,我如何告诉硒清除该字段?

就像是:

driver.get_element_by_id('foo').clear_field()

I’ve got some tests where I’m checking that the proper error message appears when text in certain fields are invalid. One check for validity is that a certain textarea element is not empty.

If this textarea already has text in it, how can I tell selenium to clear the field?

something like:

driver.get_element_by_id('foo').clear_field()

回答 0

driver.find_element_by_id('foo').clear()
driver.find_element_by_id('foo').clear()

回答 1

您可以使用

 webElement.clear();

如果此元素是文本输入元素,则将清除该值。

请注意,此事件引发的事件可能与您预期的不同。特别是,我们不会触发任何键盘或鼠标事件。如果您想确保触发了键盘事件,请考虑使用sendKeys(CharSequence)。例如:

 webElement.sendKeys(Keys.BACK_SPACE); //do repeatedly, e.g. in while loop

要么:

 webElement.sendKeys(Keys.CONTROL + "a");
 webElement.sendKeys(Keys.DELETE);

You can use

 webElement.clear();

If this element is a text entry element, this will clear the value.

Note that the events fired by this event may not be as you’d expect. In particular, we don’t fire any keyboard or mouse events. If you want to ensure keyboard events are fired, consider using something like sendKeys(CharSequence). E.g.:

 webElement.sendKeys(Keys.BACK_SPACE); //do repeatedly, e.g. in while loop

or:

 webElement.sendKeys(Keys.CONTROL + "a");
 webElement.sendKeys(Keys.DELETE);

回答 2

我遇到了.clear()无法正常工作的领域。结合使用前两个答案可解决此问题。

from selenium.webdriver.common.keys import Keys

#...your code (I was using python 3)

driver.find_element_by_id('foo').send_keys(Keys.CONTROL + "a");
driver.find_element_by_id('foo').send_keys(Keys.DELETE);

I ran into a field where .clear() did not work. Using a combination of the first two answers worked for this field.

from selenium.webdriver.common.keys import Keys

#...your code (I was using python 3)

driver.find_element_by_id('foo').send_keys(Keys.CONTROL + "a");
driver.find_element_by_id('foo').send_keys(Keys.DELETE);

回答 3

在最新的Selenium版本中,使用:

driver.find_element_by_id('foo').clear()

In the most recent Selenium version, use:

driver.find_element_by_id('foo').clear()

回答 4

对于java

driver.findelement(By.id('foo').clear();

要么

webElement.clear();

如果此元素是文本输入元素,则将清除该值。

for java

driver.findelement(By.id('foo').clear();

or

webElement.clear();

If this element is a text entry element, this will clear the value.


回答 5

这是一般语法

driver.find_element_by_id('Locator value').clear();
driver.find_element_by_name('Locator value').clear();

It is general syntax

driver.find_element_by_id('Locator value').clear();
driver.find_element_by_name('Locator value').clear();

回答 6

通过对clear()的简单调用,在DOM中就会出现相应的输入/文本区域组件仍具有其旧值的情况,因此对该组件进行的任何后续更改(例如,用新值填充该组件)都不会及时得到处理。

如果看一下硒源代码,您会发现clear()方法记录在案并带有以下注释:

/ **如果此元素是文本输入元素,则将清除该值。对其他元素没有影响。文本输入元素是INPUT和TEXTAREA元素。请注意,此事件引发的事件可能与您预期的不同。特别是,我们不会触发任何键盘或鼠标事件。如果要确保触发键盘事件,请考虑将{@link #sendKeys(CharSequence …)}之类的键与退格键一起使用。为确保您收到更改事件,请考虑使用Tab键跟随对{@link #sendKeys(CharSequence …)}的调用。* /

因此,使用此有用的提示来清除输入/文本区域(已经具有值的组件)并为其分配新的值,您将获得如下代码:

public void waitAndClearFollowedByKeys(By by, CharSequence keys) {
    LOG.debug("clearing element");
    wait(by, true).clear();
    sendKeys(by, Keys.BACK_SPACE.toString() + keys);
}

public void sendKeys(By by, CharSequence keysToSend) {
    WebElement webElement = wait(by, true);
    LOG.info("sending keys '{}' to {}", escapeProperly(keysToSend), by);
    webElement.sendKeys(keysToSend);
    LOG.info("keys sent");
}

private String escapeProperly(CharSequence keysToSend) {
    String result = "" + keysToSend;
    result = result.replace(Keys.TAB, "\\t");
    result = result.replace(Keys.ENTER, "\\n");
    result = result.replace(Keys.RETURN, "\\r");

    return result;
}

抱歉,此代码是Java而不是Python。另外,我还不得不跳过其他的“ waitUntilPageIsReady()-方法,这会使这篇文章过长。

希望这对您在硒的旅途中有所帮助!

With a simple call of clear() it appears in the DOM that the corresponding input/textarea component still has its old value, so any following changes on that component (e.g. filling the component with a new value) will not be processed in time.

If you take a look in the selenium source code you’ll find that the clear()-method is documented with the following comment:

/** If this element is a text entry element, this will clear the value. Has no effect on other elements. Text entry elements are INPUT and TEXTAREA elements. Note that the events fired by this event may not be as you’d expect. In particular, we don’t fire any keyboard or mouse events. If you want to ensure keyboard events are fired, consider using something like {@link #sendKeys(CharSequence…)} with the backspace key. To ensure you get a change event, consider following with a call to {@link #sendKeys(CharSequence…)} with the tab key. */

So using this helpful hint to clear an input/textarea (component that already has a value) AND assign a new value to it, you’ll get some code like the following:

public void waitAndClearFollowedByKeys(By by, CharSequence keys) {
    LOG.debug("clearing element");
    wait(by, true).clear();
    sendKeys(by, Keys.BACK_SPACE.toString() + keys);
}

public void sendKeys(By by, CharSequence keysToSend) {
    WebElement webElement = wait(by, true);
    LOG.info("sending keys '{}' to {}", escapeProperly(keysToSend), by);
    webElement.sendKeys(keysToSend);
    LOG.info("keys sent");
}

private String escapeProperly(CharSequence keysToSend) {
    String result = "" + keysToSend;
    result = result.replace(Keys.TAB, "\\t");
    result = result.replace(Keys.ENTER, "\\n");
    result = result.replace(Keys.RETURN, "\\r");

    return result;
}

Sorry for this code being Java and not Python. Also, I had to skip out an additional “waitUntilPageIsReady()-method that would make this post way too long.

Hope this helps you on your journey with Selenium!


回答 7

以我的经验,这是最有效的

driver.find_element_by_css_selector('foo').send_keys(u'\ue009' + u'\ue003')

我们正在发送Ctrl +退格键以删除输入中的所有字符,您也可以使用delete替换退格键。

编辑:删除键依赖

In my experience, this turned out to be the most efficient

driver.find_element_by_css_selector('foo').send_keys(u'\ue009' + u'\ue003')

We are sending Ctrl + Backspace to delete all characters from the input, you can also replace backspace with delete.

EDIT: removed Keys dependency


回答 8

driver.find_element_by_xpath("path").send_keys(Keys.CONTROL + u'\ue003') 与FireFox一起工作得很好

  • u’\ ue003’对像我这样的人来说是BACK_SPACE-永远不会记住它)

driver.find_element_by_xpath("path").send_keys(Keys.CONTROL + u'\ue003') worked great with FireFox

  • u’\ue003′ is a BACK_SPACE for those like me – never remembering it)

如何使用Python使用Selenium选择下拉菜单值?

问题:如何使用Python使用Selenium选择下拉菜单值?

我需要从中选择一个元素 下拉菜单中。

例如:

<select id="fruits01" class="select" name="fruits">
  <option value="0">Choose your fruits:</option>
  <option value="1">Banana</option>
  <option value="2">Mango</option>
</select>

1)首先,我必须单击它。我这样做:

inputElementFruits = driver.find_element_by_xpath("//select[id='fruits']").click()

2)之后,我必须选择一个好的元素,让我们说Mango

我尝试这样做,inputElementFruits.send_keys(...)但是没有用。

I need to select an element from a drop-down menu.

For example:

<select id="fruits01" class="select" name="fruits">
  <option value="0">Choose your fruits:</option>
  <option value="1">Banana</option>
  <option value="2">Mango</option>
</select>

1) First I have to click on it. I do this:

inputElementFruits = driver.find_element_by_xpath("//select[id='fruits']").click()

2) After that I have to select the good element, lets say Mango.

I tried to do it with inputElementFruits.send_keys(...) but it did not work.


回答 0

除非您的点击触发了某种Ajax调用来填充列表,否则您实际上不需要执行该点击。

只需找到元素,然后枚举选项,然后选择所需的选项即可。

这是一个例子:

from selenium import webdriver
b = webdriver.Firefox()
b.find_element_by_xpath("//select[@name='element_name']/option[text()='option_text']").click()

您可以在以下网址中阅读更多内容:https :
//sqa.stackexchange.com/questions/1355/unable-to-select-an-option-using-seleniums-python-webdriver

Unless your click is firing some kind of ajax call to populate your list, you don’t actually need to execute the click.

Just find the element and then enumerate the options, selecting the option(s) you want.

Here is an example:

from selenium import webdriver
b = webdriver.Firefox()
b.find_element_by_xpath("//select[@name='element_name']/option[text()='option_text']").click()

You can read more in:
https://sqa.stackexchange.com/questions/1355/unable-to-select-an-option-using-seleniums-python-webdriver


回答 1

Selenium提供了一个方便的Select来使用select -> option构造:

from selenium import webdriver
from selenium.webdriver.support.ui import Select

driver = webdriver.Firefox()
driver.get('url')

select = Select(driver.find_element_by_id('fruits01'))

# select by visible text
select.select_by_visible_text('Banana')

# select by value 
select.select_by_value('1')

也可以看看:

Selenium provides a convenient Select class to work with select -> option constructs:

from selenium import webdriver
from selenium.webdriver.support.ui import Select

driver = webdriver.Firefox()
driver.get('url')

select = Select(driver.find_element_by_id('fruits01'))

# select by visible text
select.select_by_visible_text('Banana')

# select by value 
select.select_by_value('1')

See also:


回答 2

首先,您需要导入Select类,然后创建Select类的实例。创建Select类的实例后,您可以对该实例执行select方法以从下拉列表中选择选项。这是代码

from selenium.webdriver.support.select import Select

select_fr = Select(driver.find_element_by_id("fruits01"))
select_fr.select_by_index(0)

firstly you need to import the Select class and then you need to create the instance of Select class. After creating the instance of Select class, you can perform select methods on that instance to select the options from dropdown list. Here is the code

from selenium.webdriver.support.select import Select

select_fr = Select(driver.find_element_by_id("fruits01"))
select_fr.select_by_index(0)

回答 3

希望这段代码对您有所帮助。

from selenium.webdriver.support.ui import Select

ID为下拉列表的元素

ddelement= Select(driver.find_element_by_id('id_of_element'))

带xpath的下拉元素

ddelement= Select(driver.find_element_by_xpath('xpath_of_element'))

带CSS选择器的下拉元素

ddelement= Select(driver.find_element_by_css_selector('css_selector_of_element'))

从下拉列表中选择“香蕉”

  1. 使用下拉索引

ddelement.select_by_index(1)

  1. 使用下拉菜单的值

ddelement.select_by_value('1')

  1. 您可以使用匹配显示在下拉菜单中的文本。

ddelement.select_by_visible_text('Banana')

I hope this code will help you.

from selenium.webdriver.support.ui import Select

dropdown element with id

ddelement= Select(driver.find_element_by_id('id_of_element'))

dropdown element with xpath

ddelement= Select(driver.find_element_by_xpath('xpath_of_element'))

dropdown element with css selector

ddelement= Select(driver.find_element_by_css_selector('css_selector_of_element'))

Selecting ‘Banana’ from a dropdown

  1. Using the index of dropdown

ddelement.select_by_index(1)

  1. Using the value of dropdown

ddelement.select_by_value('1')

  1. You can use match the text which is displayed in the drop down.

ddelement.select_by_visible_text('Banana')


回答 4

我尝试了很多事情,但下拉菜单位于表内,因此我无法执行简单的选择操作。仅以下解决方案有效。在这里,我突出显示下拉元素并按下箭头,直到获得所需的值-

        #identify the drop down element
        elem = browser.find_element_by_name(objectVal)
        for option in elem.find_elements_by_tag_name('option'):
            if option.text == value:
                break

            else:
                ARROW_DOWN = u'\ue015'
                elem.send_keys(ARROW_DOWN)

I tried a lot many things, but my drop down was inside a table and I was not able to perform a simple select operation. Only the below solution worked. Here I am highlighting drop down elem and pressing down arrow until getting the desired value –

        #identify the drop down element
        elem = browser.find_element_by_name(objectVal)
        for option in elem.find_elements_by_tag_name('option'):
            if option.text == value:
                break

            else:
                ARROW_DOWN = u'\ue015'
                elem.send_keys(ARROW_DOWN)

回答 5

您无需单击任何内容。使用xpath或任何您选择的方式查找,然后使用发送键

例如:HTML:

<select id="fruits01" class="select" name="fruits">
    <option value="0">Choose your fruits:</option>
    <option value="1">Banana</option>
    <option value="2">Mango</option>
</select>

Python:

fruit_field = browser.find_element_by_xpath("//input[@name='fruits']")
fruit_field.send_keys("Mango")

而已。

You don’t have to click anything. Use find by xpath or whatever you choose and then use send keys

For your example: HTML:

<select id="fruits01" class="select" name="fruits">
    <option value="0">Choose your fruits:</option>
    <option value="1">Banana</option>
    <option value="2">Mango</option>
</select>

Python:

fruit_field = browser.find_element_by_xpath("//input[@name='fruits']")
fruit_field.send_keys("Mango")

That’s it.


回答 6

您可以很好地使用CSS选择器组合

driver.find_element_by_css_selector("#fruits01 [value='1']").click()

将attribute = value css选择器中的1更改为与所需水果对应的值。

You can use a css selector combination a well

driver.find_element_by_css_selector("#fruits01 [value='1']").click()

Change the 1 in the attribute = value css selector to the value corresponding with the desired fruit.


回答 7

from selenium.webdriver.support.ui import Select
driver = webdriver.Ie(".\\IEDriverServer.exe")
driver.get("https://test.com")
select = Select(driver.find_element_by_xpath("""//input[@name='n_name']"""))
select.select_by_index(2)

会很好的工作

from selenium.webdriver.support.ui import Select
driver = webdriver.Ie(".\\IEDriverServer.exe")
driver.get("https://test.com")
select = Select(driver.find_element_by_xpath("""//input[@name='n_name']"""))
select.select_by_index(2)

It will work fine


回答 8

它与选项值一起使用:

from selenium import webdriver
b = webdriver.Firefox()
b.find_element_by_xpath("//select[@class='class_name']/option[@value='option_value']").click()

It works with option value:

from selenium import webdriver
b = webdriver.Firefox()
b.find_element_by_xpath("//select[@class='class_name']/option[@value='option_value']").click()

回答 9

这样,您可以在任何下拉菜单中选择所有选项。

driver.get("https://www.spectrapremium.com/en/aftermarket/north-america")

print( "The title is  : " + driver.title)

inputs = Select(driver.find_element_by_css_selector('#year'))

input1 = len(inputs.options)

for items in range(input1):

    inputs.select_by_index(items)
    time.sleep(1)

In this way you can select all the options in any dropdowns.

driver.get("https://www.spectrapremium.com/en/aftermarket/north-america")

print( "The title is  : " + driver.title)

inputs = Select(driver.find_element_by_css_selector('#year'))

input1 = len(inputs.options)

for items in range(input1):

    inputs.select_by_index(items)
    time.sleep(1)

回答 10

使用selenium.webdriver.support.ui.Select类与下拉选择配合使用的最佳方法,但由于HTML的设计问题或其他问题,有时它无法按预期工作。

在这种情况下,您也可以使用execute_script()以下替代方法:

option_visible_text = "Banana"
select = driver.find_element_by_id("fruits01")

#now use this to select option from dropdown by visible text 
driver.execute_script("var select = arguments[0]; for(var i = 0; i < select.options.length; i++){ if(select.options[i].text == arguments[1]){ select.options[i].selected = true; } }", select, option_visible_text);

The best way to use selenium.webdriver.support.ui.Select class to work to with dropdown selection but some time it does not work as expected due to designing issue or other issues of the HTML.

In this type of situation you can also prefer as alternate solution using execute_script() as below :-

option_visible_text = "Banana"
select = driver.find_element_by_id("fruits01")

#now use this to select option from dropdown by visible text 
driver.execute_script("var select = arguments[0]; for(var i = 0; i < select.options.length; i++){ if(select.options[i].text == arguments[1]){ select.options[i].selected = true; } }", select, option_visible_text);

回答 11

按照提供的HTML:

<select id="fruits01" class="select" name="fruits">
  <option value="0">Choose your fruits:</option>
  <option value="1">Banana</option>
  <option value="2">Mango</option>
</select>

选择一个 <option>元素中元素菜单,您必须使用Select Class。此外,由于您必须与你有诱导WebDriverWaitelement_to_be_clickable()

选择<option>文本作为芒果您可以使用以下两种定位策略之一

  • 使用ID属性和select_by_visible_text()方法:

    from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.ui import Select
    
    select = Select(WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "fruits01"))))
    select.select_by_visible_text("Mango")
  • 使用CSS-SELECTORselect_by_value()方法:

    select = Select(WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "select.select[name='fruits']"))))
    select.select_by_value("2")
  • 使用XPATHselect_by_index()方法:

    select = Select(WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "//select[@class='select' and @name='fruits']"))))
    select.select_by_index(2)

As per the HTML provided:

<select id="fruits01" class="select" name="fruits">
  <option value="0">Choose your fruits:</option>
  <option value="1">Banana</option>
  <option value="2">Mango</option>
</select>

To select an <option> element from a menu you have to use the Select Class. Moreover, as you have to interact with the you have to induce WebDriverWait for the element_to_be_clickable().

To select the <option> with text as Mango from the you can use you can use either of the following Locator Strategies:

  • Using ID attribute and select_by_visible_text() method:

    from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.ui import Select
    
    select = Select(WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "fruits01"))))
    select.select_by_visible_text("Mango")
    
  • Using CSS-SELECTOR and select_by_value() method:

    select = Select(WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "select.select[name='fruits']"))))
    select.select_by_value("2")
    
  • Using XPATH and select_by_index() method:

    select = Select(WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "//select[@class='select' and @name='fruits']"))))
    select.select_by_index(2)
    

回答 12

  1. 项目清单

公共类ListBoxMultiple {

public static void main(String[] args) throws InterruptedException {
    // TODO Auto-generated method stub
    System.setProperty("webdriver.chrome.driver", "./drivers/chromedriver.exe");
    WebDriver driver=new ChromeDriver();
    driver.get("file:///C:/Users/Amitabh/Desktop/hotel2.html");//open the website
    driver.manage().window().maximize();


    WebElement hotel = driver.findElement(By.id("maarya"));//get the element

    Select sel=new Select(hotel);//for handling list box
    //isMultiple
    if(sel.isMultiple()){
        System.out.println("it is multi select list");
    }
    else{
        System.out.println("it is single select list");
    }
    //select option
    sel.selectByIndex(1);// you can select by index values
    sel.selectByValue("p");//you can select by value
    sel.selectByVisibleText("Fish");// you can also select by visible text of the options
    //deselect option but this is possible only in case of multiple lists
    Thread.sleep(1000);
    sel.deselectByIndex(1);
    sel.deselectAll();

    //getOptions
    List<WebElement> options = sel.getOptions();

    int count=options.size();
    System.out.println("Total options: "+count);

    for(WebElement opt:options){ // getting text of every elements
        String text=opt.getText();
        System.out.println(text);
        }

    //select all options
    for(int i=0;i<count;i++){
        sel.selectByIndex(i);
        Thread.sleep(1000);
    }

    driver.quit();

}

}

  1. List item

public class ListBoxMultiple {

public static void main(String[] args) throws InterruptedException {
    // TODO Auto-generated method stub
    System.setProperty("webdriver.chrome.driver", "./drivers/chromedriver.exe");
    WebDriver driver=new ChromeDriver();
    driver.get("file:///C:/Users/Amitabh/Desktop/hotel2.html");//open the website
    driver.manage().window().maximize();


    WebElement hotel = driver.findElement(By.id("maarya"));//get the element

    Select sel=new Select(hotel);//for handling list box
    //isMultiple
    if(sel.isMultiple()){
        System.out.println("it is multi select list");
    }
    else{
        System.out.println("it is single select list");
    }
    //select option
    sel.selectByIndex(1);// you can select by index values
    sel.selectByValue("p");//you can select by value
    sel.selectByVisibleText("Fish");// you can also select by visible text of the options
    //deselect option but this is possible only in case of multiple lists
    Thread.sleep(1000);
    sel.deselectByIndex(1);
    sel.deselectAll();

    //getOptions
    List<WebElement> options = sel.getOptions();

    int count=options.size();
    System.out.println("Total options: "+count);

    for(WebElement opt:options){ // getting text of every elements
        String text=opt.getText();
        System.out.println(text);
        }

    //select all options
    for(int i=0;i<count;i++){
        sel.selectByIndex(i);
        Thread.sleep(1000);
    }

    driver.quit();

}

}


如何在Selenium Webdriver(Python)中找到包含特定文本的元素?

问题:如何在Selenium Webdriver(Python)中找到包含特定文本的元素?

我正在尝试使用Selenium(使用Python接口并在多个浏览器上)测试复杂的javascript接口。我有许多形式的按钮:

<div>My Button</div>

我希望能够基于“我的按钮”(或不区分大小写的部分匹配项,例如“我的按钮”或“按钮”)搜索按钮

我发现这非常困难,在某种程度上我感觉自己缺少明显的东西。到目前为止,我最好的是:

driver.find_elements_by_xpath('//div[contains(text(), "' + text + '")]')

但是,这是区分大小写的。我尝试过的另一件事是遍历页面上的所有div,并检查element.text属性。但是,每次您得到以下形式的情况:

<div class="outer"><div class="inner">My Button</div></div>

div.outer还使用“我的按钮”作为文本。为了解决这个问题,我尝试查看div.outer是否是div.inner的父级,但无法弄清楚该怎么做(element.get_element_by_xpath(’..’)返回元素的父级,但是测试不等于div.outer)。此外,至少使用Chrome网络驱动程序,迭代页面上的所有元素似乎真的很慢。

有想法吗?

编辑:这个问题有点模糊。在此处询问(并回答)一个更具体的版本:如何在Selenium WebDriver中(通过Python api)获取元素的文本而不包含子元素文本?

I’m trying to test a complicated JavaScript interface with Selenium (using the Python interface, and across multiple browsers). I have a number of buttons of the form:

<div>My Button</div>

I’d like to be able to search for buttons based on “My Button” (or non-case-sensitive, partial matches such as “my button” or “button”).

I’m finding this amazingly difficult, to the extent to which I feel like I’m missing something obvious. The best thing I have so far is:

driver.find_elements_by_xpath('//div[contains(text(), "' + text + '")]')

This is case-sensitive, however. The other thing I’ve tried is iterating through all the divs on the page, and checking the element.text property. However, every time you get a situation of the form:

<div class="outer"><div class="inner">My Button</div></div>

div.outer also has “My Button” as the text. To fix that, I’ve tried looking to see if div.outer is the parent of div.inner, but I couldn’t figure out how to do that (element.get_element_by_xpath(‘..’) returns an element’s parent, but it tests not equal to div.outer).

Also, iterating through all the elements on the page seems to be really slow, at least using the Chrome webdriver.

Ideas?


I asked (and answered) a more specific version here: How to get text of an element in Selenium WebDriver, without including child element text?


回答 0

尝试以下方法:

driver.find_elements_by_xpath("//*[contains(text(), 'My Button')]")

Try the following:

driver.find_elements_by_xpath("//*[contains(text(), 'My Button')]")

回答 1

您可以尝试使用xpath:

'//div[contains(text(), "{0}") and @class="inner"]'.format(text)

You could try an XPath expression like:

'//div[contains(text(), "{0}") and @class="inner"]'.format(text)

回答 2

您还可以将其与“页面对象模式”一起使用,例如:

试试这个代码:

@FindBy(xpath = "//*[contains(text(), 'Best Choice')]")
WebElement buttonBestChoice;

You can also use it with Page Object Pattern, e.g:

Try this code:

@FindBy(xpath = "//*[contains(text(), 'Best Choice')]")
WebElement buttonBestChoice;

回答 3

// *将寻找任何HTML标记。如果某些文本对于Button和div标签是公用的,并且// *是类别,则将无法按预期工作。如果需要选择任何特定内容,则可以通过声明HTML Element标签来获取。喜欢:

driver.find_element_by_xpath("//div[contains(text(),'Add User')]")
driver.find_element_by_xpath("//button[contains(text(),'Add User')]")

//* will be looking for any HTML tag. Where if some text is common for Button and div tag and if //* is categories it will not work as expected. If you need to select any specific then You can get it by declaring HTML Element tag. Like:

driver.find_element_by_xpath("//div[contains(text(),'Add User')]")
driver.find_element_by_xpath("//button[contains(text(),'Add User')]")

回答 4

有趣的是,几乎所有答案都围绕着xpath的功能contains(),而忽略了它区分大小写的事实-与OP的要求相反。
如果您需要不区分大小写,则可以在xpath 1.0 (现代浏览器支持的版本)中实现,尽管效果不佳-通过使用该translate()函数。通过使用转换表,它将源字符替换为其所需的形式。

构造一个由所有大写字母组成的表格,可以将节点的文本有效地转换为lower()形式-允许不区分大小写的匹配(这里只是特权)

[
  contains(
    translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
    'my button'
  )
]
# will match a source text like "mY bUTTon"

完整的python调用:

driver.find_elements_by_xpath("//*[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZЙ', 'abcdefghijklmnopqrstuvwxyzй'), 'my button')]")

自然,这种方法有其缺点-如所给出的,它仅适用于拉丁文字;如果要覆盖Unicode字符-您必须将它们添加到翻译表中。我已经在上面的示例中做到了-最后符是西里尔字母符号"Й"


如果我们生活在其中承载的XPath 2.0及以上的浏览器世界(🤞,但不会很快☹️发生的任何时间),我们可以有使用的功能lower-case()(但不完全区域识别),以及matches(对于正则表达式搜索,以案例-insensitive('i')标志)。

Interestingly virtually all answers revolve around xpath’s function contains(), neglecting the fact it is case sensitive – contrary to OP’s ask.
If you need case insensitivity, that is achievable in xpath 1.0 (the version contemporary browsers support), though it’s not pretty – by using the translate() function. It substitutes a source character to its desired form, by using a translation table.

Constructing a table of all upper case characters will effectively transform the node’s text to its lower() form – allowing case-insensitive matching (here’s just the prerogative):

[
  contains(
    translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
    'my button'
  )
]
# will match a source text like "mY bUTTon"

The full python call:

driver.find_elements_by_xpath("//*[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZЙ', 'abcdefghijklmnopqrstuvwxyzй'), 'my button')]")

Naturally this approach has its drawbacks – as given, it’ll work only for latin text; if you want to cover unicode characters – you’ll have to add them to the translation table. I’ve done that in the sample above – the last character is the Cyrillic symbol "Й".


And if we lived in a world where browsers supported xpath 2.0 and up (🤞, but not happening any time soon ☹️), we could having used the functions lower-case() (yet, not fully locale-aware), and matches (for regex searches, with case-insensitive ('i') flag).


回答 5

在您提供的HTML中:

<div>My Button</div>

文本My Button为,innerHTML周围没有空格,因此您可以轻松地text()按以下方式使用:

my_element = driver.find_element_by_xpath("//div[text()='My Button']")

注意text()选择上下文节点的所有文本节点子级


带有前导/后缀空格的文本

如果开头的相关文本包含空格

<div>   My Button</div>

或最后:

<div>My Button   </div>

或两端:

<div> My Button </div>  

在这些情况下,您有2个选择:

  • 您可以使用contains()确定第一个参数字符串是否包含第二个参数字符串并返回boolean true或false的函数,如下所示:

    my_element = driver.find_element_by_xpath("//div[contains(., 'My Button')]")
  • 您可以使用以下normalize-space()功能:从字符串中去除开头和结尾的空格,将空格字符序列替换为一个空格,然后返回结果字符串,如下所示:

    driver.find_element_by_xpath("//div[normalize-space()='My Button']]")

变量文本的xpath

如果文本是变量,则可以使用:

foo= "foo_bar"
my_element = driver.find_element_by_xpath("//div[.='" + foo + "']")

In the HTML which you have provided:

<div>My Button</div>

The text My Button is the innerHTML and have no whitespaces around it so you can easily use text() as follows:

my_element = driver.find_element_by_xpath("//div[text()='My Button']")

Note: text() selects all text node children of the context node


Text with leading/trailing spaces

Incase the relevant text containing whitespaces either in the beginning:

<div>   My Button</div>

or at the end:

<div>My Button   </div>

or at both the ends:

<div> My Button </div>  

In these cases you have 2 options:

  • You can use contains() function which determines whether the first argument string contains the second argument string and returns boolean true or false as follows:

    my_element = driver.find_element_by_xpath("//div[contains(., 'My Button')]")
    
  • You can use normalize-space() function which strips leading and trailing white-space from a string, replaces sequences of whitespace characters by a single space, and returns the resulting string as follows:

    driver.find_element_by_xpath("//div[normalize-space()='My Button']]")
    

xpath for variable Text

Incase the text is a variable you can use:

foo= "foo_bar"
my_element = driver.find_element_by_xpath("//div[.='" + foo + "']")

回答 6

wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(), 'YourTextHere')]")));
    assertNotNull(driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")));
    String yourButtonName=driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")).getAttribute("innerText");
    assertTrue(yourButtonName.equalsIgnoreCase("YourTextHere"));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(), 'YourTextHere')]")));
assertNotNull(driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")));
String yourButtonName = driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")).getAttribute("innerText");
assertTrue(yourButtonName.equalsIgnoreCase("YourTextHere"));

回答 7

类似的问题:查找 <button>Advanced...</button>

也许这会给您一些想法(请将概念从Java转移到Python):

wait.until(ExpectedConditions.elementToBeClickable(//
    driver.findElements(By.tagName("button")).stream().filter(i -> i.getText().equals("Advanced...")).findFirst().get())).click();

Similar problem: Find <button>Advanced...</button>

Maybe this will give you some ideas (please transfer the concept from Java to Python):

wait.until(ExpectedConditions.elementToBeClickable(//
    driver.findElements(By.tagName("button")).stream().filter(i -> i.getText().equals("Advanced...")).findFirst().get())).click();

回答 8

使用driver.find_elements_by_xpath匹配正则表达式匹配函数,以按元素的文本区分大小写

driver.find_elements_by_xpath("//*[matches(.,'My Button', 'i')]")

Use driver.find_elements_by_xpath and matches regex matching function for the case insensitive search of the element by its text.

driver.find_elements_by_xpath("//*[matches(.,'My Button', 'i')]")

回答 9

试试这个。非常简单:

driver.getPageSource().contains("text to search");

这对于硒网络驱动程序确实很有效。

Try this. It’s very easy:

driver.getPageSource().contains("text to search");

This really worked for me in Selenium WebDriver.