python Splinter 12306抢票

源码记录如下:

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

from splinter.browser import Browser
from time import sleep
import os
# from selenium.webdriver.chrome.options import Options
import logging
from log_class import Logger  # 需要一个logger库
import sys

reload(sys)
sys.setdefaultencoding('utf-8')  # 防止由于Unicode编码与ASCII编码的不兼容造成错误

class BuyTicket(object):
    def __init__(self, username, passwd, order, passengers, seatType, ticketType, daytime, starts, ends):
        # 用户名 密码
        self.username = username
        self.passwd = passwd
        # 车次,选择第几趟,0则从上之下依次点击
        self.order = order
        # 乘客名
        self.passengers = passengers
        # 席位
        self.seatType = seatType
        self.ticketType = ticketType
        # 时间格式2018-02-05
        self.daytime = daytime
        # 起始地和终点
        self.starts = starts
        self.ends = ends

        self.login_url = 'https://kyfw.12306.cn/otn/login/init'
        self.initMy_url = 'https://kyfw.12306.cn/otn/index/initMy12306'
        self.ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
        # 浏览器名称
        self.driver_name = 'firefox'  # chrome firefox
        # 火狐浏览器第三方驱动
        self.executable_path = os.getcwd()+'/geckodriver'  # 获取工程目录下的火狐驱动 chromedriver

    def login(self):
        # 访问登录网址
        self.driver.visit(self.login_url)
        # 填充用户名
        self.driver.fill("loginUserDTO.user_name", self.username)
        # sleep(1)
        # 填充密码
        self.driver.fill("userDTO.password", self.passwd)
        logbticket.info("请手动输入验证码...")
        # print('请手动输入验证码...')  # 目前没有自动验证码
        # 循环等待登录,登录成功,跳出循环
        while True:
            if self.driver.url != self.initMy_url:
                sleep(1)
            else:
                break

    def start_buy(self):
        # 这些设置都是必要的
        # chrome_options = Options()
        # chrome_options.add_argument("--no-sandbox")
        # chrome_options.add_argument("--disable-setuid-sandbox")
        # chrome_options.add_argument("disable-infobars")  # 禁用网页上部的提示栏
        # self.driver = Browser(driver_name=self.driver_name, options=chrome_options, executable_path=self.executable_path)
        self.driver = Browser(driver_name=self.driver_name,
                              executable_path=self.executable_path)
        # 设置窗口大小尺寸
        self.driver.driver.set_window_size(1400, 1000)
        # 用户登录
        self.login()
        # 进入选票网站
        self.driver.visit(self.ticket_url)
        try:
            logbticket.info("购票页面开始....")
            # print("购票页面开始....")
            # sleep(1)
            # 加载查询信息
            self.driver.cookies.add({"_jc_save_fromStation": self.starts})
            self.driver.cookies.add({"_jc_save_toStation": self.ends})
            self.driver.cookies.add({"_jc_save_fromDate": self.daytime})

            self.driver.reload()

            count = 0
            if self.order != 0:
                while self.driver.url == self.ticket_url:
                    self.driver.find_by_text("查询").click()
                    count = count+1
                    logbticket.info("第 %d 次点击查询..." % count)
                    # print("第 %d 次点击查询..." % count)
                    # sleep(1)
                    try:
                        self.driver.find_by_text("预订")[self.order - 1].click()  # 点击第几个“预订”
                        sleep(1.5)
                    except Exception as e:  # e是Exception 的一个instance
                        # print(e)
                        # print("预订失败...")
                        logbticket.error(e)
                        logbticket.error("预订失败...")
                        continue
            else:
                while self.driver.url == self.ticket_url:
                    self.driver.find_by_text("查询").click()
                    count += 1
                    logbticket.info("第 %d 次点击查询..." % count)
                    # print("第 %d 次点击查询..." % count)
                    try:
                        for i in self.driver.find_by_text("预订"):
                            i.click()
                            sleep(1)
                    except Exception as e:
                        # print(e)
                        # print("预订失败...")
                        logbticket.error(e)
                        logbticket.error("预订失败...")
                        continue

            # print("开始预订....")
            logbticket.info("开始预订....")
            # sleep(1)
            # self.driver.reload()
            sleep(1)
            # print("开始选择用户....")
            logbticket.info("开始选择用户....")
            for p in self.passengers:
                pg = self.driver.find_by_text(p)  # .last.click()
                pg.last.click()
            # print("提交订单....")
            logbticket.info("提交订单....")
            sleep(1)
            i = 0
            while len(self.passengers) > 0:
                i = i + 1
                seat_id_string = "seatType_" + str(i)
                ticket_id_string = "ticketType_" + str(i)
                self.driver.find_by_xpath('//select[@id="%s"]/option[@value="%s"]'
                                          % (seat_id_string, self.seatType)).first._element.click()
                self.driver.find_by_xpath('//select[@id="%s"]//option[@value="%s"]'
                                          % (ticket_id_string, self.ticketType)).first._element.click()
                # self.driver.select("confirmTicketType", "3")
                self.passengers.pop()
                sleep(1)
            self.driver.find_by_id("submitOrder_id").click()
            # print("开始选座...")
            logbticket.info("开始选座...")
            sleep(1.5)
            # print("确认选座....")
            logbticket.info("确认选座....")
            self.driver.find_by_text("qr_submit_id").click()

        except Exception as e:
            # print(e)
            logbticket.error(e)


