又是一年,立刻就要回家过年了,尚未买到票的小伙伴们是否已经像热锅上的蚂蚁了无脑的开始找黄牛了? css
俗话说的好,求人不如求本身,抢票这玩意,其实我以为我也能够~ html
来来来,直接入正题吧! 这里有两种方案,一种是基于Selenium2的自动化框架控制浏览器实现,另外一种方案则是基于Python自身的爬虫package如request,urllib等来实现,本文实现第一种方案,第二种方案也在摸索中。chrome
https://kyfw.12306.cn/otn/resources/login.html
https://kyfw.12306.cn/otn/view/index.html
https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc
复制代码
这里使用的是chrome浏览器浏览器
在此处下载
https://sites.google.com/a/chromium.org/chromedriver/downloads
复制代码
买票必要信息,好比乘车人,来往车站,车次类型等等bash
# 乘客姓名
passengers_input = 'xxx'
passengers = passengers_input.split(",")
#乘车日期,格式为2019-01-10
from_time = '2019-01-31'
# 城市cookie字典
city_list = {
'sz':'%u6DF1%u5733%2CSZQ', #深圳
'zz':'%u90D1%u5DDE%2CZZF', #郑州
'gz':'%u5E7F%u5DDE%2CGZQ', #广州
}
# 出发站
from_station = '%u5E7F%u5DDE%2CGZQ'
# 终点站
to_station = '%u90D1%u5DDE%2CZZF'
# 车次编号
numbers = ['Z90','Z190','Z14','Z168','Z98','T124','T370']
# 座位类型
seat_type = '硬卧'
#通知邮件
receiver_email = 'xxxxxxxxx@163.com'
复制代码
注意:城市字典是将城市简写和城市代码之间联系起来。若是没有你想要到城市,能够在打开12306的查票页面,而后打开浏览器的开发者模式,输入对应的城市,而后查看请求信息。服务器
登陆咱们须要手动登陆,扫码或者输入帐号均可以。登陆后记录session,供后面抢票使用cookie
def do_login(self):
"""登陆功能实现,手动识别验证码进行登陆"""
self.driver.visit(self.login_url)
sleep(1)
# 选择登录方式登录
print('请扫码登录或者帐号登录……')
while True:
if self.driver.url != self.init_my_url:
sleep(1)
else:
break
复制代码
核心功能实现,经过扫描关键字来确认是否有余票,而后实现点击页面,进而走向下一步。session
current_tr = self.driver.find_by_xpath('//tr[@datatran="' + number + '"]/preceding-sibling::tr[1]')
if current_tr:
if current_tr.find_by_tag('td')[self.seat_type_index].text == '--':
print('无此座位类型出售,已结束当前刷票,请从新开启!')
sys.exit(1)
else:
# 有票,尝试预订
print('刷到票了(余票数:' + str(current_tr.find_by_tag('td')[self.seat_type_index].text) + '),开始尝试预订……')
current_tr.find_by_css('td.no-br>a')[0].click()
sleep(1)
key_value = 1
for p in self.passengers:
# 选择用户
print('开始选择用户……')
self.driver.find_by_text(p).last.click()
# 选择座位类型
print('开始选择席别……')
if self.seat_type_value != 0:
self.driver.find_by_xpath(
"//select[@id='seatType_" + str(key_value) + "']/option[@value='" + str(
self.seat_type_value) + "']").first.click()
key_value += 1
sleep(0.2)
if p[-1] == ')':
self.driver.find_by_id('dialog_xsertcj_ok').click()
print('正在提交订单……')
self.driver.find_by_id('submitOrder_id').click()
sleep(2)
print('正在确认订单……')
self.driver.find_by_id('qr_submit_id').click()
复制代码
一个很简单的功能,不过倒是必要的,避免本身错过!并发
def send_mail(self, receiver_address, content):
"""发送邮件通知"""
# 链接邮箱服务器信息
host = 'xxxx.163.com'
port = 25
sender = 'xxxxxx@163.com' # 你的发件邮箱号码
pwd = 'xxxxx' # 第三方受权登陆吗,不是登陆密码!!
# 发件信息
receiver = receiver_address
body = '<h2>舒适提醒:</h2><p>' + content + '</p>'
msg = MIMEText(body, 'html', _charset="utf-8")
msg['subject'] = '抢票成功通知!'
msg['from'] = sender
msg['to'] = receiver
s = smtplib.SMTP(host, port)
# 开始登录邮箱,并发送邮件
s.login(sender, pwd)
s.sendmail(sender, receiver, msg.as_string())
复制代码
总的来讲是成功的,但还不是彻底自动化的。不过相比手动抢票仍是快不少的。其实网上这种代码不少,只不过由于12306网站的更新大多数不能用了,我也是在前辈们的基础上修改完成的。想要最新源码的同窗能够关注的我公众号,回复抢票源码!框架
喜欢我写的东西的朋友能够关注一下个人公众号,上面有个人学习资源以及一些其余福利。:Devops部落