思路

  • 模拟登录
  1. 更新cookies(填写RAIL_DEVICEID)
  2. 下载验证图片、通过验证
  3. 账号密码登录
  4. 获取app的token
  5. 验证token
  • 查询余票
  1. 查询余票
  2. 展示余票
  3. 存储实际可买的余票
  • 填写个人信息下单
  1. 根据策略选票
  2. 发起下单请求
  3. 获取下单需要的token跟key值
  4. 获取乘车人信息
  5. 请求验证码
  6. 检查订单信息
  7. 下单
  • 邮件通知支付
  1. 下单成功通知邮箱

实现

  • 登录类

    import os
    import sys
    import time
    import json
    import base64
    import requests
    import urllib3
    from PIL import Image
    from prettytable import PrettyTable
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from config import Config
    from fxxk_12306.logger import Logger
    from fxxk_12306.common import get, postlogger = Logger('Login').get_logger()
    # 不展示不做验证请求接口的警告
    urllib3.disable_warnings()
    # 父级目录
    basedir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))class Login:"""模拟登录.思路以及实现步骤:1、通过验证码2、更新cookies3、账号密码登录4、获取app的token5、验证token参数:username 账号名(一般为手机号码)password 账号密码"""def __init__(self, username, password):self.username = usernameself.password = passwordself.base_url = 'https://kyfw.12306.cn'self.session = requests.Session()self.img_path = 'image.jpg'self.image_answer = Config.IMAGE_ANSWERdef save_image64(self):"""保存验证图片"""img_url = self.base_url + \'/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand'res = post(self.session, url=img_url).json()img = base64.b64decode(res.get('image'))with open(self.img_path, 'wb') as f:f.write(img)def translate_image_answer(self, input_code_list):"""输入编号转换"""try:return ','.join([self.image_answer[i] for i in input_code_list])except KeyError as e:logger.error('输入错误,请重新输入!')self.check_image()def show_image_location(self):"""展示图片对应数字位置"""table = PrettyTable()table.add_row([1, 2, 3, 4])table.add_row([5, 6, 7, 8])print(table)def show_image(self):Image.open(self.img_path).show()def check_image(self):"""验证图片:return: 图片答案对应的像素位置"""self.show_image()self.show_image_location()input_code = input("请在1—8中选择输入验证图片编号, 以','隔开.\n")input_code_list = input_code.split(',')answer = self.translate_image_answer(input_code_list)data = {'answer': answer,'login_site': 'E','rand': 'sjrand'}check_url = self.base_url + '/passport/captcha/captcha-check'check_result = get(self.session, url=check_url, params=data).json()if check_result['result_code'] == '4':logger.info('*' * 10 + '图片验证通过!!!' + '*' * 10)else:logger.warning(' ^@._.@^ ' + '验证错误,请睁大你的眼睛看清楚...' + ' ^@._.@^ ')self.recheck_image()return answerdef recheck_image(self):"""重新检查验证图"""self.save_image64()self.check_image()def update_cookies(self):"""更新cookie,否则登录不了"""rail_device_id = input('请输入当前的设备ID(RAIL_DEVICEID):')self.session.cookies.set('RAIL_DEVICEID', rail_device_id)# options = Options()# options.add_argument('--headless')# if 'linux' in sys.platform:#     chrome_path = os.path.join(basedir, 'chromedriver')# else:#     chrome_path = os.path.join(basedir, 'chromedriver.exe')# driver = webdriver.Chrome(chrome_path, chrome_options=options)# driver.get('https://www.12306.cn')# # 等待2秒,留时间给浏览器跑js脚本,设置cookie# time.sleep(3)# cookies = driver.get_cookies()# for cookie in cookies:#     if cookie['name'] == 'RAIL_DEVICEID':#         self.session.cookies.set('RAIL_DEVICEID', cookie['value'])# rail_device_id = self.session.cookies.get('RAIL_DEVICEID')# if rail_device_id is None:#     logger.error('更新cookies失败!')#     is_retry = input('是否重试(Y/N)?')#     if is_retry.lower() == 'y':#         self.update_cookies()#     else:#         logger.error('停止程序。。。')#         sys.exit(0)# else:#     logger.info(f'更新cookies成功(RAIL_DEVICEID:{ rail_device_id })')def login(self, answer):"""登录:param answer: 验证图片答案:return:"""login_url = self.base_url + '/passport/web/login'data = {'username': self.username,'password': self.password,'appid': 'otn','answer': answer}login_result = post(self.session, url=login_url, data=data)if login_result.status_code != 200:logger.error(f'很遗憾,登录失败了({login_result.status_code})...')try:res_json = login_result.json()if res_json.get('result_message') == '登录成功':self.session.cookies.set('uamtk', res_json.get('uamtk'))logger.info('*' * 10 + '恭喜你,登录成功啦!' + '*' * 10)else:logger.error('登录失败,请检查账号密码是否正确!')except json.decoder.JSONDecodeError as e:logger.error(f'登录接口没有返回json文件,检查cookies设置是否正确:{ self.session.cookies }')is_retry = input('是否重试(Y/N)?')if is_retry.lower() == 'y':self.login(answer)else:sys.exit(0)def get_app_tk(self):"""获取app的token"""data = {'appid': 'otn'}res = post(self.session,self.base_url +'/passport/web/auth/uamtk',data=data)if res.status_code == 200:res_json = res.json()if res_json.get('result_code') == 0:app_tk = res_json.get('newapptk')return app_tkdef auth_client(self, app_tk):"""客户端验证token是否有效:param app_tk::return:"""data = {'tk': app_tk}res = post(self.session,self.base_url +'/otn/uamauthclient',data=data)if res.status_code == 200:res_json = res.json()if res_json.get('result_code') == 0:logger.info('*' * 10 + '恭喜你,客户端认证成功啦!' + '*' * 10)return Truereturn Falsedef get_session(self):"""获取会话窗口"""return self.sessiondef run(self):"""主函数"""self.update_cookies()self.save_image64()answer = self.check_image()self.login(answer)app_tk = self.get_app_tk()self.auth_client(app_tk)def __repr__(self):return f'<Login - { self.base_url }> 模拟登录'if __name__ == '__main__':login = Login(os.environ.get('USERNAME'), os.environ.get('PASSWORD'))login.run()
    