city = {"深圳": "%u6DF1%u5733%2CSZQ",
        "武汉": "%u6B66%u6C49%2CWHN",
        "随州": "%u968F%u5DDE%2CSZN"}

seatT = {"硬卧": "3",
         "软卧": "4",
         "硬座": "1",
         "二等座": "O",
         "一等座": "M",
         "商务座": "9"}

if __name__ == '__main__':
    # 用户名
    username = "xxxxxxxx"
    # 密码
    password = "xxxxxx"
    # 车次选择,0代表所有车次
    order = 13
    # 乘客名,比如passengers = ['丁小红', '丁小明']
    passengers = ["xxx", "xxx"]
    # 日期,格式为:'2018-01-20'
    daytime = "2018-04-05"
    # 出发地(需填写cookie值)
    starts = city["xx"]  # 武汉
    # 目的地(需填写cookie值)
    ends = city["xx"]  # 北京
    # 席别
    seatType = seatT["二等座"]  # 二等座
    # 票种
    ticketType = "1"  # 成人票

    logbticket = Logger("bticket.log", logging.DEBUG, logging.ERROR)

    BuyTicket(username, password, order, passengers, seatType, ticketType, daytime, starts, ends).start_buy()

火狐浏览器的驱动下载地址:https://github.com/mozilla/geckodriver/releases/
logger库文件地址:https://blog.youkuaiyun.com/lijing198997/article/details/79813517

### 实现2025年春节12306自动购Python脚本 创建一个针对2025年春节期间使用的12306脚本涉及多个方面,包括但不限于登录、查询余以及提交订单等功能。下面提供了一个简化版的框架来展示如何利用`requests`库和`splinter`库实现这一目标。 #### 准备工作 确保安装必要的Python包: ```bash pip install requests splinter selenium webdriver_manager ``` #### 登录模块 由于12306网站的安全机制不断更新,模拟浏览器行为是较为可靠的方法之一: ```python from splinter import Browser import time def login_12306(username, password): with Browser('chrome') as browser: url = "https://kyfw.12306.cn/otn/resources/login.html" browser.visit(url) # 输入用户名密码并点击登录按钮 username_input = browser.find_by_id('J-userName') password_input = browser.find_by_id('J-password') submit_button = browser.find_by_css('.login-btn') username_input.fill(username) password_input.fill(password) submit_button.click() # 验证码处理(此处省略具体逻辑) captcha_handler(browser) time.sleep(5) # 等待页面加载完成 ``` #### 查询车次与下单功能 当成功登录之后,则可以通过API接口获取列车信息,并尝试预订指定日期的座位。 ```python import json import requests def search_trains(departure_station, arrival_station, date): api_url = f"https://kyfw.12306.cn/otn/leftTicket/queryTicketPrice?train_no=...&from_station={departure_station}&to_station={arrival_station}&date={date}" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)', 'Referer': 'https://www.12306.cn/index/otn/leftTicket/init' } response = requests.get(api_url, headers=headers).json() tickets_info = parse_response(response) # 解析返回的数据结构 return tickets_info def book_ticket(ticket_details): booking_api = "https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest" data = ticket_details.copy() # 构建请求参数体... session.post(booking_api, data=data) ``` 请注意上述代码仅为概念验证性质,在实际应用中还需要考虑更多细节如验证码识别、异常情况下的重试策略等[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值