2

この質問は何度も何度も尋ねられてきました - そして、すべてのハックを試したにもかかわらず、私はまだ何が悪いのか理解できないようです.

Implicitly_wait を 30 に増やしてみました (さらに 100 まで増やしました) - それでもうまくいきませんでした。

ユースケース-: 基本ケースとして、ここのページのすべてのアイテムを入力するリストを作成しようとしています- そして、これを、すべてを含むスクレイピーで既に持っているミニモジュールにバインドするつもりです (ページ同様の 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)

質問とコメント:

  1. この質問に答える場合は、この特定の「find_element_by_link_text」が機能しない理由を述べてください。

  2. (非常に基本的な) 私のセレン IDE の GUI で -> 利用可能なすべてのコマンドを表示 - すべての Web 要素の css (find_element_by_css_selector) が表示されないのはなぜですか - 要素を強制的に CSS セレクターとして読み取る方法はありますか?

  3. 他のロケーターを使用することをお勧めする場合は、(1) を考慮して、それが要素をフェッチする一貫した方法であるかどうかを言及してください。

  4. 例外をキャプチャして「続行」する作業をアサートします - 「verify」、「assert」ループを試行した後でも、この「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

1

要素が見つからなかった場合、NoSuchElementExceptionがスローされます。

この例外が発生した場合は、次の点を確認してください。

  • で使用されているセレクターを確認してくださいfind_by...
  • 検索操作の時点で、要素がまだ画面に表示されていない可能性があります。

Web ページがまだ読み込まれている場合は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 がクリックが Web ドライバーに与える影響を追跡することが難しいことも意味します。ブラウザの内部 - クリックした直後にブラウザのページ読み込みステータスをポーリングしようとするかもしれませんが、ブラウザがマルチタスクを行っていて、まだクリックを処理する準備が整っていない競合状態が発生する可能性があります。.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()
    

    上記のコード サンプルは、ハリーのブログからのものです。

  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

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() は、xpath でこれを見つける前に、次の行を追加すると、クリック/識別を高速化できます。この種の Webdriver が要素を探している場所を絞り込むと思います。 これは私が追加したものです " driver.find_element_by_css_selector("#subseries").text"

これにより、そのページでの待ち時間が少なくとも 20 秒短縮されたに違いありません。

于 2015-05-18T09:26:16.367 に答える
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 に答える