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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 18:21:16