You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地正常的Python Selenium脚本在GCP虚拟机抛出ElementNotInteractableException

Selenium脚本本地正常,部署到GCP虚拟机后点击元素抛出ElementNotInteractableException

我有一个抓取Wolt餐厅页面的Python Selenium脚本,本地运行完全正常,但部署到Google Cloud虚拟机后,点击页面左上角地址图标(XPATH选择器为//div[@data-projection-id='2']/button)时抛出ElementNotInteractableException。

以下是精简后的代码,最后一行执行失败:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import logging
logging.basicConfig(
    filename="wolt_scraping_logs.log",
    level="INFO",
    format="%(asctime)s  - %(levelname)s - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
    encoding="utf-8"
)

# Set the Chrome options
chrome_options = Options()
chrome_options.add_argument("start-maximized") # Required for a maximized Viewport
chrome_options.add_experimental_option('excludeSwitches', ['enable-logging', 'enable-automation', 'disable-popup-blocking']) # Disable pop-ups to speed up browsing
chrome_options.add_experimental_option("detach", True) # Keeps the Chrome window open after all the Selenium commands/operations are performed 
chrome_options.add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) # Operate Chrome using English as the main language
chrome_options.add_argument('--blink-settings=imagesEnabled=false') # Disable images
chrome_options.add_argument('--disable-extensions') # Disable extensions
chrome_options.add_argument("--headless=new") # Operate Selenium in headless mode
chrome_options.add_argument('--no-sandbox') # Disables the sandbox for all process types that are normally sandboxed. Meant to be used as a browser-level switch for testing purposes only
chrome_options.add_argument('--disable-gpu') # An additional Selenium setting for headless to work properly, although for newer Selenium versions, it's not needed anymore
chrome_options.add_argument("--window-size=1920x1080") # Set the Chrome window size to 1920 x 1080

# Global inputs
base_url = "https://wolt.com/en/discovery/restaurants"

# Instantiate a webdriver
driver = webdriver.Chrome(options=chrome_options)

# Navigate to the target URL
logging.info("Navigate to the target URL...")
driver.get(base_url)

# Maximize the window
logging.info("Maximize the window...")
driver.maximize_window()

# Click on the "Accept Cookies" button
logging.info("Click on the 'Accept Cookies' button")
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//button[@data-localization-key='gdpr-consents.banner.accept-button']")))
driver.find_element(by=By.XPATH, value="//button[@data-localization-key='gdpr-consents.banner.accept-button']").click()

# Click on the "Delivery to" button
logging.info("Click on the 'Delivery to' button")
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//div[@data-projection-id='2']/button")))
driver.find_element(by=By.XPATH, value="//div[@data-projection-id='2']/button").click() # The code fails here

虚拟机上的错误信息:

Traceback (most recent call last):
  File "wolt-crawler/wolt_finland_scraping_script.py", line 73, in <module>
    driver.find_element(by=By.XPATH, value="//div[@data-projection-id='2']/button").click()
  File "/home/omarmoataz6/venv-scraping/lib/python3.8/site-packages/selenium/webdriver/remote/webelement.py", line 93, in click
    self._execute(Command.CLICK_ELEMENT)
  File "/home/omarmoataz6/venv-scraping/lib/python3.8/site-packages/selenium/webdriver/remote/webelement.py", line 403, in _execute
    return self._parent.execute(command, params)
  File "/home/omarmoataz6/venv-scraping/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 440, in execute
    self.error_handler.check_response(response)
  File "/home/omarmoataz6/venv-scraping/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 245, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
  (Session info: chrome=112.0.5615.49)
Stacktrace:
#0 0x5629637d4603 <unknown>
#1 0x562963525741 <unknown>
#2 0x562963562c43 <unknown>
#3 0x562963557025 <unknown>
#4 0x562963582402 <unknown>
#5 0x562963556891 <unknown>
#6 0x5629635825ce <unknown>
#7 0x56296359a9a9 <unknown>
#8 0x5629635821d3 <unknown>
#9 0x562963554fb8 <unknown>
#10 0x5629635560ee <unknown>
#11 0x56296379b046 <unknown>
#12 0x56296379e3c3 <unknown>
#13 0x56296379ec5a <unknown>
#14 0x5629637a6b0e <unknown>
#15 0x56296379f3ec <unknown>
#16 0x562963775ea8 <unknown>
#17 0x5629637bf318 <unknown>
#18 0x5629637bf4c3 <unknown>
#19 0x5629637cce34 <unknown>
#20 0x7fdad2727609 <unknown>

问题原因及解决方案

核心原因

本地与虚拟机环境的差异集中在无头模式页面渲染、元素交互时机、页面加载状态三个方面:

  1. 无头模式下页面渲染布局可能与有头模式不同,导致元素被遮挡或未完全加载
  2. presence_of_element_located仅等待元素存在于DOM,但不保证元素可见、可交互
  3. 虚拟机网络延迟可能导致页面加载速度慢于本地,元素未就绪就执行点击操作

具体解决方案

1. 替换等待条件,确保元素可交互

将presence_of_element_located替换为element_to_be_clickable,该条件会等待元素同时满足存在、可见、可交互三个状态:

# 替换原有的地址按钮点击代码
WebDriverWait(driver, 15).until(EC.element_to_be_clickable((By.XPATH, "//div[@data-projection-id='2']/button"))).click()

2. 优化无头模式Chrome配置

虚拟机上的无头模式需要针对性配置,避免渲染异常:

  • 移除冲突的窗口设置:同时设置start-maximized和window-size会导致无头模式渲染混乱,优先保留window-size并移除driver.maximize_window()(无头模式下该方法无效)
  • 添加--disable-dev-shm-usage:解决虚拟机/dev/shm空间不足问题,避免页面渲染失败
  • 移除无效配置:detach在无头模式下不生效,可直接删除

修改后的Chrome配置:

chrome_options = Options()
chrome_options.add_experimental_option('excludeSwitches', ['enable-logging', 'enable-automation', 'disable-popup-blocking'])
chrome_options.add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'})
chrome_options.add_argument('--blink-settings=imagesEnabled=false')
chrome_options.add_argument('--disable-extensions')
chrome_options.add_argument("--headless=new")
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument("--window-size=1920x1080")
chrome_options.add_argument('--disable-dev-shm-usage')  # 新增:解决共享内存不足问题

3. 处理元素遮挡与滚动

虚拟机上可能存在额外弹窗或布局偏移导致元素被遮挡,可通过滚动确保元素可见:

import time

delivery_button = WebDriverWait(driver, 15).until(EC.element_to_be_clickable((By.XPATH, "//div[@data-projection-id='2']/button")))
# 滚动到元素可见位置
driver.execute_script("arguments[0].scrollIntoView(true);", delivery_button)
# 短暂等待元素状态稳定
time.sleep(0.5)
delivery_button.click()

4. 优化元素定位器稳定性

data-projection-id属于动态生成属性,不同环境下可能变化,建议使用更稳定的定位方式,比如结合元素的功能描述:

# 示例:通过按钮的aria-label属性定位
By.XPATH, "//button[contains(@aria-label, 'Delivery address')]"

内容的提问来源于stack exchange,提问作者oelmaria

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 06:37:02