Selenium/Python中By.CSS_SELECTOR报无效选择器错误求助
解决Selenium选择Booking日历日期时的CSS选择器错误
问题根源
你代码里的select_dates方法存在CSS选择器语法错误:
check_in_element = self.find_element(By.CSS_SELECTOR, f'data-date="{ci_date}')
CSS属性选择器的标准格式是[属性名="属性值"],你缺少了开头的[和结尾的"],导致Selenium识别为非法选择器,直接抛出An invalid or illegal selector was specified错误。
修正方案
1. 修复CSS选择器并优化日期选择逻辑
Booking的日历需要先点击日期输入框展开面板,跨月份的日期还需要切换月份才能选中,以下是修正后的select_dates方法:
def select_dates(self, ci_date, co_date): # 先点击日期输入框,触发日历面板展开 date_input = WebDriverWait(self, 10).until( ec.element_to_be_clickable((By.CSS_SELECTOR, 'div[data-testid="searchbox-datepicker"]')) ) date_input.click() # 封装日期选择的通用函数,处理跨月份场景 def pick_target_date(target_date): while True: # 查找所有匹配目标日期的元素 date_elements = WebDriverWait(self, 10).until( ec.presence_of_all_elements_located((By.CSS_SELECTOR, f'[data-date="{target_date}"]')) ) # 找到可见的日期元素并点击 for elem in date_elements: if elem.is_displayed(): elem.click() return # 目标日期不在当前月份,点击切换到下一月 next_month_btn = WebDriverWait(self, 10).until( ec.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-testid="datepicker-next-month"]')) ) next_month_btn.click() # 依次选择入住、退房日期 pick_target_date(ci_date) pick_target_date(co_date)
2. 其他代码优化建议
- 替换
time.sleep为显式等待:显式等待比固定时长等待更可靠,能避免不必要的延迟,同时规避隐式等待和显式等待混用的冲突。比如修改select_place_to_go方法:
def select_place_to_go(self, place_to_go=None): search_field = WebDriverWait(self, 10).until( ec.element_to_be_clickable((By.CLASS_NAME, 'eb46370fe1')) ) search_field.clear() search_field.send_keys(place_to_go) search_result = WebDriverWait(self, 10).until( ec.element_to_be_clickable((By.ID, 'autocomplete-result-0')) ) search_result.click()
- 优化浏览器关闭逻辑:用用户输入替代
while(True): pass的懒办法,更友好:
# deploy代码修改 from booking.booking import Booking with Booking(teardown=False) as bot: bot.land_first_page() bot.close_ini_popup() # bot.change_currency(currency='AUD') bot.select_place_to_go('Buenos Aires') bot.select_dates(ci_date='2024-05-19', co_date='2024-06-24') input("按回车键关闭浏览器...")
完整修正后的main代码
import booking.constants as cons import os from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as ec class Booking(webdriver.Chrome): def __init__(self, driver_path=r"C:\SeleniumDrivers", teardown=False): self.driver_path = driver_path self.teardown = teardown os.environ['PATH'] += self.driver_path super(Booking, self).__init__() self.maximize_window() def __exit__(self, exc_type, exc_val, exc_tb): if self.teardown: self.quit() def land_first_page(self): self.get(cons.BASE_URL) def change_currency(self, currency=None): currency_element = WebDriverWait(self, 10).until( ec.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-testid="header-currency-picker-trigger"]')) ) currency_element.click() sltd_currency_element = WebDriverWait(self, 10).until( ec.presence_of_all_elements_located((By.CSS_SELECTOR, 'button[data-testid="selection-item"]')) ) for sltd_currency in sltd_currency_element: if currency in sltd_currency.text: sltd_currency.click() break def close_ini_popup(self): ini_popup_element = WebDriverWait(self, 10).until( ec.element_to_be_clickable((By.CSS_SELECTOR, 'button[aria-label="Dismiss sign-in info."]')) ) ini_popup_element.click() def select_place_to_go(self, place_to_go=None): search_field = WebDriverWait(self, 10).until( ec.element_to_be_clickable((By.CLASS_NAME, 'eb46370fe1')) ) search_field.clear() search_field.send_keys(place_to_go) search_result = WebDriverWait(self, 10).until( ec.element_to_be_clickable((By.ID, 'autocomplete-result-0')) ) search_result.click() def select_dates(self, ci_date, co_date): # 展开日历面板 date_input = WebDriverWait(self, 10).until( ec.element_to_be_clickable((By.CSS_SELECTOR, 'div[data-testid="searchbox-datepicker"]')) ) date_input.click() def pick_target_date(target_date): while True: date_elements = WebDriverWait(self, 10).until( ec.presence_of_all_elements_located((By.CSS_SELECTOR, f'[data-date="{target_date}"]')) ) for elem in date_elements: if elem.is_displayed(): elem.click() return # 切换到下一个月份 next_month_btn = WebDriverWait(self, 10).until( ec.element_to_be_clickable((By.CSS_SELECTOR, 'button[data-testid="datepicker-next-month"]')) ) next_month_btn.click() pick_target_date(ci_date) pick_target_date(co_date)
内容的提问来源于stack exchange,提问作者Nimrod
相关产品推荐
相关产品推荐

