2

这个问题被一遍又一遍地问到——尽管尝试了所有的技巧,但我似乎仍然无法弄清楚出了什么问题。

我尝试将implicitly_wait 增加到30(甚至增加到100) - 但它没有用。

用例- :我正在尝试创建一个列表,该列表将在此处填充页面中的所有项目,作为基本案例 - 我打算将它绑定到我已经拥有的迷你模块,其中包含所有(页面与类似的网络元素)爬网链接 - 所以基本上将构建整个管道,我已经完成了这个。

###My source code - generated via Selenium IDE, exported to a Python webdriver and manipulated a little later ###

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.wait import WebDriverWait
import unittest, time, re

class Einstein(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "http://shopap.lenovo.com/in/en/laptops/"
        self.verificationErrors = []
        self.accept_next_alert = True

    def test_einstein(self):
        driver = self.driver
        driver.get(self.base_url)
        print driver.title
        driver.find_element_by_link_text("T430").click()
        print driver.title
#       driver.find_element_by_xpath("id('facetedBrowseWrapper')/div/div/div[1]/div[2]/ul[1]/li[1]/a").click()
        driver.find_element_by_xpath("//div[@id='subseries']/div[2]/div/p[3]/a").click()
        print driver.title
       # driver.find_element_by_xpath("//div[@id='subseries']/div[2]/div/p[3]/a").click()
        try: self.assertEqual("Thinkpad Edge E530 (Black)", driver.find_element_by_link_text("Thinkpad Edge E530 (Black)").text)
        except AssertionError as e: self.verificationErrors.append(str(e))
       # Everything ok till here

        #**THE CODE FAILS HERE**#
        laptop1 = driver.find_element_by_link_text("Thinkpad Edge E530 (Black)").text
        print laptop1
        price1 = driver.find_element_by_css_selector("span.price").text
        print price1
        detail1 = self.is_element_present(By.CSS_SELECTOR, "div.desc.std")
        print detail1

            def is_element_present(self, how, what):
        try: self.driver.find_element(by=how, value=what)
        except NoSuchElementException, e: return False
        return True

    def is_alert_present(self):
        try: self.driver.switch_to_alert()
        except NoAlertPresentException, e: return False
        return True

    def close_alert_and_get_its_text(self):
        try:
            alert = self.driver.switch_to_alert()
            alert_text = alert.text
            if self.accept_next_alert:
                alert.accept()
            else:
                alert.dismiss()
            return alert_text
        finally: self.accept_next_alert = True

    def tearDown(self):
        self.driver.quit()
        self.assertEqual([], self.verificationErrors)

if __name__ == "__main__":
    unittest.main()


Errors & output :
ekta@ekta-VirtualBox:~$ python einstein.py
Laptops & Ultrabooks | Lenovo (IN)
ThinkPad T430 Laptop PC for Business Computing | Lenovo (IN)
Buy Lenovo Thinkpad Laptops | Lenovo Thinkpad Laptops Price India
E
======================================================================
ERROR: test_einstein (__main__.Einstein)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "einstein.py", line 27, in test_einstein
    try: self.assertEqual("Thinkpad Edge E530 (Black)", driver.find_element_by_link_text("Thinkpad Edge E530 (Black)").text)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 246, in find_element_by_link_text
    return self.find_element(by=By.LINK_TEXT, value=link_text)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 680, in find_element
    {'using': by, 'value': value})['value']
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 165, in execute
    self.error_handler.check_response(response)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/errorhandler.py", line 158, in check_response
    raise exception_class(message, screen, stacktrace)
