python实现12306抢票及自动邮件发送提醒付款功能


Posted in Python onMarch 08, 2018

#写在前面,这个程序我已经弄出来了,但是因为黄牛泛滥以及懒人太多,整个程序的代码就不贴出来了,这里纯粹就是技术交流。

只做技术交流、、、、、

python实现12306抢票及自动邮件发送提醒付款功能python实现12306抢票及自动邮件发送提醒付款功能

嗯,程序结束后,自己还是得手动付款。

废话不多说,下面就直接开始技术主要部分阐述。

先讲理论部分:首先我们需要代码实现一个浏览器功能,那么模块基本上可以确定urllib.parse、urllib.request,这两个包都是和网址有关的模块,那么咱们去登录一个网址,特别是有验证码这些的网址,我们登录进去是不是就行了?答案是对的,但是我们用代码实现的话,这个网址可能每次都有可能被代码去请求,那么服务器怎么知道我们是一个人,而不是多个浏览器不同的用户呢?

此时cookie就非常重要了,在代码中设置好cookie,那么对方服务器自然就知道我们是一个人,比较服务器都是这么区分的。python3中 cookie这个功能是封装在http.cookiejar这个模块之内。好了,代码如下:

# coding=utf-8
# author: Jason
# time:2018/1/16 20:00:00
#version:1.0
import urllib.request as ul
import urllib.parse as uz
import http.cookiejar as cookielib
from json import loads
c=cookielib.LWPCookieJar()#先把cookie对象存储为cookiejar的对象
cookie = ul.HTTPCookieProcessor(c)#把cookiejar对象转换为一个handle
opener = ul.build_opener(cookie)#建立一个模拟浏览器,需要handle作为参数
ul.install_opener(opener)#安装一个全局模拟浏览器,代表无论怎么访问都是一个浏览器操作而不是分开获取验证码等msg

好了,如此一来,我们代码的初步实现已经完成,接下来就是进入网络分析部分

首先可以使用google浏览器或者搜狗浏览器(本人用的搜狗),打开F12,也就是开发者模式,登录12306的登录地址 https://kyfw.12306.cn/otn/login/init

python实现12306抢票及自动邮件发送提醒付款功能

两个红圈中第二个是验证码来源,此时我们只需要记录这个网页(点进去)的详细情况,写入代码当中,python3中urllib.request这个模块打开既可

python实现12306抢票及自动邮件发送提醒付款功能

如此便是验证码来源,那么如何用代码捕捉呢?首先我们可以先乱输入密码,乱点验证码,然后我们直接点击登录

python实现12306抢票及自动邮件发送提醒付款功能

多了一个很奇妙的东西,此时,这里就是验证码验证的网址,那么我们是不是应该记录下来呢?很简单,到Headers里面就全都看得到了

python实现12306抢票及自动邮件发送提醒付款功能

上面那个是服务器验证网址,下面就是我们回复给他的东西,那么那个163,121其实就是我乱点的验证码坐标了。至于为啥是坐标,因为它是用鼠标去点图片,那么他只可能是记录坐标,除非他自己搞了一套人工智能验证图片,但基于他几年前就这么玩了,人工智能根本没有怎么开始,他自然只能是最原始的技术而已。

那么这代表了他是先验证验证码,那么验证密码的在哪?自然是需要验证码这关能过,那我们输一个正确的验证码,再写个错密码,登录

python实现12306抢票及自动邮件发送提醒付款功能

此时可以看到,和验证码一样的方法,我们的回复与验证都在这几个圈了,还记得上面验证码失败的时候回复给我们的code是不是有个数字?这个也很重要,那么可以看看我们的验证成功的验证码返回给我们的是什么东西

python实现12306抢票及自动邮件发送提醒付款功能

这次我们看到了,验证码成功,显示是4,好,那我们不就可以进行条件判断了么?

那么如何打开一个网址然后把我们点的东西一起发过去呢?上代码

headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'}#先写个头,表示我这是浏览器用户登录而不是代码登录,如果不写,代码默认用的签名之类的是编程语言的标识,这样对方服务器很容易就发现你是个脚本了
def get_code():#获取验证码的步骤
  req = ul.Request('https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&0.6758635422370105')
  req.headers = headers
  code_file = opener.open(req).read()#此时为浏览器的open而不再是ul.urlopen,下同
  with open(r'C:\Users\Administrator\Desktop\12306自动抢票\code.png','wb')as f:
    f.write(code_file)

把验证码直接下载后方电脑上,后面要坐标只需要打开这个图既可输入,坐标的输入方式我用字典表示给大家看{1:(45,45)}{2:(120,45)}{3:(180,45)}{4:(255,45)}{5:(45,120)}{6:(120,120)}{7:(180,120)}{8:(255,120)}

根据这个验证码的排序,我相信读者应该知道顺序怎么来的吧,比较坐标就能懂了。

继续

def main_():
  get_code()
  code = input('输入验证码:')
  req = ul.Request('https://kyfw.12306.cn/passport/captcha/captcha-check')
  req.headers = headers

  data = {
    'answer':code,
    'login_site':'E',
    'rand':'sjrand'
  }
  data = uz.urlencode(data).encode()#把字典转换为URL query string,此时是str,要把它变为byts。

  html = opener.open(req,data= data).read().decode()#读取出来是byts格式,转换为‘utf-8(默认)
  print(html)
  result = loads(html)
  if result['result_code']=='4':
    print('验证码通过')
    rep = ul.Request('https://kyfw.12306.cn/passport/web/login')
    rep.headers = headers
    data = {'username':'这里就是你用户名',
        'password':'这里就是你的密码',
        'appid':'otn'
    }
    data = uz.urlencode(data).encode() #看到了吗,这就是你给服务器回复的东西

    html1 = opener.open(rep,data = data ).read().decode()
    result1 = loads(html1)
    if result1['result_code'] == 0:
      print('账户密码验证通过')
    else:
      print(result1['result_message'])

  else:
    print('验证码校验失败,重来')


if __name__ == '__main__':
  main_()

此时,咱们就过了验证码密码这一关,后面是不是又要查票?那么同样的方法,我们就可以以此类推到最后一步,这里就不一一贴代码了

ps:查代码这几步的信息可是很重要喔,我们要把它记录好,并且这里面的信息包含了各种作为信息以及他们的顺序,多测试几次基本都能搞出来,这里就是提醒一点

python实现12306抢票及自动邮件发送提醒付款功能

找找规律,然后用split的方法完全就可以切割出来,然后一个循环,就可以得到第几个元素是我们要的,那么后面就可以标志判断返回值如果是无,就没票可以继续查询,直到有票就可以下一步;

那么有票的话,后面一样也是以此类推的方式,代码我就不重现了,很简单,我就把后面出现需要请求的网址都发出来供大家观摩

查询车票信息

url = 'https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=%s&leftTicketDTO.from_station=%s&leftTicketDTO.to_station=%s&purpose_codes=ADULT'%(train_data,from_station,to_station)
req = ul.Request('https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest')#确定订单信息
req = ul.Request("https://kyfw.12306.cn/otn/confirmPassenger/initDc")#验证订单
req = ul.Request('https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs')#准备跨到下单中的过度
req = ul.Request('https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo')#检查订单信息
req = ul.Request('https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount')#信息提交给服务器,准备进入下单步骤
req = ul.Request('https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue')#正式进入下单步骤
req = ul.Request('https://kyfw.12306.cn/otn/confirmPassenger/queryOrderWaitTime?random=%s&tourFlag=dc&_json_att=&REPEAT_SUBMIT_TOKEN=%s'%(numb,time.time()))#下单确认中,此时这个网址一般是进行两次访问,不知为何,我还是做了两次访问,numb是前面查询车票点击预定回复我们的信息中的一条,有点难找喔,我曾经找了三天。。。当然是因为自己不仔细而已
zreq = ul.Request("https://kyfw.12306.cn/otn/confirmPassenger/resultOrderForDcQueue")#最后的结果回执,如果一切都顺利,那么票就已经订了。我一般是打印他返回的内容
'''
      zreq = ul.Request("https://kyfw.12306.cn/otn/confirmPassenger/resultOrderForDcQueue")
      zreq.headers = headers
      data ={"REPEAT_SUBMIT_TOKEN":"%s"%numb,
          "_json_att": "",
          "orderSequence_no":orderId
          }
      data = uz.urlencode(data).encode()
      html = opener.open(zreq,data=data).read().decode()
      result = loads(html)
      print('代码全部过完,回去登录下是否搞定')
      print(result)
      print(result['data']['submitStatus'])
      if result['data']['submitStatus'] == True:
        print('购票成功')
        return True
      else:
        print('购票失败,重试其他列车')
        continue
'''
最终的回执代码详细 信息,读者可以自己尝试多次,得到自己的回复代码确认是否购票成功,因为result['data']['submitStatus']==True只不过是确认订单状态而已,这个被我改动过,你可以多次尝试

