吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 16366|回复: 120
收起左侧

[Python 转载] 12306车票剩余数信息监控,国庆回家没买到票的可以看看哦~~

    [复制链接]
朝夕忆浅 发表于 2018-9-13 17:47
本帖最后由 朝夕忆浅 于 2018-9-13 17:50 编辑


来吾爱也好久了,一直也没有发过贴,今天上班闲着无聊,想起自己从老家来的票还没买到,就写了个python的动车剩余票数监控,现分享给大家~~
新手发帖,有不好或不对的地方还请大家指出哦~~


以下为源代码

[Asm] 纯文本查看 复制代码
import requests
import json
import smtplib
import sys
import time
from email.mime.text import MIMEText
from email.header import Header
class tl12306:
    def __init__(self):
        self.num = 1
        # 替换为你要查询的url地址
        self.url = 'https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.train_date=2018-10-07&leftTicketDTO.from_station=LYS&leftTicketDTO.to_station=FZS&purpose_codes=ADULT'
    def getlist(self):
        try:
            r = requests.get(self.url)
            if r.status_code == 200:
                j = json.loads(r.text)
                k = j['data']
                for r in k['result']:
                    # 以下共查询了5个车次信息,如需更多请自行添加
                    if "|D6577|" in r: # 获取D6577车次信息
                        # 查询站票、二等票是否还有票,不为无则视为有票发送邮件通知,如需监控一等票请自行添加
                        if r.split('|')[-7] != '无' or r.split('|')[-11] != '无':
                            str1 = 'D6577,有票啦~~'
                            print(str1)
                            self.send_mail(str1)
                    elif "|D6435|" in r:
                        if r.split('|')[-7] != '无' or r.split('|')[-11] != '无':
                            str2 = 'D6435,有票啦~~'
                            print(str2)
                            self.send_mail(str2)
                    elif "|D6437|" in r:
                        if r.split('|')[-7] != '无' or r.split('|')[-11] != '无':
                            str3 = 'D6437,有票啦~~'
                            print(str3)
                            self.send_mail(str3)
                    elif "|D6439|" in r:
                        if r.split('|')[-7] != '无' or r.split('|')[-11] != '无':
                            str4 = 'D6439,有票啦~~'
                            print(str4)
                            self.send_mail(str4)
                    elif "|D6441|" in r:
                        if r.split('|')[-7] != '无' or r.split('|')[-11] != '无':
                            str5 = 'D6441,有票啦~~'
                            print(str5)
                            self.send_mail(str5)
                sys.stdout.write('\r')
                sys.stdout.write('已查询%d次~' % self.num)
                sys.stdout.flush()
                self.num+=1
            else:
                msg = '获取车票信息失败~~'
                print(msg)
                self.send_mail(msg)
        except Exception as e:
            print(e)
    def send_mail(self,str):
        # 第三方 SMTP 服务
        mail_host = "smtp.qq.com"  # 设置服务器
        mail_user = "xxxxxx@qq.com"  # 用户名 发送者的邮箱
        mail_pass = "xxxxxxxxxxxxxxxxx"  # 口令 登录邮箱开启POP3/SMTP服务,输入授权码
        sender = 'xxxxxxx@qq.com' #  发送者的邮箱
        receivers = ['111111111@qq.com']  # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
        message = MIMEText(str, 'plain', 'utf-8')
        message['From'] = Header("发送者的名字", 'utf-8') 
        message['To'] = Header("接收者的名字", 'utf-8')
        subject = str
        message['Subject'] = Header(subject, 'utf-8')
        try:
            smtpObj = smtplib.SMTP()
            smtpObj.connect(mail_host, 25)  # 25 为 SMTP 端口号
            smtpObj.login(mail_user, mail_pass)
            smtpObj.sendmail(sender, receivers, message.as_string())
            print("邮件发送成功")
        except smtplib.SMTPException:
            print("Error: 无法发送邮件")
    def input_second(self):
        second = input("请输入查询间隔(单位/秒): ")
        try:
            return int(second)
        except Exception:
            print('您输入的不是数字,请重新输入~~')
            return self.input_page()
if __name__ == '__main__':
    c = tl12306()
    print('程序正在运行~~关闭窗口即退出监控~')
    second = c.input_second()
    while True:
        c.getlist()
        time.sleep(second)



关于url的提取,如下~~
menu.saveimg.savepath20180913173129.jpg
menu.saveimg.savepath20180913173416.jpg

程序运行界面~~楼主把它打包成了EXE可执行文件~~
menu.saveimg.savepath20180913174054.jpg
在查询了69次之后,终于有票了,哈哈哈哈~~,注意,如果你没关掉程序,程序会一直发送邮件哦~~

邮件发送成功~~快去买票啦~~
menu.saveimg.savepath20180913174428.jpg


免费评分

