

Python、Seleniumを使って下記のサイトをスクレイピングしたいと考えていますがうまく行きません。

[https://www.spacemarket.com/spaces/eqt2ssndgz6ukjve/rooms/Wsr2fj8iAGN-
FSkT/reservations/new/?date=2023-10-23&from=room_calendar&price_type=HOURLY&rent_type=1](https://www.spacemarket.com/spaces/eqt2ssndgz6ukjve/rooms/Wsr2fj8iAGN-
FSkT/reservations/new/?date=2023-10-23&from=room_calendar&price_type=HOURLY&rent_type=1)

上記ページの利用料金 ¥3,118 を指定する XPath:

[code]

    xpath(//*[@id="__next"]/div[3]/div/div[2]/div[2]/div/div/ul/li[1]/button/span[3]/span[2])
    
[/code]

上記のXPathをChromeのデベロッパーツールで取得し、下記のコードを実行しました。  
しかし、エラーが表示されてうまく行きません。  
`time.sleep(60)` を入れてみましたが同様でした。  
申し訳ありませんがよろしくお願いいたします。

**実行環境:**  
macOS Ventura 13.5.2  
Selenium 4.9.1  
Python 3.8.16

**実行したコード:**

[code]

    xpath = '//*[@id="__next"]/div[3]/div/div[2]/div[2]/div/div/ul/li[1]/button/span[3]/span[2]'
    link2 = driver.find_element(
        By.XPATH, xpath)
    print(link2.text)
    
[/code]

**エラーメッセージ:**

[code]

    Traceback (most recent call last):
      File "/Users/truth/Documents/python/scraping/レンタルスペース/spacemarket.py", line 31, in <module>
        link2 = driver.find_element(
                ^^^^^^^^^^^^^^^^^^^^
      File "/opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/webdriver.py", line 831, in find_element
        return self.execute(Command.FIND_ELEMENT, {"using": by, "value": value})["value"]
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/webdriver.py", line 440, in execute
        self.error_handler.check_response(response)
      File "/opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/errorhandler.py", line 245, in check_response
        raise exception_class(message, screen, stacktrace)
    selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id="__next"]/div[3]/div/div[2]/div[2]/div/div/ul/li[1]/button/span[3]/span[2]"}
      (Session info: chrome=117.0.5938.92)
    
[/code]


CC BY-SA 4.0
2023-10-16T10:37:43.130
96503
2023-10-16T14:42:05.350
2023-10-16T12:08:44.380
3060
40701
question
python selenium xpath
find_elementでXPathを指定してスクレイピングできない


手元の環境(Python 3.11.4/Selenium 4.14.0)で以下のコードを実行してみましたが、"￥3,118" と表示されます。

[code]

    from selenium import webdriver
    from selenium.webdriver.chrome import service as fs
    from selenium.webdriver.common.by import By
    
    chrome_service = fs.Service()
    driver = webdriver.Chrome(service=chrome_service)
    
    url = 'https://www.spacemarket.com/spaces/eqt2ssndgz6ukjve/rooms/Wsr2fj8iAGN-FSkT/reservations/new/?date=2023-10-23&from=room_calendar&price_type=HOURLY&rent_type=1'
    driver.get(url)
    
    xpath = '//*[@id="__next"]/div[3]/div/div[2]/div[2]/div/div/ul/li[1]/button/span[3]/span[2]'
    link2 = driver.find_element(By.XPATH, xpath)
    
    print(link2.text)
    
[/code]


CC BY-SA 4.0
2023-10-16T12:04:59.803
96504
2023-10-16T12:04:59.803
47127
96503
answer


手元の環境下（PythonとSeleniumのバージョンは質問と同じ）でも、質問の内容のみだと事象の再現度がかなり低いようです。  
ので、おそらくは動作環境そのものやWebDriverの設定に起因するような気がしています。

上記を踏まえた上で、下記の内容で「擬似的な再現」をした上で「擬似的な再現環境下でも問題が発生しにくい」手法を試してみました。

## 擬似的な再現

WebDriverのセットアップ時に、[`page_load_strategy`の設定を調整することでページ読み込み戦略を意図的に変更する](https://www.selenium.dev/ja/documentation/webdriver/drivers/options/#pageloadstrategy)ことが出来ます。  
下記例のように`eager`にすると`driver.get()`時にすべてのコンテンツの読み込みが終わるのを待たずに後続処理に進みます。

[code]

    options = webdriver.ChromeOptions()
    options.page_load_strategy = 'eager'
    
    driver = webdriver.Chrome(options=options)
    
[/code]

この状態で質問文にあるURL+XPathの組み合わせで値を取得しようとすると、プラン情報を取得する前にXPathによる`find_element()`に進む可能性が上がり、再現しやすくなるみたいです。  
※手元で試す限りでは、高頻度で再現できる見込み

## 再現内容の解消例

Selenium上で[「WebDriver処理上で目的を達成する」まで待機する](https://www.selenium.dev/ja/documentation/webdriver/waits/#explicit-
waits)ことが出来ます。

下記の例では、`wait.until()`内の処理として`find_element()`を実行することで、「XPathに該当する要素が出現する」までほぼ確実に待つことが出来ます。

[code]

    from selenium.webdriver.support.ui import WebDriverWait
    
    driver.get(url)
    
    wait = WebDriverWait(driver, 60)
    wait.until(lambda d: d.find_element(By.XPATH, xpath))
    
    link2 = driver.find_element(By.XPATH, xpath)
    print(link2.text)
    
[/code]


CC BY-SA 4.0
2023-10-16T14:42:05.350
96505
2023-10-16T14:42:05.350
2784
96503
answer