最后的最后,火车票预订成功只有30分钟支付时间,所以我为了防止订好票但是我人不在,特意写了qq邮件通知

qq邮件通知:

def email():#这是我订票后给自己发邮件的函数
  import smtplib
  from email.mime.text import MIMEText
  import time
  text = '已经为%s抢到票,速度登录12306付款,用户名:%s,密码:%s'%(NAME,username,password)
  msg = MIMEText(text, 'plain', 'utf-8')
  msg_From = '2059****16@qq.com'
  msg_To = '5043****75@qq.com'#是的,我有两个qq,一个发一个收
  smtpSever = 'smtp.qq.com' # qq邮箱的smtp Sever地址
  smtpPort = '465' # 开放的端口
  sqm = 'q********eghe' # 在登录smtp时需要login中的密码应当使用授权码而非账户密码
  msg['from'] = msg_From
  msg['to'] = msg_To
  msg['subject'] = 'Python自动邮件-%s' % time.ctime()
  smtp = smtplib
  smtp = smtplib.SMTP_SSL()
  '''
  smtplib的connect(连接到邮件服务器)、login(登陆验证)、sendmail(发送邮件)
  '''
  smtp.connect(smtpSever, smtpPort)
  smtp.login(msg_From, sqm)
  smtp.sendmail(msg_From, msg_To, str(msg))
  # s = smtplib.SMTP("localhost")
  # s.send_message(msg)
  smtp.quit()
  print('邮件已发送~你可以安心去玩了')
def emailforcode():#此函数是防止查询有票但12306账号掉线人不在无法订票的提醒
  import smtplib
  from email.mime.text import MIMEText
  import time
  text = '%s账号下线,速度登录验证12306' % NAME
  msg = MIMEText(text, 'plain', 'utf-8')
  msg_From = '205****516@qq.com'
  msg_To = '50****75@qq.com'
  smtpSever = 'smtp.qq.com' # qq邮箱的smtp Sever地址
  smtpPort = '465' # 开放的端口
  sqm = 'qowa*******ghe' # 在登录smtp时需要login中的密码应当使用授权码而非账户密码
  msg['from'] = msg_From
  msg['to'] = msg_To
  msg['subject'] = 'Python自动邮件-%s' % time.ctime()
  smtp = smtplib
  smtp = smtplib.SMTP_SSL()
  '''
  smtplib的connect(连接到邮件服务器)、login(登陆验证)、sendmail(发送邮件)
  '''
  smtp.connect(smtpSever, smtpPort)
  smtp.login(msg_From, sqm)
  smtp.sendmail(msg_From, msg_To, str(msg))
  # s = smtplib.SMTP("localhost")
  # s.send_message(msg)
  smtp.quit()
  print('邮件已发送~')

如此就大功告成了。

不能发完整的代码(本身目的就是为了技术交流而已,防止懒人盗码乱搞),但是我相信各位开发中的朋友们只要有逻辑,有开头,只要自己肯动手,都可以自己钻研出来,举一反三。毕竟我就是这样搞出来的,我从来都相信,只要肯学,都会学会,只要肯做,都可以做成。

