python实现火车票监控

由于近期需要刷火车票,飞猪和智行刷没有vip略坑,自己尝试了一下。具体的思路:python requests库爬取12306余票结果,re模块正则找到想要的车次,通过twilio发送短信给自己的手机,python threading库实现多个车次的监控。

1. 环境:

linux,python 2.7,twilio
twilio : 支持python发送短信,https://www.twilio.com/ 免费注册,第一次尝试没有注册成功,百度结果是注册可能需要fq,用xxnet尝试注册仍然不行,后来无意间再试一次,没有fq也成功了,注册赠送$15,账号生成account_sid,auth_token和一个美国号码。

2. 实现:

2.1 初始化变量

url1="https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9098"
#获取12306站点代号查询结果,版本可能需要更新
html1=requests.get(url1).text
area=re.findall(ur"([\u4E00-\u9FA5]+)\|([A-Z]+)",html1)
area=dict(area)
#把站点代码映射存入一个dict
tag = '无'.decode('utf-8')
#查询结果标记
pool = []
#标记一个线程池
account_sid = '************************'
auth_token  = '**************************'
#twilio 提供的接口
twilioclient = Client(account_sid, auth_token)
#登录twilio 

2.2 生成12306查询网址

#param是订单参数
def gerUrl(param):
    from_area=area[param['fs']]
    to_area=area[param['ts']]
    time=param['data']
    url=("https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={}"
    "&leftTicketDTO.from_station={}"
    "&leftTicketDTO.to_station={}"
    "&purpose_codes=ADULT").format(time,from_area,to_area)
    return url

2.3 查询及结果处理

