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中bisect的用法
Sep 23 Python
在RedHat系Linux上部署Python的Celery框架的教程
Apr 07 Python
使用Python的Twisted框架编写非阻塞程序的代码示例
May 25 Python
Python中用psycopg2模块操作PostgreSQL方法
Nov 28 Python
基于windows下pip安装python模块时报错总结
Jun 12 Python
Django框架 信号调度原理解析
Sep 04 Python
Django中使用haystack+whoosh实现搜索功能
Oct 08 Python
Tensorflow 1.0之后模型文件、权重数值的读取方式
Feb 12 Python
基于python 凸包问题的解决
Apr 16 Python
pandas DataFrame 数据选取,修改,切片的实现
Apr 24 Python
Python通过文本和图片生成词云图
May 21 Python
解析python 类方法、对象方法、静态方法
Aug 15 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
桌面中心(一)创建数据库
2006/10/09 PHP
杏林同学录(一)
2006/10/09 PHP
PHP的一个完美GIF等比缩放类,附带去除缩放黑背景
2014/04/01 PHP
php curl批处理实现可控并发异步操作示例
2018/05/09 PHP
Mootools 1.2教程 类(一)
2009/09/15 Javascript
jquery 新浪网易的评论块制作
2010/07/01 Javascript
javascript Array.prototype.slice使用说明
2010/10/11 Javascript
jQuery编写widget的一些技巧分享
2010/10/28 Javascript
javascript利用初始化数据装配模版的实现代码
2010/11/17 Javascript
jQuery遍历对象、数组、集合实例
2014/11/08 Javascript
超级简单的jquery操作表格方法
2014/12/15 Javascript
jQuery中设置form表单中action值的实现方法
2016/05/25 Javascript
微信公众平台开发教程(六)获取个性二维码的实例
2016/12/02 Javascript
layui实现tab的添加拒绝重复的方法
2019/09/04 Javascript
angular组件间传值测试的方法详解
2020/05/07 Javascript
JavaScript Blob对象原理及用法详解
2020/10/14 Javascript
[59:15]完美世界DOTA2联赛PWL S2 LBZS vs FTD.C 第一场 11.20
2020/11/20 DOTA
Python连接SQLServer2000的方法详解
2017/04/19 Python
python requests 使用快速入门
2017/08/31 Python
Python 读取指定文件夹下的所有图像方法
2018/04/27 Python
Python分支语句与循环语句应用实例分析
2019/05/07 Python
Python 脚本拉取 Docker 镜像问题
2019/11/10 Python
python读写Excel表格的实例代码(简单实用)
2019/12/19 Python
python+adb命令实现自动刷视频脚本案例
2020/04/23 Python
解决Keras自带数据集与预训练model下载太慢问题
2020/06/12 Python
Django框架安装及项目创建过程解析
2020/09/14 Python
俄罗斯最大的在线珠宝大卖场:Nebo
2019/12/08 全球购物
乌克兰数字设备、配件和智能技术的连锁商店:KTC
2020/08/18 全球购物
《绿色蝈蝈》教学反思
2014/03/02 职场文书
手术室护士长竞聘书
2014/03/31 职场文书
开服装店计划书
2014/08/15 职场文书
党性教育心得体会
2014/09/03 职场文书
考试作弊检讨书
2015/01/27 职场文书
第一节英语课开场白
2015/06/01 职场文书
红色影片观后感
2015/06/18 职场文书
遗失证明范文
2015/06/19 职场文书