Python + selenium + requests实现12306全自动抢票及验证码破解加自动点击功能


Posted in Python onNovember 23, 2018

测试结果: 

Python + selenium + requests实现12306全自动抢票及验证码破解加自动点击功能

整个买票流程可以再快一点,不过为了稳定起见,有些地方等待了一些时间

完整程序,拿去可用

整个程序分了三个模块:购票模块(主体)、验证码识别模块、余票查询模块

购票模块:

from selenium import webdriver
from selenium.webdriver.common.by import By 
from selenium.webdriver.support import expected_conditions as EC 
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException, ElementNotVisibleException
import time
import requests
from urllib.parse import urlencode
from pyquery import PyQuery as pq
from check_ticket import Check
from verify import Code
import json
class Buy_Ticket():
  def __init__(self, start_station, end_station, date, username, password, purpose):
    self.num = 1
    self.start = start_station
    self.end = end_station
    self.date = date
    self.username = username
    self.password = password
    self.purpose = purpose
    self.login_url = 'https://kyfw.12306.cn/otn/login/init'
    self.ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init'
  def login(self):
    browser.get(self.login_url)
    try:
      input_name = browser.find_element_by_id('username')
      input_pd = browser.find_element_by_id('password')
      button = browser.find_element_by_id('loginSub')
      time.sleep(1)
      input_name.send_keys(self.username)
      input_pd.send_keys(self.password)
      c = Code(browser)    #调用验证码识别模块
      c.main()
      button.click()
      time.sleep(2)
      #等待页面跳转,如果验证码识别错误,就执行下面的while语句
      while browser.current_url == self.login_url + '#':
        c = Code(browser)
        c.main()
        button.click()
        time.sleep(2)
      #self.get_passenger()
      self.check()
    except NoSuchElementException:
      self.login()
  def check(self):
    #调用余票查询模块
    check = Check(self.date, self.start, self.end, self.purpose)
    start_end = check.look_up_station()
    self.num = check.get_info()
    #cookie的添加,json.dumps把以汉字形式呈现的起始、终点站转化成unicode编码,可在审查元素里查看cookie
    browser.add_cookie({'name':'_jc_save_fromStation', 'value':json.dumps(self.start).strip('"').replace('\\', '%') + '%2C' + start_end[0]})
    browser.add_cookie({'name':'_jc_save_toStation', 'value':json.dumps(self.end).strip('"').replace('\\', '%') + '%2C' + start_end[1]})
    browser.add_cookie({'name':'_jc_save_fromDate', 'value':self.date})
    browser.get(self.ticket_url)
    if self.purpose == '学生':
      btn = browser.find_element_by_id('sf2')
      time.sleep(1)
      btn.click()
    button = browser.find_element_by_id('query_ticket')
    time.sleep(1)
    button.click()
  def book_ticket(self):
    print('开始预订车票...')
    #先查找出所有车次对应的预订按钮,再根据余票查询模块返回的车次序号,点击相应的预订按钮
    button = browser.find_elements_by_class_name('btn72')
    button[self.num-1].click()
    time.sleep(3)
    button2 = browser.find_element_by_id('normalPassenger_0') #按实际情况,可自行修改,这里就选择的第一个常用联系人,
                                  #第二个是normalPassenger_1,依此类推
    button2.click()
    button3 = browser.find_element_by_id('submitOrder_id')
    time.sleep(1)
    button3.click()
    time.sleep(3) #等待页面加载完毕,不然后面可能会报错,等待时间自行决定
    try:
      button4 = browser.find_element_by_id('qr_submit_id')
      button4.click()
    except ElementNotVisibleException:
      button4 = browser.find_element_by_id('qr_submit_id')
      button4.click()
    print('车票预定成功!请在30分钟内完成付款!')
  def main(self):
    self.login()
    self.book_ticket()
if __name__ == '__main__':
  begin = time.time()
  browser = webdriver.Chrome()
  b = Buy_Ticket('上海', '重庆', '2018-09-18', '账号', '密码', 'ADULT') #账号、密码自行修改
  b.main()
  end = time.time()
  print('总耗时:%d秒' % int(end-begin))
  #browser.close()