总结

以上所述是小编给大家介绍的python实现12306抢票及自动邮件发送提醒付款功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
python+mysql实现简单的web程序
Sep 11 Python
python实现文件快照加密保护的方法
Jun 30 Python
django轻松使用富文本编辑器CKEditor的方法
Mar 30 Python
python 容器总结整理
Apr 04 Python
Django forms组件的使用教程
Oct 08 Python
Django csrf 验证问题的实现
Oct 09 Python
对python中的float除法和整除法的实例详解
Jul 20 Python
python 两个数据库postgresql对比
Oct 21 Python
python 实现从高分辨图像上抠取图像块
Jan 02 Python
Python自带的IDE在哪里
Jul 01 Python
Python如何解除一个装饰器
Aug 07 Python
python 如何将两个实数矩阵合并为一个复数矩阵
May 19 Python
TensorFlow模型保存/载入的两种方法
Mar 08 #Python
python2.7 json 转换日期的处理的示例
Mar 07 #Python
教你用Python创建微信聊天机器人
Mar 31 #Python
为什么入门大数据选择Python而不是Java?
Mar 07 #Python
详解Python中如何写控制台进度条的整理
Mar 07 #Python
python爬虫爬取网页表格数据
Mar 07 #Python
python使用mysql的两种使用方式
Mar 07 #Python
You might like
为什么那些咖啡爱好者大多看不上连锁咖啡店?
2021/03/06 咖啡文化
php下图片文字混合水印与缩略图实现代码
2009/12/11 PHP
php中邮箱地址正则表达式实现与详解
2012/04/24 PHP
php二维数组排序详解
2013/11/06 PHP
php set_include_path函数设置 include_path 配置选项
2016/10/30 PHP
Mootools 1.2教程 设置和获取样式表属性
2009/09/15 Javascript
Safari5中alert的无限循环BUG
2011/04/07 Javascript
Javascript字符串对象的常用方法简明版
2014/06/26 Javascript
JQuery表格拖动调整列宽效果(自己动手写的)
2014/09/01 Javascript
如何编写高质量JS代码(续)
2015/02/25 Javascript
jQuery+CSS3折叠卡片式下拉列表框实现效果
2015/11/02 Javascript
一些实用性较高的js方法
2016/04/19 Javascript
JavaScript实现打开链接页面的方式汇总
2016/06/02 Javascript
js获取浏览器和屏幕的各种宽度高度
2017/02/22 Javascript
html中通过JS获取JSON数据并加载的方法
2017/11/30 Javascript
Vue+Element UI+Lumen实现通用表格分页功能
2019/02/02 Javascript
微信小程序导航栏跟随滑动效果的实现代码
2019/05/14 Javascript
详解微信小程序胶囊按钮返回|首页自定义导航栏功能
2019/06/14 Javascript
VueJS实现用户管理系统
2020/05/29 Javascript
原生js+css实现tab切换功能
2020/09/17 Javascript
JavaScript代码实现微博批量取消关注功能
2021/02/05 Javascript
浅谈Python实现2种文件复制的方法
2018/01/19 Python
python线程池threadpool使用篇
2018/04/27 Python
详解Python的数据库操作(pymysql)
2019/04/04 Python
python实现粒子群算法
2020/10/15 Python
阿联酋团购网站:Groupon阿联酋
2016/10/14 全球购物
世界上最大的高分辨率在线图片库:Alamy
2018/07/07 全球购物
小学校园活动策划
2014/01/30 职场文书
贷款担保书范文
2014/05/13 职场文书
师德师风自我评价范文
2014/09/11 职场文书
2015年度培训工作总结范文
2015/04/02 职场文书
2016年度师德标兵先进事迹材料
2016/02/26 职场文书
大学生奖学金获奖感言(范文)
2019/08/15 职场文书
详解JSON.parse和JSON.stringify用法
2022/02/18 Javascript
基于Python实现流星雨效果的绘制
2022/03/18 Python
Mybatis-Plus 使用 @TableField 自动填充日期
2022/04/26 Java/Android