python监控12306是否有火车票并发送邮件

目录

    • 环境
    • 数据解析
    • 发送邮件
    • 计划任务
    • 后台执行


环境

python3.6
用到的模块:

  • requests —–请求12306官网数据
  • sched —–定时执行
  • email —–构造邮件
  • smtplib —–发送邮件

数据解析

首先登陆到12306的余票查询页面,浏览器中按F12到network页面启用监控,然后点击查询

python监控12306是否有火车票并发送邮件_第1张图片

查询出数据可以看到服务器返回一个json文件,文件中就是网页要展示的数据

python监控12306是否有火车票并发送邮件_第2张图片

转到Headers中可以看到请求该文件的链接

python监控12306是否有火车票并发送邮件_第3张图片

https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2018-08-27&leftTicketDTO.from_station=ZZF&leftTicketDTO.to_station=CDW&purpose_codes=ADULT

看文件链接中参数:

  • train_date:车票日期
  • from_station:出发地
  • to_station:目的地
  • purpose_codes:车票种类(成人/学生)

直接访问此链接可以获得json数据,所以访问这个链接应该不需要cookie。所以,用requests发送get请求,然后解析json数据。

格式化此json

{
    data: {
        flag: "",
        map:{...},
        result: [...]
        }
}

主要数据都在result中,把result解析为一个list。

取Z49这一行的数据:

YhBPGuoW3xAhBD%2FApM98PQIvZmCwzLEDbSvk5UbIhGZPgfy3upEPNaJYQoIvyDB5pSIVWRPietsQ%0ASCHz4oQKJOhY8VCWlOaZb61bbtAJ4PQgVq8EN72dh12yQOEyG1OeSTr13egLY6%2BzyxORFcxu%2Fg4F%0AaC41NbKpMK5l8caKh35GOWsZI%2BRcpgiFstLVp1L3wRSLkBGwp%2BqCJvCPL%2FMhcmA9O6Dub7bkWpVo%0AvcWOiQARue9o5jYe5bQoZ74ngbW4t4TFaQ%3D%3D|预订|2400000Z490F|Z49|BXP|CDW|ZZF|CDW|17:36|08:39|15:03|Y|ky1p1Fop2AZbAbH4RmJUkdkP%2BS5np0lU9ofb%2F1zDI7zlskmc9fmjGswIM30%3D|20180827|3|P4|04|10|0|0||||无|||1||无|无|||||10401030|1413|0”

初看全无头绪,实际只是用“|”为分割的有关Z49的所有信息。解析时以“|”把一行数据切开。切开后的strs[0]是一个secretStr,如果要用代码控制买票需要用到此字符串,重点关注strs[20]到strs[29],这几个数组中包含了各类座位的余票情况,strs[26]对应硬卧。

import requests
def getInfo(url): # 检测是否有余票
    res = requests.get(url)
    train = 'Z49' # 要监控的车次
    if res.status_code == 200:
        ticket = res.json()['data']['result']
        for info in ticket:
            strs = info.split('|')
            if strs[3] == train:
                if strs[26] == '有':
                    sendEmail() # 检测到有余票发送邮件通知
                    return True

发送邮件

import smtplib, time
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr

def _format_addr(s): #邮件信息格式化为utf-8编码
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

def sendEmail(): # 发送邮件
    content = str('Z49! \nAt:' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) # 邮件正文
    sender = '[email protected]' # 发送方
    recv = ['[email protected]'] # 接收方
    mail_host = 'smtp.163.com' # 发送方邮件服务器地址
    mail_user = sender # 发送方账户
    mail_passwd = 'xxxxxx' # 发送方服务器授权码
    msg = MIMEText(content, _subtype='plain', _charset='utf-8')
    msg['Subject'] = Header('Z49', 'utf-8').encode() # 邮件标题
    msg['From'] = _format_addr('<%s>' % sender) # 发送方
    msg['To'] = _format_addr('terminal <%s>' % recv) # 接收方
    smtp = smtplib.SMTP_SSL(host=mail_host, port=465)
    try:
        # smtp.set_debuglevel(1)
        smtp.login(mail_user, mail_passwd) # 验证账户
        smtp.sendmail(sender, recv, msg.as_string()) # 发送邮件
        print('Email send success!')
    except smtplib.SMTPResponseException as e:
        print(e)
    finally:
        smtp.close()

计划任务

import sched, time

s = sched.scheduler(time.time, time.sleep)

def perform(inc=300): #定时任务
    print('开始执行:' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    s.enter(inc, 0, perform, (inc,))
    url = ''
    if getInfo(url) :
        print('有')
    else:
        print('无')

if __name__ == '__main__':
    s.enter(0, 0, perform, (300,)) # 每隔300秒查询一次
    s.run()

后台执行

懒一下,直接用screen挂着好了

$ screen -S train
$ python train.py

这样就算关掉Command Line程序也可以在后台运行。

你可能感兴趣的:(Python)