参与人数 19吾爱币 +16 热心值 +17 收起 理由
lhc0205 + 1 + 1 我很赞同!
yedos + 1 用心讨论,共获提升!
qycc + 1 热心回复!
多幸运遇见baby + 1 + 1 谢谢@Thanks!
潮鸣汐落 + 1 我很赞同!
英姿飒爽d木叶君 + 1 我很赞同!
失忆方程 + 1 + 1 谢谢@Thanks!
明天何从 + 1 + 1 谢谢@Thanks!
开口笑笑 + 1 + 1 谢谢@Thanks!
caozong + 1 请勿灌水,提高回帖质量是每位会员应尽的义务!
缄默难在言 + 1 + 1 我很赞同!
coomka + 1 + 1 谢谢@Thanks!
lilihuakai + 1 + 1 我很赞同!
静坐常思己过 + 1 + 1 谢谢@Thanks!
Ney + 1 我很赞同!
Chivalee + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
静观其静 + 1 + 1 谢谢@Thanks!
a70726 + 1 + 1 谢谢@Thanks!
wushaominkk + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

林夕丶 发表于 2018-9-13 18:02
唉电脑没环境做成个exe多好
shengzhigang 发表于 2018-9-13 19:15
我是缺源码的人吗?我是缺打包成了EXE可执行文件的方法
LemonX 发表于 2018-9-15 14:56
本帖最后由 LemonX 于 2018-9-15 16:11 编辑

在楼主的基础上稍作修改,可输入 日期,起点站,终点站 自动匹配url获取余票信息.
变更余票提示为:
1、如果有余票数量,则显示余票数量,否则仅显示有票。
2、车次由原来的制定车次变更为遍历所有的车次信息,并返回有票的车次信息
3、加入header,模拟浏览器访问
4、加入根据起止站点去匹配站点编码,再将编码加入生成url 【再也不需要去浏览器打开调试,然后复制NetWork的Header中的URL粘贴过来】
4、等待时间变更为随机等待,听说能稍稍避免被反爬虫,主要是懒,懒得去输入
5、邮件发送,由原来的每个车次发送结果变更为【每次查询仅发送一次】,强迫症讨厌被过分打扰
6、加入发送到微信,使用的是wxpy模块,需要先pip install wxpy .麻烦的是需要扫码登陆
[Python] 纯文本查看 复制代码
import requests
import json
import smtplib
import time
from random import randint#随机函数

from email.mime.text import MIMEText
from email.header import Header
from wxpy import *
headers={
    "Host": "kyfw.12306.cn",
    "If-Modified-Since": "0",
    "Referer": "https://kyfw.12306.cn/otn/leftTicket/init",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36"
}