验证码识别模块:

import requests
from PIL import Image
from selenium.webdriver import ActionChains
import time
from io import BytesIO
class Code():
  def __init__(self, browser):
    self.browser = browser
    self.verify_url = 'http://littlebigluo.qicp.net:47720/'   #验证码识别网址,返回识别结果
    #确定验证码的位置
  def get_position(self):
    time.sleep(3)
    element = self.browser.find_element_by_class_name('touclick-img-par')
    time.sleep(2)
    location = element.location
    size = element.size
    position= (location['x'], location['y'], location['x'] + size['width'], location['y'] + size['height'])
    return position
    #截取整个网页页面
  def get_screenshot(self):
    screenshot = self.browser.get_screenshot_as_png()
    screenshot = Image.open(BytesIO(screenshot))
    return screenshot
    #从截取的网页,裁剪出验证码图片,并保存到本地
  def get_touclick_img(self, name = 'captcha.png'):
    position = self.get_position()
    print('验证码的位置:', position)
    screenshot = self.get_screenshot()
    captcha = screenshot.crop(position)
    captcha.save('captcha.png')
    #验证码解析
  def parse_img(self):
    files = {'file': open('captcha.png', 'rb')}       #打开保存到本地的验证码图片
    response = requests.post(self.verify_url, files=files)
    num = response.text.split('<B>')[1].split('<')[0]
    print('验证码识别成功!图片位置:%s' % num)
    try:
      if int(num):
        return [int(num)]
    except ValueError:
      num = list(map(int,num.split()))
      return num
    #识别结果num都以列表形式返回,方便后续验证码的点击
    #实现验证码自动点击
  def move(self):
    num = self.parse_img()
    try:
      element = self.browser.find_element_by_class_name('touclick-img-par')
      for i in num:
        if i <= 4:
          ActionChains(self.browser).move_to_element_with_offset(element,40+72*(i-1),73).click().perform()
        else :
          i -= 4
          ActionChains(self.browser).move_to_element_with_offset(element,40+72*(i-1),145).click().perform()
    except:
      print('元素不可选!')
  def main(self):
    self.get_touclick_img()
    self.move()

余票查询模块:

 

import requests
from urllib.parse import urlencode
class Check():
  def __init__(self, date, start, end, purpose):
    self.base_url = 'https://kyfw.12306.cn/otn/leftTicket/queryA?'
    self.url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9018'
    self.date = date
    self.start_station = start
    self.end_station = end
    if purpose == '学生':
      self.purpose = '0X00'
    else:
      self.purpose = purpose
    #查找出车站的英文简称,用于构造cookie、完整的余票查询链接
  def look_up_station(self):
    response1 = requests.get(self.url)
    a = response1.text.split('@')
    a.pop(0)
    for each in a:
      i = each.split('|')
      if self.start_station == i[1]:
        self.start_station = i[2]
      elif self.end_station == i[1]:
        self.end_station = i[2]
    return [self.start_station, self.end_station]
  def get_info(self):
    start_end = self.look_up_station()
    #构造请求参数
    data = {
    'leftTicketDTO.train_date':self.date,
    'leftTicketDTO.from_station':start_end[0],
    'leftTicketDTO.to_station':start_end[1],
    'purpose_codes':self.purpose
    }
    url = self.base_url + urlencode(data)
    response = requests.get(url)
    json = response.json()
    maps = json['data']['map']
    count = 0    #用于对车次编号       
    for each in json['data']['result']:
      count += 1
      s = each.split('|')[3:]
      info = {
      'train':s[0],
      'start_end':maps[s[3]] + '-' + maps[s[4]],
      'time':s[5] + '-' + s[6],
      '历时':s[7],
      '一等座':s[-5],
      '二等座':s[-6]
      }
      try:
        #余票的结果有3种:有、一个具体的数字(如:18、6等)、无,判断如果余票是有或者一个具体的数字就直接输出对应的车次信息,然后返回
        if info['二等座'] == '有' or int(info['二等座']):   
          print('[%d]' % count, info)
          return count
      except ValueError:
        continue

总结

