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

使用Selenium的航班爬虫运行无响应,VS Code无报错求助

航班价格追踪程序无响应问题排查与修复

问题概述

开发基于Selenium的航班价格追踪毕业项目,VS Code无语法报错,但程序运行后无任何反应,需强制终止。已更新Chrome浏览器及对应ChromeDriver、Python为最新版本,检查缩进无问题。

原代码

from selenium import webdriver  # 缺失的导入,需添加
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

from selenium.common.exceptions import TimeoutException
import time

import pandas as pd

import smtplib
from email.message import EmailMessage

import schedule

departure_flight_inputs={'Departure': " ORD",
               'Arrival': " LAS",
               'Date': "Jun 1, 2024"}

return_flight_inputs={'Departure': " LAS",
               'Arrival': " ORD",
               'Date': "Jun 8, 2024"}

def find_cheapest_flights(flight_info):
    PATH = R"C:\Users\theya\OneDrive\Desktop\FlightPriceTracker\chromedriver.exe"
    driver = webdriver.Chrome(executable_path=PATH)

    leaving_from = flight_info['Departure']
    going_to = flight_info['Arrival']
    trip_date = flight_info['Date']
    
    
    #Go to Expedia
    driver.get( "https://expedia.com")

   #Click on Flights
   # The flight_xpath represent the flight button on expedia
    flight_xpath = "//a[@class='uitk-tab-anchor' and @aria-controls='search_form_product_selector_flights']"  # 移除selected类
    flight_element = WebDriverWait(driver,5).until(
        EC.presence_of_element_located((By.XPATH, flight_xpath))
        )
    flight_element.click()
    time.sleep(0.2)

      #Click on One-Way. IBecause it is easier this way.
    oneway_xpath = "//a[@class='uitk-tab-anchor' and @aria-controls='FlightSearchForm_ONE_WAY']"  # 移除selected类
    one_way_element = WebDriverWait(driver,5).until(
        EC.presence_of_element_located((By.XPATH, oneway_xpath))
        )
    one_way_element.click()
    time.sleep(0.2)

   #Part 1: Flying From, Flying To, Departure Date, Return Date
    
    #**********************  Complete Leaving From Portion  **********************
    leaving_from_xpath = "//button[@aria-label='Leaving from' and @data-stid='origin_select-dialog-trigger']"
    leaving_from_element = WebDriverWait(driver,5).until(
        EC.presence_of_element_located((By.XPATH, leaving_from_xpath))
        )
    leaving_from_element.clear()  # 添加括号调用方法
    leaving_from_element.click()
    time.sleep(1)
    leaving_from_element.send_keys(leaving_from)
    
    time.sleep(1) #Need this otherwise it will be too fast for the broswer
    leaving_from_element.send_keys(Keys.DOWN, Keys.RETURN)
    #**********************  Complete Leaving From Portion  **********************
    
    
    
    #**********************  Complete Going To Portion  **********************
    going_to_xpath = "//button[@aria-label='Going to' and @data-stid='destination_select-dialog-trigger']"
    going_to_element = WebDriverWait(driver,5).until(
        EC.presence_of_element_located((By.XPATH, going_to_xpath))
        )
    going_to_element.clear()  # 添加括号调用方法
    going_to_element.click()
    time.sleep(1)
    going_to_element.send_keys(going_to)
    
    time.sleep(1) #Need this otherwise it will be too fast for the broswer
    going_to_element.send_keys(Keys.DOWN, Keys.RETURN) #Go down on item and click on it
    #**********************  Complete Going To Portion  **********************
    
    
    
    #**********************  Complete Departure Date Portion  **********************
    departing_box_xpath = '//button[contains(@aria-label,"Departing")]'
    
    depart_box_element = WebDriverWait(driver,5).until(
        EC.presence_of_element_located((By.XPATH, departing_box_xpath))
        )
    
    depart_box_element.click() #Click on the departure box
    time.sleep(2)
    
    
    #Find the current date. WILL arrow through too
    trip_date_xpath = '//button[contains(@aria-label,"{}")]'.format(trip_date)
    departing_date_element = None
    max_attempts = 12  # 添加循环次数限制
    attempts = 0
    while departing_date_element is None and attempts < max_attempts:
        try:
            departing_date_element = WebDriverWait(driver,3).until(
            EC.presence_of_element_located((By.XPATH, trip_date_xpath))
            )
            departing_date_element.click() #Click on the departure date
        except TimeoutException:
           attempts +=1
           next_month_xpath = "//button[@data-stid='uitk-calendar-navigation-controls-next-button']"
           driver.find_element(By.XPATH, next_month_xpath).click()  # 改用新版Selenium语法
           time.sleep(1)
    
    if departing_date_element is None:
        print(f"无法找到日期: {trip_date}")
        driver.quit()
        return []
    
    depart_date_done_xpath = "//button[@data-stid='apply-date-selector' and text()='Done']"
    driver.find_element(By.XPATH, depart_date_done_xpath).click()  # 改用新版Selenium语法
    #**********************  Complete Departure Date Portion  **********************
    
    
    #**********************  Click Search  **********************
    search_button_xpath =  "//button[@id='search_button' and @type='submit' and @aria-label='Search' and text()='Search']"
    driver.find_element(By.XPATH, search_button_xpath).click()  # 改用新版Selenium语法
    time.sleep(15) #Need to let the page load properly
    #**********************  Click Search  **********************

     #Part 2: Setting Conditions for our flight
    
    #**********************  Check for Nonstop Flights Sorted by Lowest Price  **********************
    nonstop_flight_xpath = "//label[span[text()='Nonstop']]"  # 简化XPATH,避免动态ID
    
    
    if len(driver.find_elements(By.XPATH, nonstop_flight_xpath)) > 0:  # 改用新版Selenium语法
        
        driver.find_element(By.XPATH, nonstop_flight_xpath).click()  # 改用新版Selenium语法
        time.sleep(5)
        
        #Check if there are available flights
        available_flights = driver.find_elements(By.XPATH, "//span[contains(text(),'Select and show fare information ')]")  # 改用新版Selenium语法
        if len(available_flights) >  0:
            if len(available_flights) == 1: #Don't have to sort by prices here
                flights = [(item.text.split(",")[0].split('for')[-1].title(),
                            item.text.split(",")[1].title().replace("At",":"),
                            item.text.split(",")[2].title().replace("At",":"),
                            item.text.split(",")[3].title().replace("At",":")) for item in available_flights[0:5]]

            else:
                #Sort by lowest prices
                driver.find_element(By.XPATH, "//select[@id='sort-filter-dropdown-SORT']/option[@value='PRICE_INCREASING']").click()  # 改用新版Selenium语法
                time.sleep(5)
                flights = [(item.text.split(",")[0].split('for')[-1].title(),
                            item.text.split(",")[1].title().replace("At",":"),
                            item.text.split(",")[2].title().replace("At",":"),
                            item.text.split(",")[3].title().replace("At",":")) for item in available_flights[0:5]]
            
            
            print("Conditions satisfied for: {}:{}, {}:{}, {}:{}".format("Departure",leaving_from,
                                                             "Arrival",going_to,
                                                             "Date",trip_date))
            driver.quit()
            return flights
    else:
        print('Not all conditions could be met for the following: "{}:{}, {}:{}, {}:{}'.format("Departure",leaving_from,
                                                                                             "Arrival",going_to,
                                                                                             "Date",trip_date))
        driver.quit()
        return []
    

    #**********************  Check for Nonstop Flights Sorted by Lowest Price  **********************