NoSuchElementException: Message: u'Unable to locate element: {"method":"link text","selector":"Thinkpad Edge E530 (Black)"}' ; Stacktrace: 
    at FirefoxDriver.prototype.findElementInternal_ (file:///tmp/tmphli5Jg/extensions/fxdriver@googlecode.com/components/driver_component.js:8444)
    at fxdriver.Timer.prototype.setTimeout/<.notify (file:///tmp/tmphli5Jg/extensions/fxdriver@googlecode.com/components/driver_component.js:386) 

----------------------------------------------------------------------
Ran 1 test in 79.348s

FAILED (errors=1)

问题和评论:

  1. 如果您正在回答这个问题 - 请说明为什么这个特定的“find_element_by_link_text”不起作用。

  2. (非常基本)在我的 selenium IDE 的 GUI -> 显示所有可用命令 - 为什么我看不到所有 Web 元素的 css (find_element_by_css_selector) -有没有办法强制将元素作为 CSS 选择器读取?

  3. 如果您建议使用其他定位器 - 请说明这是否是获取元素的一致方式,给定 (1)

  4. 断言是否可以捕获异常并“继续” - 因为即使在尝试“验证”、“断言”循环之后,我仍然无法获取这个“find_element_by_link_text”

  5. 我尝试使用 Xpath 来构建这个“元素”,但是在 Xpath 视图中(在 firefox 中) - 我什么也没看到,以提示为什么会发生这种情况(当然我删除了命名空间 ":x" )

我尝试过的其他事情implicity_wait(30)

find_element_by_partial_link(“Thinkpad”) and appending Unicode to this (wasn’t sure if it was reading the brackets ( , driver.find_element_by_link_text(u"Thinkpad Edge E530 (Black)").text, still did not work.

相关问题:

4

4 回答 4

2

我之前也遇到过这种find_element_by_link_text方法有时有效,有时无效;即使在一个案例中。我认为这不是访问元素的可靠方法;最好的方法是使用find_element_by_id.

但是在您的情况下,当我访问该页面时,没有 id 可以帮助您。您仍然可以尝试find_elements_by_xpath3 种方式:

1-访问标题:find_element_by_xpath["//a[contains(@title = 'T430')]"]

2-访问文本:find_element_by_xpath["//a[contains(text(), 'T430')]"]

3-访问href find_element_by_xpath["//a[contains(@href = 'http://www.thedostore.com/laptops/thinkpad-laptops/thinkpad-t430-u-black-627326q.html')]"]:。

希望能帮助到你。

于 2013-09-26T07:40:23.267 回答
1

找不到元素时抛出NoSuchElementException 。

如果遇到此异常,请检查以下内容:

  • 检查您的选择器中使用的find_by...
  • 在查找操作时,元素可能尚未出现在屏幕上。

如果网页仍在加载,请检查selenium.webdriver.support.wait.WebDriverWait()并编写等待包装器以等待元素出现。

故障排除和代码示例

您可以在失败行之前添加断点pdb.set_trace()(不要忘记import pdb),然后运行测试,一旦调试器停止,然后执行以下测试。

  1. 你可以试试:

    driver.find_element_by_xpath(u'//a[text()="Foo text"]')
    

    反而。这是更可靠的测试,所以如果这可行,请改用它。

  2. 如果以上没有帮助,请检查您的页面是否已通过以下方式正确加载:

    (Pdb) driver.execute_script("return document.readyState")
    'complete'
    

    有时当页面未加载时,您实际上是从旧页面获取元素。但即便如此,readyState仍然可以指示旧页面的状态(尤其是在使用 时click())。这是此博客中的解释方式:

    由于 Selenium webdriver 变得更加先进,点击更像是“真正的”点击,这有利于让我们的测试更加真实,但这也意味着 Selenium 很难跟踪点击对浏览器的内部——它可能会在点击后立即尝试轮询浏览器的页面加载状态,但这会导致浏览器处于多任务处理、尚未完全处理点击的竞争条件,并且它给你.readyState旧页面的。

  3. 如果您认为这是因为页面未正确加载而发生的,那么“推荐”(但仍然很难看)解决方案是显式等待

    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait 
    from selenium.webdriver.support import expected_conditions
    
    old_value = browser.find_element_by_id('thing-on-old-page').text
    browser.find_element_by_link_text('my link').click()
    WebDriverWait(browser, 3).until(
        expected_conditions.text_to_be_present_in_element(
            (By.ID, 'thing-on-new-page'),
            'expected new text'
        )
    )
    

    天真的尝试是这样的:

    def wait_for(condition_function):
        start_time = time.time()
        while time.time() < start_time + 3:
            if condition_function():
                return True
            else:
                time.sleep(0.1)
        raise Exception(
            'Timeout waiting for {}'.format(condition_function.__name__)
        )
    
    
    def click_through_to_new_page(link_text):
        browser.find_element_by_link_text('my link').click()
    
        def page_has_loaded():
            page_state = browser.execute_script(
                'return document.readyState;'
            ) 
            return page_state == 'complete'
    
        wait_for(page_has_loaded)
    

    另一个更好的是(感谢@ThomasMarks):

    def click_through_to_new_page(link_text):
        link = browser.find_element_by_link_text('my link')
        link.click()
    
        def link_has_gone_stale():
            try:
                # poll the link with an arbitrary call
                link.find_elements_by_id('doesnt-matter') 
                return False
            except StaleElementReferenceException:
                return True
    
        wait_for(link_has_gone_stale)
    

    最后一个示例包括如下比较页面 id(这可能是防弹的):

    class wait_for_page_load(object):
    
        def __init__(self, browser):
            self.browser = browser
    
        def __enter__(self):
            self.old_page = self.browser.find_element_by_tag_name('html')
    
        def page_has_loaded(self):
            new_page = self.browser.find_element_by_tag_name('html')
            return new_page.id != self.old_page.id
    
        def __exit__(self, *_):
            wait_for(self.page_has_loaded)
    

    现在我们可以这样做:

    with wait_for_page_load(browser):
        browser.find_element_by_link_text('my link').click()
    

    以上代码示例来自Harry 的博客

  4. 这是Tommy Beadle提出的版本(通过使用陈旧方法):

    import contextlib
    from selenium.webdriver import Remote
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support.expected_conditions import staleness_of
    
    class MyRemote(Remote):
        @contextlib.contextmanager
        def wait_for_page_load(self, timeout=30):
            old_page = self.find_element_by_tag_name('html')
            yield
            WebDriverWait(self, timeout).until(staleness_of(old_page))
    
  5. 如果您认为这与页面加载无关,请仔细检查您的元素是否不在iframe或不同的窗口中。如果是这样,您必须先切换到它。要检查可用窗口列表,请运行driver.window_handles

于 2015-05-17T23:32:30.737 回答
0

从查看您提供链接的页面的来源来看,您似乎使用了不正确的选择器。

您应该改用 find_elements_by_link_text(u'text here')[0] 来选择第一次出现,因为似乎有多个链接具有相同链接文本的可能性。

所以而不是:

self.assertEqual("Thinkpad Edge E530 (Black)", driver.find_element_by_link_text("Thinkpad Edge E530 (Black)").text)

你应该使用:

self.assertEqual("Thinkpad Edge E530 (Black)", driver.find_elements_by_link_text("Thinkpad Edge E530 (Black)")[0].text)
于 2013-09-26T16:06:33.707 回答
0

OP发布的解决方案:

技巧 1:我没有将元素标识为文本链接,而是确定了该元素所在的“更大的框架”。itemlist_1 = driver.find_element_by_css_selector("li.item.first").text 这将给出整个项目以及名称、价格和详细信息(以及不需要的添加到购物车和比较”

有关更多信息,请参见附图。 在此处输入图像描述

技巧 2:我发现“立即购买”是带有 xPath 的图像元素 (driver.find_element_by_xpath("//div[@id='subseries']/div[2]/div/p[3]/a" ).click() ,在上面的代码中 我认为这种范围缩小了 Webdriver 正在寻找元素的范围。 这就是我添加的“driver.find_element_by_css_selector("#subseries").text”

在该页面上,这一定使我的等待时间至少减少了 20 秒。希望对您有所帮助。

于 2015-05-18T09:26:16.367 回答