如何用Selenium Python定位马士基网站多层Shadow Root内的输入框
马士基船期查询页输入框交互问题
我用Selenium Python开展网页自动化项目,目标页面为马士基船期查询页(https://www.maersk.com/schedules/pointToPoint)。尝试点击页面上的“From (City, Country/Region)”和“To (City, Country/Region)”输入框时,通过find_elements获取的input元素执行click()方法会抛出ElementNotInteractableException异常。目标输入框位于form标签内,页面还包含iframe元素。
原Python代码
from webdriver_manager.chrome import ChromeDriverManager import tkinter as tk from tkinter import filedialog, messagebox from PIL import ImageTk, Image from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium import webdriver from selenium.webdriver.common.keys import Keys import time import time import os import wget import pandas as pd import csv from collections.abc import Iterable import glob import shutil import re import openpyxl from selenium import webdriver from PIL import Image import pytesseract from selenium.common.exceptions import TimeoutException # Automatically download and set up the appropriate ChromeDriver driver = webdriver.Chrome(ChromeDriverManager().install()) driver.get(f"https://www.maersk.com/schedules/pointToPoint") #time.sleep(1) driver.maximize_window() allow_all = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//*[@id='coiPage- 1']/div[2]/button[3]"))) allow_all.click() form = driver.find_element(By.CLASS_NAME, "schedules-view__search--box") # Find the input element within the form input_element = form.find_elements(By.TAG_NAME, "input") # Click on the first input element or perform any action needed print(input_element)
代码输出
[<selenium.webdriver.remote.webelement.WebElement (session="3fb48d1f542b127316d4cb737f238639", element="B037E6D01D955BB15533DAE9CA20FFB4_element_66")>, <selenium.webdriver.remote.webelement.WebElement (session="3fb48d1f542b127316d4cb737f238639", element="B037E6D01D955BB15533DAE9CA20FFB4_element_68")>, <selenium.webdriver.remote.webelement.WebElement (session="3fb48d1f542b127316d4cb737f238639", element="B037E6D01D955BB15533DAE9CA20FFB4_element_70")>, <selenium.webdriver.remote.webelement.WebElement (session="3fb48d1f542b127316d4cb737f238639", element="B037E6D01D955BB15533DAE9CA20FFB4_element_72")>]
报错信息
执行input_element[0].click()时抛出:
ElementNotInteractableException Traceback (most recent call last) Cell In[26], line 1 ----> 1 input_element[0].click() File ~\anaconda3\lib\site-packages\selenium\webdriver\remote\webelement.py:93, in WebElement.click(self) 91 def click(self) -> None: 92 """Clicks the element.""" ---> 93 self._execute(Command.CLICK_ELEMENT) File ~\anaconda3\lib\site-packages\selenium\webdriver\remote\webelement.py:410, in WebElement._execute(self, command, params) 408 params = {} 409 params["id"] = self._id --> 410 return self._parent.execute(command, params) File ~\anaconda3\lib\site-packages\selenium\webdriver\remote\webdriver.py:444, in WebDriver.execute(self, driver_command, params) 442 response = self.command_executor.execute(driver_command, params) 443 if response: --> 444 self.error_handler.check_response(response) 445 response["value"] = self._unwrap_value(response.get("value", None)) 446 return response File ~\anaconda3\lib\site-packages\selenium\webdriver\remote\errorhandler.py:249, in ErrorHandler.check_response(self, response) 247 alert_text = value["alert"].get("text") 248 raise exception_class(message, screen, stacktrace, alert_text) # type: ignore[call-arg] # mypy is not smart enough here --> 249 raise exception_class(message, screen, stacktrace) ElementNotInteractableException: Message: element not interactable (Session info: chrome=119.0.6045.160) Stacktrace: GetHandleVerifier [0x003072A3+45731] (No symbol) [0x00292D51] (No symbol) [0x001886D0] (No symbol) [0x001BCAC4] (No symbol) [0x001B4FC0] (No symbol) [0x001D7FDC] (No symbol) [0x001B4A4E] (No symbol) [0x001D8254] (No symbol) [0x001EB7A2] (No symbol) [0x001D7DD6] (No symbol) [0x001B31F6] (No symbol) [0x001B439D] GetHandleVerifier [0x00610716+3229462] GetHandleVerifier [0x006584C8+3523784] GetHandleVerifier [0x0065214C+3498316] GetHandleVerifier [0x00391680+611968] (No symbol) [0x0029CCCC] (No symbol) [0x00298DF8] (No symbol) [0x00298F1D] (No symbol) [0x0028B2C7] BaseThreadInitThunk [0x7548FCC9+25] RtlGetAppContainerNamedObjectPath [0x770A7C6E+286] RtlGetAppContainerNamedObjectPath [0x770A7C3E+238] (No symbol) [0x00000000]
目标输入框所在form标签HTML结构
<form novalidate="" class="schedules-view__search--box"> <mc-c-origin-destination class="origin-destination"></mc-c-origin-destination> <hr class="schedules-view__search--divider"> <div class="form-group"> <div class="date-section"> <mc-select-native id="sortBy" name="sortBy" value="[{"label":"Departing","value":"D"}]"><input type="text" name="sortBy" style="display:none" aria-hidden="true" tabindex="-1" value="[{"label":"Departing","value":"D"}]" data-di-id="di-id-a9af2e59-782584d2"></mc-select-native> <mc-input-date data-test="ptp-date-picker" dontusenativeonmobile="" id="" name="ptpDatePicker" value="23/11/2023"><input type="text" name="ptpDatePicker" style="display:none" aria-hidden="true" tabindex="-1" value="23/11/2023" data-di-id="di-id-d08f07b1-d6f0dde0"></mc-input-date> </div> <hr class="schedules-view__search--divider"> <div class="container-section"> <div class="form-group"> <mc-select-native id="containerType" name="containerType" value="[{"label":"40' Dry Standard","value":"42G1"}]"><input type="text" name="containerType" style="display:none" aria-hidden="true" tabindex="-1" value="[{"label":"40' Dry Standard","value":"42G1"}]" data-di-id="di-id-409271ab-305b2833"></mc-select-native> <mc-checkbox id="reeferCheckbox"></mc-checkbox> </div> </div> </div> <hr class="schedules-view__search--divider"> <div class="form-group vessel-flag"> <mc-c-typeahead clearbutton="" id="vesselFlag" name="vesselFlag" value=""><input type="text" name="vesselFlag" style="display:none" aria-hidden="true" tabindex="-1" value="" data-di-id="di-id-f906762b-b9bc3f2e"></mc-c-typeahead> </div> <div class="form-group"> <mc-button data-test="ptp-search-button" fit="medium" appearance="primary" variant="filled" width="full-width">Search</mc-button> </div> </form>
解决方案及代码示例
问题原因
- 你定位到的input元素是隐藏元素(HTML中含
style="display:none"),这类元素不可交互,并非页面上实际显示的输入框。 - 实际可交互的输入框在自定义组件
<mc-c-origin-destination>内部,需定位该组件下的可见输入区域。 - 页面存在动态加载,需等待元素完全可交互后再操作。
优化后的代码
from webdriver_manager.chrome import ChromeDriverManager from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 初始化浏览器 driver = webdriver.Chrome(ChromeDriverManager().install()) driver.get("https://www.maersk.com/schedules/pointToPoint") driver.maximize_window() # 处理Cookie弹窗,等待元素可点击后操作 WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, "//*[@id='coiPage-1']/div[2]/button[3]")) ).click() # 等待出发地输入框可交互并输入内容 from_input = WebDriverWait(driver, 15).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "mc-c-origin-destination .origin input")) ) from_input.click() from_input.send_keys("Shanghai, China") # 等待目的地输入框可交互并输入内容 to_input = WebDriverWait(driver, 15).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "mc-c-origin-destination .destination input")) ) to_input.click() to_input.send_keys("Los Angeles, USA")
关键说明
- 定位正确元素:通过CSS选择器直接定位
<mc-c-origin-destination>下的.origin input和.destination input,这些是页面可见的可交互输入框。 - 使用显式等待:用
element_to_be_clickable替代presence_of_element_located,确保元素加载完成且可操作,避免静态等待time.sleep()的不可靠性。 - iframe处理(若需):如果后续发现输入框位于iframe内,需先切换到iframe再操作,示例代码:
# 切换到目标iframe(需替换为实际iframe的定位符) WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "target_iframe_id"))) # 操作输入框... # 操作完成后切回主文档 driver.switch_to.default_content()
内容的提问来源于stack exchange,提问作者Santhosh Kumar
相关产品推荐
相关产品推荐