完整项目见github:这是链接哦(欢迎 fork && star)

注:写完才注意到12306这个版本添加了候补功能,抢到票的几率几乎没了,以后要抢候补票了,还不懂候补功能的看以下本人猜测12306购票流程。

开放车票
有票
支付成功
无票
有名额
有人退票
无名额
有候补名额
有票
100%名额
开始
有限车票
购买车票
结束
有限候补名额
候补
等到有名额再来吧

总结一下:就是说我们能抢票的时间段在 开放车票100%候补名额且有人退票 这两个空档,而且第二个空档几乎不可能存在。

python实现12306自助刷票下单相关推荐

  1. 12306自动刷票下单-查票下单

    12306自动刷票下单-登录 前言 上篇写了12306登录,隔了快一个月了,才准备动手写下单篇,真的要非常感谢博客园的 Asimple朋友,如果不是看到你的留言,我几乎都忘了要写下篇了,这一点在简书上 ...

  2. 12306自动刷票下单-登录篇

    12306网站推出图片验证码以后,对于抢票软件就提出了更高的要求,本篇并不涉及自动识别验证码登录(主要是博主能力所限),提供一个途径-打码平台,这个几乎是可以破解所有验证码了,本篇主要是分享一下123 ...

  3. 12306自动刷票下单-下单

    12306自动刷票下单-登录 12306自动刷票下单-查票预定 下单 进入下单界面了 https://kyfw.12306.cn/otn/confirmPassenger/initDc 还有一个请求h ...

  4. 12306自动刷票下单-下单(三)

    12306自动刷票下单-登录篇(一) 12306自动刷票下单-查票预定(二) 下单 进入下单界面了  https://kyfw.12306.cn/otn/confirmPassenger/initDc ...

  5. 第三篇 12306自动刷票下单-下单

    下单 进入下单界面了  https://kyfw.12306.cn/otn/confirmPassenger/initDc    还有一个请求https://kyfw.12306.cn/otn/con ...

  6. 12306自动刷票下单-登录篇(一)

    12306网站推出图片验证码以后,对于抢票软件就提出了更高的要求,本篇并不涉及自动识别验证码登录(主要是博主能力所限),提供一个途径-打码平台,这个几乎是可以破解所有验证码了,本篇主要是分享一下123 ...

  7. 12306自动刷票下单-查票下单(二)

    前言 上篇写了12306登录,隔了快一个月了,才准备动手写下单篇,真的要非常感谢博客园的 Asimple朋友,如果不是看到你的留言,我几乎都忘了要写下篇了,这一点在简书上就不好,都没人看/(ㄒoㄒ)/ ...

  8. 第二篇 12306自动刷票下单-查票下单

    前言 上篇写了12306登录,隔了快一个月了,才准备动手写下单篇,真的要非常感谢博客园的 Asimple朋友,如果不是看到你的留言,我几乎都忘了要写下篇了,这一点在简书上就不好,都没人看/(ㄒoㄒ)/ ...

  9. 使用Python模拟登陆12306并全自动下单

    最近一段时间一直在研究用Python模拟登陆12306网站并自动刷票下单,经过一段时间的摸索,终于完成了代码,实现了12306刷票的功能.话不多说,先给大伙儿看看成果.我录制了一段时间,展示了自动刷票 ...

  10. python+splinter实现12306网站刷票并自动购票流程

    python+splinter实现12306网站刷票并自动购票流程 通过python+splinter,实现在12306网站刷票并自动购票流程(无法自动识别验证码). 此类程序只是提高了12306网站 ...

