目录
python3.6
用到的模块:
首先登陆到12306的余票查询页面,浏览器中按F12到network页面启用监控,然后点击查询
查询出数据可以看到服务器返回一个json文件,文件中就是网页要展示的数据
转到Headers中可以看到请求该文件的链接
https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2018-08-27&leftTicketDTO.from_station=ZZF&leftTicketDTO.to_station=CDW&purpose_codes=ADULT
看文件链接中参数:
直接访问此链接可以获得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程序也可以在后台运行。