以上所述是小编给大家介绍的Python + selenium + requests实现12306全自动抢票及验证码破解加自动点击功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
Python映射拆分操作符用法实例
May 19 Python
Python字符串格式化
Jun 15 Python
Python正则抓取网易新闻的方法示例
Apr 21 Python
python2.7无法使用pip的解决方法(安装easy_install)
Apr 03 Python
Python实现数据可视化看如何监控你的爬虫状态【推荐】
Aug 10 Python
python读取txt文件,去掉空格计算每行长度的方法
Dec 20 Python
Python 正则表达式匹配字符串中的http链接方法
Dec 25 Python
Python 读取WAV音频文件 画频谱的实例
Mar 14 Python
python db类用法说明
Jul 07 Python
详解python 支持向量机(SVM)算法
Sep 18 Python
关于python3.9安装wordcloud出错的问题及解决办法
Nov 02 Python
Elasticsearch 数据类型及管理
Apr 19 Python
python+selenium实现自动抢票功能实例代码
Nov 23 #Python
3分钟学会一个Python小技巧
Nov 23 #Python
值得收藏,Python 开发中的高级技巧
Nov 23 #Python
python 常见字符串与函数的用法详解
Nov 23 #Python
django+mysql的使用示例
Nov 23 #Python
Linux下Python安装完成后使用pip命令的详细教程
Nov 22 #Python
Windows下Python3.6安装第三方模块的方法
Nov 22 #Python
You might like
PHP去除数组中重复的元素并按键名排序函数
2008/08/18 PHP
Thinkphp将二维数组变为标签适用的一维数组方法总结
2014/10/30 PHP
PHP 序列化和反序列化函数实例详解
2020/07/18 PHP
PHP使用XMLWriter读写xml文件操作详解
2018/07/31 PHP
制作高质量的JQuery Plugin 插件的方法
2010/04/20 Javascript
JQuery操作tr和td内容的方法实例
2013/03/06 Javascript
javascript生成大小写字母
2015/07/03 Javascript
jquery UI Datepicker时间控件的使用方法(加强版)
2015/11/07 Javascript
JavaScript获取URL中参数querystring的方法详解
2016/10/11 Javascript
微信小程序 摇一摇抽奖简单实例实现代码
2017/01/09 Javascript
ajax与json 获取数据并在前台使用简单实例
2017/01/19 Javascript
js 数据存储和DOM编程
2017/02/09 Javascript
JS遍历JSON数组及获取JSON数组长度操作示例【测试可用】
2018/12/12 Javascript
JavaScript函数式编程(Functional Programming)组合函数(Composition)用法分析
2019/05/22 Javascript
jQuery高级编程之js对象、json与ajax用法实例分析
2019/11/01 jQuery
python中nan与inf转为特定数字方法示例
2017/05/11 Python
Python日期的加减等操作的示例
2017/08/15 Python
Python基于回溯法子集树模板解决旅行商问题(TSP)实例
2017/09/05 Python
python如何压缩新文件到已有ZIP文件
2018/03/14 Python
python使用turtle库与random库绘制雪花
2018/06/22 Python
对python 操作solr索引数据的实例详解
2018/12/07 Python
python安装requests库的实例代码
2019/06/25 Python
Python中Unittest框架的具体使用
2019/08/27 Python
python numpy中cumsum的用法详解
2019/10/17 Python
python add_argument()用法解析
2020/01/29 Python
python tkinter之 复选、文本、下拉的实现
2020/03/04 Python
HTML5利用约束验证API来检查表单的输入数据的代码实例
2016/12/20 HTML / CSS
Wallis官网:英国女装零售商
2020/01/21 全球购物
EJB timer的种类
2014/10/28 面试题
高中语文教学反思
2014/01/16 职场文书
清华大学自主招生自荐信
2014/01/29 职场文书
学校个人对照检查材料
2014/08/26 职场文书
学校领导干部民主生活会整改方案
2014/09/29 职场文书
小学生大队委竞选稿
2015/11/20 职场文书
导游词之珠海轮廓
2019/10/25 职场文书
Java spring单点登录系统
2021/09/04 Java/Android