又是一年, 马上就要回家过年了, 还没有买到票的小伙伴们是否已经像热锅上的蚂蚁了无脑的开始找黄牛了?
俗话说的好, 求人不如求自己, 抢票这玩意, 其实我觉得我也可以~
来来来, 直接入正题吧!
这里有两种方案, 一种是基于 Selenium2 的自动化框架控制浏览器实现, 另一种方案则是基于 Python 自身的爬虫 package 如 request,urllib 等来实现, 本文实现第一种方案, 第二种方案也在摸索中.
实现过程
一, 新版 12306 官网主要页面网址
- 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
三, 初始化必要信息
买票必要信息, 比如乘车人, 来往车站, 车次类型等等
- # 乘客姓名
- passengers_input = 'xxx'
- passengers = passengers_input.split(",")
- # 乘车日期, 格式为 2019-01-10
- from_time = '2019-01-31'
- # 城市 cookie 字典
- city_list = {
- 'sz':'深圳,SZQ', #深圳
- 'zz':'郑州,ZZF', #郑州
- 'gz':'广州,GZQ', #广州
- }
- # 出发站
- from_station = '广州,GZQ'
- # 终点站
- to_station = '郑州,ZZF'
- # 车次编号
- numbers = ['Z90','Z190','Z14','Z168','Z98','T124','T370']
- # 座位类型
- seat_type = '硬卧'
- # 通知邮件
- receiver_email = 'xxxxxxxxx@163.com'
注意: 城市字典是将城市简写和城市代码之间联系起来. 如果没有你想要到城市, 可以在打开 12306 的查票页面, 然后打开浏览器的开发者模式, 输入对应的城市, 然后查看请求信息.
四, 登录功能实现
登录我们需要手动登录, 扫码或者输入账号都可以. 登录后记录 session, 供后面抢票使用
- 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
五, 抢票功能实现
核心功能实现, 通过扫描关键字来确认是否有余票, 然后实现点击页面, 进而走向下一步.
- 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 网站
抢票成功
等待支付
邮件通知
总结:
总的来说是成功的, 但还不是完全自动化的. 不过相比手动抢票还是快很多的. 其实网上这种代码很多, 只不过因为 12306 网站的更新大多数不能用了, 我也是在前辈们的基础上修改完成的. 想要最新源码的同学可以关注的我公众号, 回复抢票源码!
来源: http://www.bubuko.com/infodetail-2916068.html