最新文章

  1. excel宏转txt替换强制换行符_三个步骤学会用EXCEL批量导入anki题库
  2. 零基础入门学习Python(20)-lambda表达式、filter()、map() BIF
  3. 作幼儿教育软件的感受(2005-05-09)
  4. Google帮助IE浏览器实现对SVG支持
  5. 什么是WebSocket,以及如何在Python中使用它?
  6. T-SQL with关键字
  7. 可以练计算机应用基础的网址,计算机应用基础(第3版)章节练习题答案
  8. linux 最常用的指令- [readelf][objdump] 读取elf 文件系列
  9. 关于MAC安装yarn
  10. 检测移动端设备信息 (手机品牌、系统版本等 或 PC
  11. mcu AD采样值和物理值
  12. error: undefined reference to ‘_imp___ZN12QApplicationC1ERiPPci‘
  13. 恶意程序分析之数字签名验证系统的探究
  14. 图像修复(拖影、失焦、雨雾、模糊)deblurGAN 论文解读
  15. python使用微信进行消息推送
  16. 按键控制le灯c语言程序,C语言按键控制led灯和蜂鸣器
  17. ESP32学习笔记(23)——NVS(非易失性存储)接口使用
  18. 目标检测任务超大图像的切图实现
  19. JdbcTemplate的使用
  20. React属性与状态

热门文章

  1. Idea中如何查看pom中dependency Analyzer的快捷键
  2. Encrypt加密解密
  3. Web报表系统葡萄城报表:报表设计
  4. 盘点那些走向世界的中国开源项目
  5. 弘扬时代新风建设网络文明,小趣带你揭秘肾透明细胞癌致瘤机制
  6. Java计算花费时间的模板设计模式
  7. 华为大数据与阿里大数据的区别
  8. 实战小项目——基于STM32的蓝牙小车
  9. unity物体自身轴旋转_Unity 中物体的旋转
  10. 电梯运行控制模式:如何做到人脸识别、刷卡、二维码?