def send_email():
    #Get return values
    departing_flights = find_cheapest_flights(departure_flight_inputs)
    return_flights = find_cheapest_flights(return_flight_inputs)

    #Put it into a dataframe to visualize this more easily
    df = pd.DataFrame(departing_flights + return_flights)
    
    if not df.empty: #Only send an email if we have actual flight info
        email = "theyamarlyons@gmail.com"  # 直接赋值邮箱,而非读取文件
        password = "$mallJoke11"  # 实际项目建议用环境变量存储密码
        
        msg = EmailMessage()
        
        msg['Subject'] = "Python Flight Info! {} --> {}, Departing: {}, Returning: {}".format(departure_flight_inputs['Departure'], departure_flight_inputs['Arrival'], departure_flight_inputs['Date'],return_flight_inputs['Date'])
        
        msg['From'] = email
        msg['To'] = email
        
        msg.add_alternative('''\
            <!DOCTYPE html>
            <html>
                <body>
                    {}
                </body>
            </html>'''.format(df.to_html()), subtype="html")
    
            
        with smtplib.SMTP_SSL('smtp.gmail.com',465) as smtp:
            smtp.login(email,password)
            smtp.send_message(msg)
    

schedule.clear()
schedule.every(30).minutes.do(send_email)

while True:
    schedule.run_pending()
    time.sleep(1)

核心修复点

  • 缺失WebDriver导入:添加from selenium import webdriver,否则程序会因找不到webdriver对象静默报错。
  • XPATH定位错误:移除Flights/One-Way按钮XPATH中的uitk-tab-anchor-selected类(首次打开页面时默认未选中),简化Nonstop筛选的XPATH避免动态ID问题。
  • 未调用clear()方法:将clear改为clear(),实际执行清空输入框操作。
  • 日期循环无限执行风险:添加最大循环次数限制,避免因目标日期不存在导致无限循环。
  • 旧版Selenium语法替换:将find_element_by_xpath替换为find_element(By.XPATH, ...),适配Selenium 4版本。
  • 邮件读取逻辑错误:直接赋值邮箱字符串,而非试图读取名为邮箱地址的文件。

调试建议

  • 启用ChromeDriver日志:添加以下代码初始化driver,查看详细运行日志定位问题:
    from selenium.webdriver.chrome.options import Options
    options = Options()
    options.add_argument("--log-level=DEBUG")
    driver = webdriver.Chrome(executable_path=PATH, options=options)
    
  • 在关键步骤(如页面跳转、元素点击)后添加print语句,确认程序执行到的位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 19:18:09