class tl12306(object):
    def __init__(self):
        self.num=1
        #按需停止查询
        self.finded_tiket=False#标识是否有票,有票则停止查询,避免对12306无效访问,造成带宽拥堵而且由ip封杀的风险【不给12306添堵了,反正咱要的信息已经有了】
        self.station_name_url='https://kyfw.12306.cn/otn/resources/js/framework/station_name.js' #起始站点信息表,根据起止站点获取站点编码code
        # 灵活修改为模拟输入【日期,起止站点由用户输入】
        self.url = 'https://kyfw.12306.cn/otn/leftTicket/queryA?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'
    def get_station_code(self,from_station,to_statian):
        '''根据起止站站点名去获取对应的站点编码'''
        result={}
        result['from_code']=''
        result['to_code']=''
        r = requests.get(url=self.station_name_url,verify=False).text
        for i in r.split('@'):
            # i 的格式为  bjb|北京北|VAP|beijingbei|bjb|0
            if len(i.split('|')) >= 3:#是否大于3个成员,排除返回起始无效字段ar station_names ='
                stationText=i.split('|')[1]
                stationCode=i.split('|')[2]
                if stationText==from_station:
                    result['from_code']=stationCode
                elif stationText==to_statian:
                    result['to_code']=stationCode
                if result['from_code']!='' and result['to_code']!='':#找到起止code 后直接退出,避免无效等待
                    return result
    def getlist(self,data,fromStaion,toStation):
        '''根据传入的日期,起点站,终点站去查询余票信息'''
        try:
            r=requests.get(self.url.format(data,fromStaion,toStation),headers=headers)
            if r.status_code==200:
                j=json.loads(r.text)
                k=j['data']
                print(str(k['map']))#站点信息(含同城异站站点) 如:{'KMM': '昆明', 'KOM': '昆明南', 'NNZ': '南宁'}
                last_result=[]#所有车次所有余票信息列表
                for r in k['result']:
                    strarray=r.split('|')
                    train_num=str(strarray[3])#车次
                    seat1=str(strarray[-6])#一等座
                    seat2=str(strarray[-7])#二等座
                    seat3=str(strarray[-11])#站票
                    result=''
                    if seat1 != '无' and  seat1 != '':
                        result +=' 一等座有票!{};'.format('' if seat1=='有' else '余票:{}'.format(seat1)) #pyrhon的三目运算,如果返回实际剩余票数,则显示余票数
                    if seat2 != '无' and  seat2 != '':
                        result +=' 二等座有票!{};'.format('' if seat2=='有' else '余票:{}'.format(seat2))
                    if seat3 != '无' and  seat3 != '':
                        result +=' 站票有票!{};'.format('' if seat3=='有' else '余票:{}'.format(seat3))
                    if result!= '':
                        self.finded_tiket=True#查到票就标记已有票,不再刷新页面,如果不是自己想要的车次,可以注释此行代码,或者修改判断逻辑
                        result = '{},有票啦~~;{}\n'.format(train_num,result)
                        last_result.append(result)
                        print(result)
                self.send_mail(str(k['map'])+'\n'+'  '.join(last_result))
                print('已查询%d次' %self.num)
                self.num +=1
                return last_result
            else:
                print('获取车票失败!')
                self.send_mail('获取车票失败')
        except Exception as e:
            print(e)
    def send_mail(self,str):
        #第三方SMTP服务
        mail_host="smtp.qq.com"#设置服务器
        mail_user="xxxxxx@qq.com"#发送者邮箱
        mail_pass='gsvwqbXXXXXtwjclwjbddcdfddjb'# 口令 登录邮箱开启POP3/SMTP服务,输入授权码
        sender="XXXX@qq.com"
        receivers=['XXXX@qq.com']  # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
        message=MIMEText(str,'plain','utf-8')#邮件文本内容
        message['From']=Header('Lemon','utf-8')
        message['to']=Header('Lemon_too','utf-8')
        message['Subject']=Header('余票查询结果','utf-8')#邮件标题
        try:
            smtpobj=smtplib.SMTP()
            smtpobj.connect(mail_host,25)#25为端口号
            smtpobj.login(mail_user,mail_pass)
            smtpobj.sendmail(sender,receivers,message.as_string())
            print('邮件发送成功')
        except smtplib.SMTPException:
            print('Error: 无法发送邮件{}'.format(smtplib.SMTPException))
   
    #发送消息到微信
    def send_msg_to_wachat(self,data):
        bot = Bot()
        my_friend = bot.friends().search(u'Lemon')[0]    #你朋友/自己的微信名称,不是备注,也不是微信帐号。。
        my_friend.send(data)
    def input_date(self):
        return input('请输入查询日期【yyyy-MM-dd】:')
    def input_from(self):
        return input('请输入起点站站名:')
    def input_to(self):
        return input('请输入到站站名:')

if __name__=='__main__':
    c=tl12306()
    print('程序开始运行')
    while c.finded_tiket==False: #如果找到票了,停止查询
        #输入日期,制定格式为 2018-10-01 
        date=c.input_date()
        #输入起点站 站名
        fromStaion=c.input_from()
        #输入终点站 站名
        toStation=c.input_to()
        #由起止站站名去匹配对应编码,用于生成实际访问url
        stationCode_Info=c.get_station_code(fromStaion,toStation)
        print(stationCode_Info)
        last_result=c.getlist(date,stationCode_Info['from_code'],stationCode_Info['to_code'])
        c.send_msg_to_wachat(last_result)
        #随机等待,避免访问过快而被禁ip等受限访问结果
        time.sleep(randint(5,10))
    print('程序运行结束')

运行

运行

免费评分

参与人数 3吾爱币 +3 热心值 +2 收起 理由
redapple2015 + 1 鼓励转贴优秀软件安全工具和文档!
无相 + 1 + 1 用心讨论,共获提升!
wushaominkk + 1 + 1 用心讨论,共获提升!

查看全部评分

羅少 发表于 2018-9-13 18:10
12306bypass了解一下
yoboboo 发表于 2018-9-13 18:11
试试!!!!!!!!!!!!!!!!
but 发表于 2018-9-13 18:13
貌似360浏览器有监控功能
ClearLover 发表于 2018-9-13 18:20
楼主发出来的目的是交流学习,你们都看的是什么呢。。。
当然,楼主,我提个小建议,可以加入微信提醒更好,现在网上都有Python微信的源码了
伴我99不88 发表于 2018-9-13 18:26
厉害.........
夏虫333 发表于 2018-9-13 18:52
本帖最后由 夏虫333 于 2018-9-13 19:36 编辑

感谢分享

免费评分

参与人数 1吾爱币 -9 收起 理由
吾爱crack -9 请勿灌水,提高回帖质量是每位会员应尽的义务!

查看全部评分

会放电的皮卡丘 发表于 2018-9-13 19:00
很不错,不过票都提前买好了。感谢,笔芯
等哈不懂何必 发表于 2018-9-13 19:00
怎么没看见文件啊??
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 03:31

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表