这个问题一再被问到 - 尽管我尝试了所有的黑客攻击,但我仍然无法弄清楚是什么问题。
我尝试将implicitly_wait增加到30(甚至将其增加到100) - 但它没有用。
用例 - :我正在尝试创建一个列表,该列表将填充页面here中的所有项目,作为基本案例 - 我打算将这个绑定到一个我已经拥有scrapy的迷你模块,它具有所有(具有类似web元素的页面)爬行链接 - 所以基本上将构建整个管道,发布我完成了这个。
###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)
问题&amp;评论:
如果您正在回答此问题 - 请提及为什么此特定“find_element_by_link_text”不起作用。
(非常基础)在我的selenium IDE的GUI中 - &gt;显示所有可用的命令 - 为什么我没有看到所有Web元素的css(find_element_by_css_selector) - 有没有办法强制将元素作为CSS选择器读取?
如果您建议使用其他定位器 - 请提及是否一致的方式获取元素,给定(1)
断言是否有效捕获异常并“继续” - 因为即使在尝试“验证”,“断言”循环后,我仍然无法获取此“find_element_by_link_text”
我尝试使用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.
相关问题:
答案 0 :(得分:2)
在我之前发生find_element_by_link_text
方法有时可行,有时不起作用;即使是在一个案例中。我认为这不是访问元素的可靠方式;最好的方法是使用find_element_by_id
。
但在您的情况下,当我访问该页面时,没有ID可以帮助您。您仍然可以通过3种方式尝试find_elements_by_xpath
:
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')]"]
。
希望它有所帮助。
答案 1 :(得分: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)
答案 2 :(得分:0)
NoSuchElementException在无法找到元素时抛出。
如果您遇到此例外,请检查以下内容:
find_by...
如果网页仍在加载,请检查selenium.webdriver.support.wait.WebDriverWait()
并编写等待包装以等待元素出现。
您可以在失败的行pdb.set_trace()
之前添加断点(不要忘记import pdb
),然后运行测试,一旦调试器停止,然后执行以下测试。
您可以尝试:
driver.find_element_by_xpath(u'//a[text()="Foo text"]')
代替。这是更可靠的测试,所以如果这样可行,请改用它。
如果上述情况无效,请通过以下方式检查您的网页是否已正确加载:
(Pdb) driver.execute_script("return document.readyState")
'complete'
有时在未加载页面时,您实际上是从旧页面获取元素。但即使readyState
仍然可以指示旧页面的状态(特别是在使用click()
时)。以下是此blog:
由于Selenium webdriver变得更加先进,点击更像是“真正的”点击,这有利于我们的测试更加真实,但这也意味着Selenium很难跟踪点击的影响在浏览器的内部 - 它可能会尝试在点击后立即轮询浏览器的页面加载状态,但是这对于浏览器是多任务的竞争条件是开放的,还没有完全处理点击,它会为您提供旧页面的
.readyState
。
如果您认为这是因为页面未正确加载,那么“推荐”(但仍然很难看)的解决方案是explicit wait:
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's blog。
以下是Tommy Beadle提出的版本(使用staleness方法):
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))
如果您认为不是页面加载,请仔细检查您的元素是否在iframe
或不同的窗口中。如果是这样,你必须switch to it first。要检查可用窗口列表,请运行:driver.window_handles
。
答案 3 :(得分:0)
OP发布的解决方案:
Hack 1:我没有将元素标识为文本链接,而是确定了更大的框架&#34;这个元素存在的地方。 itemlist_1 = driver.find_element_by_css_selector(&#34; li.item.first&#34;)。text 这将给出整个项目以及名称,价格和细节(以及不需要的添加到购物车和比较&#34;
有关详情,请参阅附图。
黑客2:我发现&#34;立即购买&#34;这是xPath的一个图像元素(driver.find_element_by_xpath(&#34; // div [@id =&#39; subseries&#39;] / div [2] / div / p [3] / a&#34;) 。点击() ,在上面的代码中,如果我添加以下行,可以更快地点击/识别,然后通过xpath找到它。 我认为这会缩小Webdriver寻找元素的地方。这就是我添加的内容&#34; driver.find_element_by_css_selector(&#34;#子系列&#34)文本&#34;
这一定必须减少我在该页面上的等待时间至少20秒。希望有所帮助。