Python实现12306车票查询

今天准备给师傅一块去应急响应,票都定好了,发现忘带身份证了,MDZZ…所以我就这样错失了一次宝贵的机会…更™可恶的是我去退票,竟然给我说

今天准备给师傅一块去应急响应,票都定好了,发现忘带身份证了,MDZZ…所以我就这样错失了一次宝贵的机会…更™可恶的是我去退票,竟然给我说没有身份证退不了。。。我特么的要是有身份证,我还退你大爷啊。。。

所以想搞它,一想,算了,凭我这本事搞12306还是别装逼,所以就有了这个脚本。。。

源代码如下:

#!/usr/bin/python

# -*- coding: UTF-8 -*-

'''

@Author:joy_nick

@博客:http://byd.dropsec.xyz/

'''

import urllib2

import json

import smtplib

import time

import codecs

from email.mime.text import MIMEText

import ssl

# 记录日志

def log(content):

t = time.strftime('%Y-%m-%d %H:%M:%S')

f = codecs.open('watcher.log', 'a', 'utf-8')

f.write('[%s]%s/n' % (t, content))

f.close()

# 发送邮件

def send_mail(content):

to_list=['1048834050@qq.com']

mail_host = 'smtp.163.com'

mail_user = '15565978325'

mail_pass = 'abcABC12345678'

mail_postfix = '163.com'

me = "TicketsWatcher"+"<"+mail_user+"@"+mail_postfix+">"

msg = MIMEText(content,_subtype='plain',_charset='gb2312')

msg['Subject'] = 'There are some tickets you need.'

msg['From'] = me

msg['To'] = ";".join(to_list)

server = smtplib.SMTP()

server.connect(mail_host)

server.ehlo()

server.starttls()

server.login(mail_user,mail_pass)

server.sendmail(me, to_list, msg.as_string())

server.close()

log('sent mail successfully')

try:

# 请求地址根据实际要抓取的页面修改,参数包括日期、出发站、到达站

ssl._create_default_https_context = ssl._create_unverified_context

resp = urllib2.urlopen("https://kyfw.12306.cn/otn/lcxxcx/query?purpose_codes=ADULT&queryDate=2016-10-11&from_station=NJH&to_station=SHH")

#print resp

result = resp.read()

#print result

data = json.loads(result)

datas = data['data']['datas']

print datas

for d in datas:

if d['station_train_code'] == 'T135':

content = 'tickes for hard seat of %s: %s' % (d['station_train_code'], d['yz_num'])

log(content)

if unicode(d['yz_num']) != u"无":

send_mail(content)

break

except Exception, e:

content = 'somethings wrong with the program:/n' + str(e)

log(content)

send_mail(content)

测试结果:

Python实现12306车票查询

Python实现12306车票查询

说明:

脚本分为三部分:

  • 记录日志
  • 发送邮件
  • 车票信息捕捉

记录日志会在脚本目录下生成一个 watch.log 文件,这个主要是得结合实时捕捉数据,你可以定时也可以使用 crontab ,这里我就没在加了(还有十个网站没测呢,政府网站真是尼玛啊,谁有比较好的经验望大牛们不吝分享,不说了都是泪…)

发送邮件部分主要用了 smtplib和email 库,具体代码为:

to_list=['xxx@qq.com'] #接收通知的邮箱

mail_host = 'smtp.163.com' #设置服务器

mail_user = 'xxx' #替换为发件邮箱用户名,不带@后面的

mail_pass = 'xxx' #替换为发件邮箱口令

mail_postfix = '163.com' #发件箱的后缀

msg = MIMEText(content,_subtype='plain',_charset='gb2312')

第一个参数就是邮件正文,第二个参数是MIME的subtype,传入’plain’,最终的MIME就是’text/plain’,最后设置编码为gb2312,不过为了兼容性,你可以使用 utf-8 ,具体的过程函数我就不解释了。

信息抓取部分,很简单就是把数据变为数组,从数组中匹配信息。这里我遇到一个问题: urllib2.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)>
这个错误信息主要是因为: SSL: CERTIFICATE_VERIFY_FAILED Python 升级到 2.7.9 之后引入了一个新特性,当使用urllib.urlopen打开一个 https 链接时,会验证一次 SSL 证书。而当目标网站使用的是自签名的证书时就会抛出一个 urllib2.URLError: 的错误消息.

解决方案:

import ssl

import urllib2

ssl._create_default_https_context = ssl._create_unverified_context

print urllib2.urlopen("https://www.111cn.net/").read()

附:

smtp协议的基本命令包括:

HELO 向服务器标识用户身份

MAIL 初始化邮件传输 mail from:

RCPT 标识单个的邮件接收人;常在MAIL命令后面,可有多个rcpt to:

DATA 在单个或多个RCPT命令后,表示所有的邮件接收人已标识,并初始化数据传输,以.结束

VRFY 用于验证指定的用户/邮箱是否存在;由于安全方面的原因,服务器常禁止此命令

EXPN 验证给定的邮箱列表是否存在,扩充邮箱列表,也常被禁用

HELP 查询服务器支持什么命令

NOOP 无操作,服务器应响应OK

QUIT 结束会话

RSET 重置会话,当前传输被取消

MAIL FROM 指定发送者地址

RCPT TO 指明的接收者地址

SMTP会话的流程:

  1. ehlo
  2. auth login
  3. mail from
  4. rcpt to
  5. data
  6. quit

上面说的是最普通的情况,但是现在好多企业邮件都是安全邮件的,就是通过SSL发送的邮件,这个怎么发呢?SMTP对SSL安全邮件的支持有两种方案,一种老的是专门开启一个465端口来接收ssl邮件,另一种更新的做法是在标准的25端口的smtp上增加一个 starttls 的命令来支持。

这个很简单, smtplib 里就有这个方法,叫 smtplib.starttls() 。当然,不是所有的邮件系统都支持安全邮件的,这个需要从 ehlo 的返回值里来确认,如果里面有 starttls ,才表示支持。

注意:

以上的代码为了方便我都没有判断返回值,严格说来,是应该判断一下返回的代码的,在smtp协议中,只有返回代码是2xx或者3xx才能继续下一步,返回4xx或5xx的,都是出错了。

未登录用户
全部评论0
到底啦