Python+Selenium实战:教你用自动化脚本搞定12306远程抢票(附邮箱交互技巧)

发布时间:2026/7/2 22:20:42

Python+Selenium实战:教你用自动化脚本搞定12306远程抢票(附邮箱交互技巧) PythonSelenium实战构建高可靠性的12306远程抢票系统每逢节假日火车票抢购大战总是让人焦头烂额。传统的手动操作不仅效率低下还常常因为网络延迟或操作失误错失良机。本文将带你从零构建一个基于Python和Selenium的自动化抢票系统特别针对远程操作场景优化实现无人值守的全流程自动化。1. 系统架构设计与环境准备一个完整的远程抢票系统需要解决几个核心问题如何稳定获取车票信息、如何处理验证码、如何实现跨设备协同以及如何确保长时间稳定运行。我们的系统架构分为三大模块数据采集模块负责实时查询12306余票信息决策中枢模块处理用户偏好和抢票策略执行模块完成实际的登录、订票操作环境配置步骤# 安装必要库 pip install selenium webdriver-manager requests pandas schedule浏览器驱动管理推荐使用webdriver-manager它可以自动下载和匹配当前浏览器版本的驱动from selenium import webdriver from webdriver_manager.microsoft import EdgeChromiumDriverManager driver webdriver.Edge(EdgeChromiumDriverManager().install())对于需要长时间运行的脚本建议添加以下异常处理机制from selenium.common.exceptions import NoSuchElementException, TimeoutException try: # 你的抢票代码 except NoSuchElementException as e: print(f元素未找到: {str(e)}) # 自动重试逻辑 except TimeoutException: print(页面加载超时) # 刷新页面或调整等待时间2. 智能余票监控与数据采集高效的余票查询是抢票成功的前提。12306的API接口经常变动我们需要设计一个适应性强的查询方案。车票查询参数对照表参数名示例值说明leftTicketDTO.train_date2024-10-01出发日期leftTicketDTO.from_stationBJH出发站代码leftTicketDTO.to_stationSHH到达站代码purpose_codesADULT票类型(成人/学生)推荐使用车站代码字典来提高可维护性station_codes { 北京: BJP, 上海: SHH, 广州: GZQ, 深圳: SZQ, # 其他车站... } def get_station_code(name): return station_codes.get(name, )优化后的查询函数import requests import json from datetime import datetime def query_tickets(date, from_station, to_station): base_url https://kyfw.12306.cn/otn/leftTicket/query params { leftTicketDTO.train_date: date.strftime(%Y-%m-%d), leftTicketDTO.from_station: get_station_code(from_station), leftTicketDTO.to_station: get_station_code(to_station), purpose_codes: ADULT } try: response requests.get(base_url, paramsparams, timeout10) data response.json() if data.get(status) and data.get(data): return parse_ticket_data(data[data][result]) except Exception as e: print(f查询失败: {str(e)}) return []3. 验证码处理与自动化登录验证码是自动化系统最大的挑战之一。我们的方案采用多级应对策略图像识别备用方案使用OpenCV进行简单的图形匹配人工干预通道通过邮件发送验证码图片获取人工输入智能等待策略在非高峰时段自动延迟操作邮件交互模块实现import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.image import MIMEImage def send_verification_email(image_data, recipient): msg MIMEMultipart() msg[From] your_emailexample.com msg[To] recipient msg[Subject] 12306验证码 text MIMEText(请输入下图中的验证码) msg.attach(text) image MIMEImage(image_data) image.add_header(Content-ID, verification_image) msg.attach(image) with smtplib.SMTP(smtp.example.com, 587) as server: server.starttls() server.login(your_emailexample.com, password) server.send_message(msg)登录流程优化代码from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def login(driver, username, password): driver.get(https://kyfw.12306.cn/otn/resources/login.html) # 切换到账号登录 account_tab WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CLASS_NAME, login-hd-account)) ) account_tab.click() # 输入账号密码 user_input driver.find_element(By.ID, J-userName) user_input.send_keys(username) pwd_input driver.find_element(By.ID, J-password) pwd_input.send_keys(password) # 获取验证码图片 captcha_img driver.find_element(By.ID, J-loginImg) img_data captcha_img.screenshot_as_png # 发送邮件获取人工输入 send_verification_email(img_data, your_phoneexample.com) captcha input(请输入邮件中的验证码) # 输入验证码并登录 captcha_input driver.find_element(By.ID, J-loginImgArea) captcha_input.send_keys(captcha) login_btn driver.find_element(By.ID, J-login) login_btn.click() # 等待登录成功 WebDriverWait(driver, 10).until( EC.url_contains(otn/view/index.html) )4. 抢票核心逻辑与异常处理抢票过程需要处理各种边界情况和异常我们设计了一个状态机模型来管理整个流程抢票状态转移表当前状态触发条件下一状态执行动作初始化开始抢票查询余票加载用户配置查询余票有余票提交订单锁定车次查询余票无余票等待重试设置定时器提交订单成功支付跳转支付页提交订单失败查询余票记录错误支付完成结束发送通知支付超时查询余票检查订单状态核心抢票函数实现import time from selenium.webdriver.common.keys import Keys def grab_ticket(driver, train_info, passenger_info): # 1. 填写查询条件 driver.find_element(By.ID, fromStationText).click() driver.find_element(By.ID, fromStationText).clear() driver.find_element(By.ID, fromStationText).send_keys(train_info[from_station]) driver.find_element(By.ID, fromStationText).send_keys(Keys.ENTER) # 同样处理到达站和日期... # 2. 查询车票 query_btn driver.find_element(By.ID, query_ticket) query_btn.click() # 3. 等待结果加载 time.sleep(3) # 显式等待更好这里简化 # 4. 查找目标车次 xpath f//tr[contains(id,ticket_{train_info[train_no]})] train_row driver.find_element(By.XPATH, xpath) # 5. 点击预订 book_btn train_row.find_element(By.CLASS_NAME, btn72) book_btn.click() # 6. 选择乘车人 passenger_checkbox driver.find_element( By.XPATH, f//label[contains(text(),{passenger_info[name]})]/preceding-sibling::input ) passenger_checkbox.click() # 7. 提交订单 submit_btn driver.find_element(By.ID, submitOrder_id) submit_btn.click() # 8. 确认订单 confirm_btn WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, qr_submit_id)) ) confirm_btn.click() return True异常处理增强def safe_grab_ticket(driver, train_info, passenger_info, max_retries3): for attempt in range(max_retries): try: if grab_ticket(driver, train_info, passenger_info): return True except NoSuchElementException as e: print(f尝试 {attempt1} 失败: 元素未找到 - {str(e)}) driver.refresh() time.sleep(2) except Exception as e: print(f尝试 {attempt1} 失败: {str(e)}) # 截屏保存错误现场 driver.save_screenshot(ferror_{int(time.time())}.png) return False5. 远程协同与通知系统真正的远程抢票系统需要解决设备不在身边时的操作问题。我们设计了一个基于邮件的双向通信机制系统通信协议设计查询指令发送QUERY 北京 上海 2024-10-01到指定邮箱设置偏好发送SET PREFER G123,D302设置优先车次获取状态发送STATUS获取当前抢票状态邮箱交互核心代码import imaplib import email from email.header import decode_header def check_commands(username, password): commands [] with imaplib.IMAP4_SSL(imap.example.com) as mail: mail.login(username, password) mail.select(INBOX) _, msgnums mail.search(None, UNSEEN) for msgnum in msgnums[0].split(): _, data mail.fetch(msgnum, (RFC822)) message email.message_from_bytes(data[0][1]) subject decode_header(message[Subject])[0][0] if isinstance(subject, bytes): subject subject.decode() if message.is_multipart(): for part in message.walk(): if part.get_content_type() text/plain: body part.get_payload(decodeTrue).decode() commands.append((subject, body)) break else: body message.get_payload(decodeTrue).decode() commands.append((subject, body)) return commands完整工作流程示例def main_loop(): driver init_driver() login(driver, your_12306_user, your_password) last_check 0 while True: current_time time.time() # 每小时检查一次邮件指令 if current_time - last_check 3600: commands check_commands(your_emailexample.com, email_password) process_commands(commands) last_check current_time # 执行抢票逻辑 tickets query_tickets(datetime(2024, 10, 1), 北京, 上海) if tickets: selected select_preferred_train(tickets) if selected and grab_ticket(driver, selected, {name: 张三}): send_notification(抢票成功, f已成功抢到{selected[train_no]}) break time.sleep(300) # 5分钟查询一次 if __name__ __main__: main_loop()6. 系统优化与高级技巧要让抢票系统在竞争中脱颖而出还需要一些高级优化技巧性能优化策略使用CDN加速接口查询实现分布式多节点监控动态调整查询频率高峰时段增加频率反反爬技巧随机化查询间隔30-120秒轮换User-Agent使用浏览器正常行为模式鼠标移动、滚动等浏览器指纹模拟代码from selenium.webdriver import ActionChains def simulate_human(driver): # 随机鼠标移动 actions ActionChains(driver) for _ in range(5): x_offset random.randint(-50, 50) y_offset random.randint(-50, 50) actions.move_by_offset(x_offset, y_offset) actions.pause(random.uniform(0.1, 0.5)) actions.perform() # 随机滚动 scroll_height driver.execute_script(return document.body.scrollHeight) scroll_pos random.randint(0, scroll_height) driver.execute_script(fwindow.scrollTo(0, {scroll_pos});) time.sleep(random.uniform(0.5, 2))智能重试机制def smart_retry(func, max_retries5, base_delay1): def wrapper(*args, **kwargs): retries 0 while retries max_retries: try: return func(*args, **kwargs) except Exception as e: retries 1 delay base_delay * (2 ** retries) random.uniform(0, 1) print(f操作失败{delay:.1f}秒后重试... ({retries}/{max_retries})) time.sleep(delay) raise Exception(f操作失败已达最大重试次数 {max_retries}) return wrapper # 使用装饰器 smart_retry def protected_query(): return query_tickets(...)7. 安全与合规注意事项在开发和使用自动化抢票工具时必须注意以下重要事项合法使用边界仅限个人使用不得用于商业牟利控制访问频率避免对12306服务器造成过大压力不得绕过或破坏网站的正常安全机制数据安全措施敏感信息加密存储如账号密码使用环境变量存储配置定期清理日志和截图配置管理示例import os from dotenv import load_dotenv import cryptography load_dotenv() class Config: USERNAME os.getenv(12306_USERNAME) PASSWORD os.getenv(12306_PASSWORD) EMAIL os.getenv(NOTIFICATION_EMAIL) # 其他配置...在实际项目中建议将核心功能模块化便于维护和扩展。例如可以将浏览器操作、邮件处理、数据查询等分离为独立模块通过主程序协调工作。

相关新闻