def work(param):
    print "mission start"
    print param
    tageturl = gerUrl(param)
    while True :
        time.sleep(1)
        #到车票日期结束后,没有结果直接结束
        if  time.mktime(time.strptime(param['data'],"%Y-%m-%d"))-time.time() < 86400:
            return
        try:
            html2=requests.get(tageturl)
            s=html2.json()["data"]["result"]
        except Exception as e:
            continue
        for area_new in s:
            list=area_new.split("|")
            if list[3]==param['zNo'] : 
                res = "%s 二等座:%s,无座:%s,%s"%(param['zNo'],list[30].encode('utf-8'),list[26].encode('utf-8'),datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
                if list[30]!= tag :
                    #sendmail(text)
                    sendmsg(res)
                    return

2.4 发送邮件及短信

def sendmsg(text):
    message = twilioclient.messages.create(
    	to="+8601234567890", 
    	from_="+12345678901",
    body=text)
    print text
    print ('Done.sent message success')

def sendmail(text):
    host = 'smtp.163.com'  
    # 设置发件服务器地址
    port = 465  
    # 设置发件服务器端口号。注意,这里有SSL和非SSL两种形式,现在一般是SSL方式
    sender = 'xxx@163.com'  
    # 设置发件邮箱,一定要自己注册的邮箱
    pwd = 'xxx'  
    # 设置发件邮箱的授权码密码,根据163邮箱提示,登录第三方邮件客户端需要授权码
    receiver = 'xxxxx'
    # 设置邮件接收人,可以是QQ邮箱
    # 设置邮件正文,这里是支持HTML的
    msg = MIMEText(text.decode('utf-8'), 'plain','gbk') 
    # 设置正文为符合邮件格式的HTML内容
    msg['subject'] = '火车票监控'.decode('utf-8')
    # 设置邮件标题
    msg['from'] = sender  
    # 设置发送人
    msg['to'] = receiver  
    # 设置接收人
    try:
        s = smtplib.SMTP_SSL(host, port)  
        # 注意!如果是使用SSL端口,这里就要改为SMTP_SSL
        s.login(sender, pwd)  
        # 登陆邮箱
        s.sendmail(sender, receiver, msg.as_string())
        # 发送邮件!
        print ('Done.sent email success')
    except smtplib.SMTPException:
        print ('Error.sent email fail')

2.5 多线程及主函数

def addtask(param):
    t=threading.Thread(target=work, args=(param,))
    t.setDaemon(True)
    t.start()
    pool.append(t)
    time.sleep(5)

if __name__ == '__main__':
    param1 = {
        'fs':'合肥'.decode('utf-8'),
        'ts':'杭州'.decode('utf-8'),
        'zNo':'D2224',
        'data':'2019-04-04'
    }

    param2 = {
        'fs':'杭州'.decode('utf-8'),
        'ts':'合肥'.decode('utf-8'),
        'zNo':'D2192',
        'data':'2019-04-07'
    }
    addtask(param1)
    addtask(param2)
    flag = True
    while flag:
        time.sleep(1)
        for t in pool:
            flag |= t.__dict__['_Thread__stopped']
    print "mission completed!"

3. 结果及完善

在这里插入图片描述
由于比较仓促,只实现了功能,还有地方没有完善也不想太折腾,比如param中日期、地点和车次不匹配的话,没有提醒功能(这个比较容易实现,就是懒…),比如python实现登录后自动抢票等等,以后有时间完善吧。
好了,全部的代码也贴一遍。

#!/usr/bin/python
# encoding: utf-8
import sys
import threading
import re,requests
import smtplib
from email.mime.text import MIMEText
import time, datetime
from twilio.rest import Client
 
url1="https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9098"
html1=requests.get(url1).text
area=re.findall(ur"([\u4E00-\u9FA5]+)\|([A-Z]+)",html1)
area=dict(area)
tag = '无'.decode('utf-8')
pool = []

account_sid = '*********************'
auth_token  = '**********************'
twilioclient = Client(account_sid, auth_token)


def gerUrl(param):
    from_area=area[param['fs']]
    to_area=area[param['ts']]
    time=param['data']
    url2=("https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={}"
    "&leftTicketDTO.from_station={}"
    "&leftTicketDTO.to_station={}"
    "&purpose_codes=ADULT").format(time,from_area,to_area)
    return url2
 
#table=PrettyTable(["车次","出发站","到达站","出发时间","到达时间","历时","特等座","一等座","二等座","软卧","硬卧","软座","硬座","无座"])
            
def work(param):
    print "mission start"
    print param
    tageturl = gerUrl(param)
    while True :
        time.sleep(1)
        if  time.mktime(time.strptime(param['data'],"%Y-%m-%d"))-time.time() < 86400:
            return
        try:
            html2=requests.get(tageturl)
            s=html2.json()["data"]["result"]
        except Exception as e:
            continue
        for area_new in s:
            list=area_new.split("|")
            if list[3]==param['zNo'] : 
                res = "%s 二等座:%s,无座:%s,%s"%(param['zNo'],list[30].encode('utf-8'),list[26].encode('utf-8'),datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
                if list[30]!= tag :
                    #sendmail(text)
                    sendmsg(res)
                    return

def sendmsg(text):
    message = twilioclient.messages.create(
    	to="+8601234567890", 
    	from_="+12345678901",
    body=text)
    print text
    print ('Done.sent message success')

def sendmail(text):
    host = 'smtp.163.com'  
    # 设置发件服务器地址
    port = 465  
    # 设置发件服务器端口号。注意,这里有SSL和非SSL两种形式,现在一般是SSL方式
    sender = 'xxxx@163.com'  
    # 设置发件邮箱,一定要自己注册的邮箱
    pwd = 'xxxxx'  
    # 设置发件邮箱的授权码密码,根据163邮箱提示,登录第三方邮件客户端需要授权码
    receiver = 'xxx'
    # 设置邮件接收人,可以是QQ邮箱
    # 设置邮件正文,这里是支持HTML的
    msg = MIMEText(text.decode('utf-8'), 'plain','gbk') 
    # 设置正文为符合邮件格式的HTML内容
    msg['subject'] = '火车票监控'.decode('utf-8')
    # 设置邮件标题
    msg['from'] = sender  
    # 设置发送人
    msg['to'] = receiver  
    # 设置接收人
    try:
        s = smtplib.SMTP_SSL(host, port)  
        # 注意!如果是使用SSL端口,这里就要改为SMTP_SSL
        s.login(sender, pwd)  
        # 登陆邮箱
        s.sendmail(sender, receiver, msg.as_string())
        # 发送邮件!
        print ('Done.sent email success')
    except smtplib.SMTPException:
        print ('Error.sent email fail')


def addtask(param):
    t=threading.Thread(target=work, args=(param,))
    t.setDaemon(True)
    t.start()
    pool.append(t)
    time.sleep(5)

if __name__ == '__main__':
    param1 = {
        'fs':'合肥'.decode('utf-8'),
        'ts':'杭州'.decode('utf-8'),
        'zNo':'D2224',
        'data':'2019-04-04'
    }

    param2 = {
        'fs':'杭州'.decode('utf-8'),
        'ts':'合肥'.decode('utf-8'),
        'zNo':'D2192',
        'data':'2019-04-07'
    }
    addtask(param1)
    addtask(param2)
    flag = True
    while flag:
        time.sleep(1)
        for t in pool:
            flag |= t.__dict__['_Thread__stopped']
    print "mission completed!"

'''
	#这里查找别人的结果,指出各个字段的意思。。。。
    YUNXIN=list[1]
    no=list[3]
    from_area=list[6]
    to_area=list[7]
    star_time=list[8]
    over_time=list[9]
    pass_time=list[10]
    TDZ=list[32] or"--"
    YDZ=list[31] or"--"
    EDZ=list[30] or"--"
    RW=list[23] or "--"
    YW=list[28] or "--"
    RZ=list[27] or"--"
    YZ=list[29] or"--"
    WZ=list[26] or"--"
    table.add_row([no,t[from_area],t[to_area],star_time,over_time,pass_time,TDZ,YDZ,EDZ,RW,YW,RZ,YZ,WZ])
#print(table)'''

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值