【问题标题】:Selenium. Unable to locate element from the html website硒。无法从 html 网站找到元素
【发布时间】:2021-08-15 22:19:48
【问题描述】:

这是我要抓取的网站的链接(我正在训练,没什么特别的):

link

这是我的剧本,他很长,但没有太复杂:

from selenium import webdriver



if __name__ == "__main__":
    print("Web Scraping application started")

    PATH = "driver\chromedriver.exe"


    options = webdriver.ChromeOptions() 
    options.add_argument("--disable-gpu")
    options.add_argument("--window-size=1200,900")
    options.add_argument('enable-logging')

    driver = webdriver.Chrome(options=options, executable_path=PATH)

    driver.get('https://fr.hotels.com/')
    driver.maximize_window()

    destination_location_element = driver.find_element_by_id("qf-0q-destination")
    check_in_date_element = driver.find_element_by_id("qf-0q-localised-check-in")
    check_out_date_element = driver.find_element_by_id("qf-0q-localised-check-out")


    search_button_element = driver.find_element_by_xpath('//*[@id="hds-marquee"]/div[2]/div[1]/div/form/div[4]/button')

    print('Printing type of search_button_element')
    print(type(search_button_element))

    destination_location_element.send_keys('Paris')
    check_in_date_element.clear()
    check_in_date_element.send_keys("29/05/2021")
    check_out_date_element.clear()
    check_out_date_element.send_keys("30/05/2021")



    close_date_window = driver.find_element_by_xpath('/html/body/div[7]/div[4]/button')

    print('Printing type of close_date_window')
    print(type(close_date_window))

    close_date_window[0].click()

    search_button_element.click()

    time.sleep(10)

    hotels = driver.find_element_by_class_name('hotel-wrap')

    print("\n")

    i = 1

    for hotel in hotels:

        try:
            print(hotel.find_element_by_xpath('//*[@id="listings"]/ol/li['+str(i)+']/article/section/div/h3/a').text)
            print(hotel.find_element_by_xpath('//*[@id="listings"]/ol/li[' + str(i) + ']/article/section/div/address/span').text)

        except Exception as ex:
            print(ex)
            print('Failed to extract data from element.')

        i = i +1

        print('\n')

    driver.close()

    print('Web Scraping application completed')

这是我得到的错误:

  File "hotelscom.py", line 21, in <module>
    destination_location_element = driver.find_element_by_id("qf-0q-destination")
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="qf-0q-destination"]"}
  (Session info: chrome=90.0.4430.85)

知道如何解决这个问题吗?我不明白为什么它会给我这个错误,因为在 html 代码中有这种语法。但我想我错了。

【问题讨论】:

  • 你在哪里?国家?
  • 法国,为了什么?
  • 定位器取决于位置
  • @FalconMelee 你试过我的解决方案了吗?
  • 是的,但是脚本找不到destination_location_element,所以我用destination_location_element 替换你的element,但它也不起作用

标签: python python-3.x selenium selenium-webdriver web-scraping


【解决方案1】:

您的代码和网站存在多个问题。

网站问题

1 网站位于多台服务器上,不同的服务器有不同的html代码。我不知道这是否取决于位置。

2 我有解决方案的版本很少有严重的错误(或者这些错误可能是功能)。其中:

  • 当您按下 Enter 键时,它会在打开日期字段并且您只想关闭此日期字段时启动酒店搜索。因此,以传统方式关闭输入字段是一个问题。
  • Selenium 的 clear() 无法正常工作。

代码中的错误

1 您在选项中定义窗口大小,并在站点打开后立即最大化窗口。只使用一个选项

2您正在输入“29/05/2021”之类的日期,但网站只能识别以下格式:“05/30/2021”。差别很大

3您没有使用任何等待,它们非常重要。

4您的定位器错误且不稳定。即使是带有id 的定位器也并不总是对我有用,因为如果您要进行搜索,其中一些有两个元素。所以我用css选择器替换它们。

请注意,我的解决方案仅适用于旧版本的网站。如果您想打开特定版本,您将需要:

  • 通过直接IP地址获取站点,例如driver.get('site ip address')
  • 在您的框架中实施一种策略,该策略可识别打开的站点版本并根据它应用输入。

解决方案

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


if __name__ == "__main__":
    print("Web Scraping application started")
    options = webdriver.ChromeOptions()
    options.add_argument("--disable-gpu")
    options.add_argument("--window-size=1200,900")
    options.add_argument('enable-logging')

    driver = webdriver.Chrome(options=options, executable_path='/snap/bin/chromium.chromedriver')

    driver.get('https://fr.hotels.com/')
    wait = WebDriverWait(driver, 15)

    wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#qf-0q-destination")))
    destination_location_element = driver.find_element_by_css_selector("#qf-0q-destination")
    destination_location_element.send_keys('Paris, France')
    wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".widget-autosuggest.widget-autosuggest-visible table tr")))
    destination_location_element.send_keys(Keys.TAB)  # workaround to close destination field
    driver.find_element_by_css_selector(".widget-query-sub-title").click()
    wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, ".widget-query-group.widget-query-destination [aria-expanded=true]")))

    wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#qf-0q-localised-check-in")))
    check_in_date_element = driver.find_element_by_css_selector("#qf-0q-localised-check-in")
    check_in_date_element.send_keys(Keys.CONTROL, 'a')  # workaround to replace clear() method
    check_in_date_element.send_keys(Keys.DELETE)  # workaround to replace clear() method
    # check_in_date_element.click()
    check_in_date_element.send_keys("05/30/2021")

    # wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "#qf-0q-localised-check-out")))
    check_out_date_element = driver.find_element_by_id("qf-0q-localised-check-out")
    check_out_date_element.click()
    check_out_date_element.send_keys(Keys.CONTROL, 'a')
    check_out_date_element.send_keys(Keys.DELETE)
    check_out_date_element.send_keys("05/31/2021")
    driver.find_element_by_css_selector(".widget-query-sub-title").click()  # workaround to close end date
    wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#hds-marquee button"))).click()

