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错误处理详解
Sep 28 Python
Python中使用HTMLParser解析html实例
Feb 08 Python
Python functools模块学习总结
May 09 Python
python数组过滤实现方法
Jul 27 Python
Python设计模式编程中解释器模式的简单程序示例分享
Mar 02 Python
python实现录音小程序
Oct 26 Python
Python3简单实现串口通信的方法
Jun 12 Python
python系列 文件操作的代码
Oct 06 Python
Python Selenium安装及环境配置的实现
Mar 17 Python
Python作用域与名字空间原理详解
Mar 21 Python
python 批量压缩图片的脚本
Jun 02 Python
Python实现将多张图片合成MP4视频并加入背景音乐
Apr 28 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
SONY ICF-SW55的电路分析
2021/03/02 无线电
PHP使用数组实现队列
2012/02/05 PHP
PHP遍历数组的三种方法及效率对比分析
2015/02/12 PHP
PHP实现一个轻量级容器的方法
2019/01/28 PHP
laravel 自定义常量的两种方案
2019/10/14 PHP
获取焦点时,利用js定时器设定时间执行动作
2010/04/02 Javascript
jQuery Lightbox 图片展示插件使用说明
2010/04/25 Javascript
点击页面其它地方隐藏该div的两种思路
2013/11/18 Javascript
JQuery实现图片轮播效果
2015/09/15 Javascript
跟我学习javascript的浮点数精度
2015/11/16 Javascript
javascript实现根据函数名称字符串动态执行函数的方法示例
2016/12/28 Javascript
Bootstrap table学习笔记(2) 前后端分页模糊查询
2017/05/18 Javascript
JS中LocalStorage与SessionStorage五种循序渐进的使用方法
2017/07/12 Javascript
vue+iview写个弹框的示例代码
2017/12/05 Javascript
从setTimeout看js函数执行过程
2017/12/19 Javascript
支付宝小程序tabbar底部导航
2018/11/06 Javascript
如何对react hooks进行单元测试的方法
2019/08/14 Javascript
JavaScript的console命令使用实例
2019/12/03 Javascript
Vue组件间的通信pubsub-js实现步骤解析
2020/03/11 Javascript
微信小程序入门之指南针
2020/10/22 Javascript
vue data有值,但是页面{{}} 取不到值的解决
2020/11/09 Javascript
JavaScript枚举选择jquery插件代码实例
2020/11/17 jQuery
Python程序员开发中常犯的10个错误
2014/07/07 Python
Python向日志输出中添加上下文信息
2017/05/24 Python
Python中字典的浅拷贝与深拷贝用法实例分析
2018/01/02 Python
python selenium 查找隐藏元素 自动播放视频功能
2019/07/24 Python
pandas中DataFrame修改index、columns名的方法示例
2019/08/02 Python
Pytorch环境搭建与基本语法
2020/06/03 Python
土耳其家居建材网站:Koçtaş
2016/11/22 全球购物
大学毕业感言100字
2014/02/03 职场文书
2014年教师业务学习材料
2014/05/12 职场文书
单位活动策划方案
2014/08/17 职场文书
婚庆答谢词
2015/01/04 职场文书
化验室岗位职责
2015/02/14 职场文书
辩护意见书
2015/06/04 职场文书
Python Socket编程详解
2021/04/25 Python