写在前面
一年一度的春运悄然来临,出门在外的你是否抢到了回家的火车票呢?
多少人因为一张小小的火车票,不能回家过春节,游子此时的思乡之情,也不过是一张小小的火车票。
最近,我的朋友圈里充斥着抢票提速套餐的信息。
小编在群里很着急,现在市面上各个平台的抢票软件都是收费的,并不能保证百分百能抢到票,很多朋友甚至被一些钓鱼网站骗了,太不值得了。
作为一个技术极客,喜欢用自己的技术解决问题,现在就来做一个12306抢票软件,实现自动抢票,大家一起期待吧~
编码
1.方案效果图
是的,抢到票之后还是需要手动付款的,这样对大家来说还是很方便的~
不用多说,让我们开始讨论主要的技术部分。
2.主要代码及调试
理论部分:首先我们需要代码来实现一个浏览器的功能,所以模块基本可以确定.parse,.,这两个包是跟网站相关的模块,那我们登录一个网站,特别是有验证码的网站,答案是肯定的,但是如果我们用代码来实现的话,这个URL可能每次都会被代码请求,那么服务器怎么知道我们是一个人,而不是多个浏览器呢?那不同的用户呢?
这个很重要,如果我们在代码里设置了,对方服务器就知道我们是一个人了,这就是比对服务器区分的,这个功能封装在http模块里了,好了,代码如下:
# 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
接下来我们进入网络分析部分
首先你可以用浏览器或者搜狗浏览器(我用的是搜狗),打开F12,也就是开发者模式,登录12306的登录地址
第二个两个红色圆圈就是验证码的来源,这时候我们只需要记录下这个网页的详细信息(点击进去),写入代码里,打开这个模块就可以了。
这时候就有一个很奇妙的事情了,这时候这个就是验证码验证的URL,那么我们要不要记录下来呢?很简单,里面的东西你都能看到
上面那个是服务器验证网址,下面那个是我们回复他的。所以那个其实就是我随便点的验证码的坐标。至于为什么是坐标,因为是用鼠标点击图片,所以只能记录坐标,除非他自己开发了验证图片的人工智能,但是他干这行几年了,人工智能都还没起步,自然只能用最原始的技术。
那么这就意味着他首先要验证验证码,那么验证密码在哪呢?当然验证码是必须要通过这一关的,所以我们输入一个正确的验证码,然后写一个不正确的密码,就可以登录了。
到此我们可以看到,跟验证码一样,我们的回复和验证都是在这几个圈里。还记得我们验证码失败时收到的code是不是有数字吗?这个也很重要。那我们再看看验证成功后我们的验证码返回给我们的是什么。
这次我们看到验证码输入成功,显示为4,OK,那么我们不可以进行条件判断吗?
那么我们如何打开 URL 并发送我们订购的东西呢?
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:检查代码这几个步骤的信息很重要,一定要记录好,而且这里的信息包括各种信息以及它们的顺序,多测试几次基本就能搞清楚了,这里稍微提醒一下
找到规律,然后用split方法把它彻底切出来,然后一次循环就可以得到我们想要的元素个数,然后就可以标记返回值进行判断,如果是none,说明没有票可以继续查询,直到有票为止,才可以进行下一步;
有票的话下面也是一样的方法,我就不复现代码了,很简单,我会把需要请求的url全部贴出来,方便大家观察。
查看票务信息
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.('')#确认订单信息
req = ul.("")#验证订单
req = ul.('')#准备过渡到下单
req = ul.('')#查看订单信息
req = ul.('')#向服务器提交信息,准备进入下单步骤
req = ul.('')#正式进入下单步骤
req = ul.(''%(numb,time.time()))#订单确认,这个网址一般都会被访问两次,不知道为什么,我还是访问了两次,numb是前面的查询,点击订票,回复我们一条消息,有点难找,找了三天……当然是我不小心造成的。
zreq = ul.("")#最终结果收据。如果一切顺利,机票已经订好了。我一般会打印他返回的内容
'''
zreq = ul.(“”)
要求数 =
数据 ={"":"%s"%numb,
"": "",
"":
数据 = uz.(数据).()
html = .open(zreq,data=data).read()
= 加载(html)
print('所有代码已审核完毕,请返回登录查看是否已完成。')
打印()
打印(['数据'][''])
如果 ['数据'][''] == True:
print('购票成功')
真的
别的:
print('购票失败,请尝试其他列车')
'''
最后的收票码详情,读者可以多次尝试获取自己的回复码来确认购票是否成功,因为['data']['']==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('邮件已发送~')
到这一步,抢票程序就写得差不多了,后面我们只要调试一下就可以了。
最后再把结果给你们看,毕竟写出来不容易。
请记住手动付款。
记得手动付款~记得手动付款~
付款是最重要的,其他都不重要,你怎么看?
最后的想法
不知道看完我的文章,你有没有想自己动手的冲动呢~
需要源码的朋友可以点击我头像,私信“520”获取自动抢票源码~
使用源代码,您还可以执行以下操作
扫一扫在手机端查看
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。