花了这几个小时,这项任务对我来说似乎很有趣。 它适用于这个用户界面:

代码仍然可以优化。这取决于你。

更新:

我发现该站点至少有三个主页,其中包含三个不同的Destination 和其他字段定位器。 我想到的最简单的解决方法是这样的:

try:
    element = driver.find_element_by_css_selector("#qf-0q-destination")
    if element.is_displayed():
        wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#qf-0q-destination")))
        destination_location_element = driver.find_element_by_css_selector("#qf-0q-destination")
        print("making input to Destination field of site 1")
        destination_location_element.send_keys('Paris, France')
        # input following data
except:
    print("Page 1 not found")
try:
    element = driver.find_element_by_css_selector("input[name=q-destination-srs7]")
    if element.is_displayed():
        wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input[name=q-destination-srs7]")))
        destination_location_element = driver.find_element_by_css_selector("input[name=q-destination-srs7]")
        print("making input to Destination field of site 2")
        destination_location_element.send_keys('Paris, France')
        # input following data
except:
    print("Page 2 is not found")
try:
    element = driver.find_element_by_css_selector("form[method=GET]>div>._1yFrqc")
    if element.is_displayed():
        wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "form[method=GET]>div>._1yFrqc")))
        destination_location_element = driver.find_element_by_css_selector("form[method=GET]>div>._1yFrqc")
        print("making input to Destination field of site 3")
        destination_location_element.send_keys('Paris, France')
        # input following data
except:
    print("Page 3 is not found")

但最好的解决方案是直接访问只有一个版本的特定服务器。

另请注意,如果您通过法国的直接链接访问该网站:https://fr.hotels.com/?pos=HCOM_FR&locale=fr_FR,您输入的日期将与您最初指定的日期相同,例如 2021 年 5 月 30 日。

【讨论】:

  • 非常感谢!这是一个绝妙的答案。现在我只有一个问题:chromium.chromedriver?这对我来说是一个新的:)
  • 像以前一样使用 chromedriver.exe。我正在使用 Linux。
  • 它对我不起作用。我收到此错误:File "hotelscom.py", line 28, in &lt;module&gt; wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#qf-0q-destination"))) File "C:\Users\evanalonso\Anaconda3\lib\site-packages\selenium\webdriver\support\wait.py", line 80, in until raise TimeoutException(message, screen, stacktrace) selenium.common.exceptions.TimeoutException: Message:
  • 这可能是因为您打开的站点具有不同的 DOM(此站点的问题 #1)。查看此内容,了解如何通过一些尝试块来制定策略stackoverflow.com/questions/17322208/…
  • @vitaliis 你的回答令人印象深刻!
【解决方案2】:

您在找到元素之前缺少等待/睡眠。
因此,只需添加以下内容:

element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.ID, "qf-0q-destination")))
element.click()

要使用它,您必须使用以下导入:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as E

【讨论】:

  • qf-0q-destination 看起来不像静态 ID
  • 我试过了,它在我的电脑上运行,确实如此。
  • @Prophet 您的定位器是正确的,但这个网站的问题是它至少有三个不同的主页。
【解决方案3】:

试试这个


driver.find_element_by_xpath(".//div[contains(@class,'destination')]/input[@name='q-destination']")

另外请在最大化窗口后添加等待

【讨论】:

  • 它没有找到 xpath,我试过这个:destination_location_element = driver.find_element_by_xpath("//input[@id='qf-0q-destination']"),它似乎工作。但我想右键单击复制 xpath 似乎不是正确的 coice,因为现在它找不到这个:close_date_window = driver.find_element_by_xpath('/html/body/div[7]/div[4]/button')
  • 试试这个 xpath:.//button[@class='widget-overlay-close']
  • 我不明白,现在是destination_location_element = driver.find_element_by_xpath("//input[@id='qf-0q-destination']"),它又不能工作了。当我更改close_date_window 时,destination_location_element 停止工作。我不明白。
  • 当我运行我的代码时,我登陆了 2 个不同的网站。可能是特定位置的。
  • 我的错,我删除了对close_date_window 的修改,但destination_location_element 现在似乎不起作用。我不明白,早些时候,它可以工作,我只是在close_date_window 上遇到另一个错误,所以我认为destination_location_element 工作正常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 2015-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多