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实现简单的可逆加密程序实例
Mar 05 Python
python定时检查某个进程是否已经关闭的方法
May 20 Python
Python2.x中文乱码问题解决方法
Jun 02 Python
Python的Django框架中URLconf相关的一些技巧整理
Jul 18 Python
python文件特定行插入和替换实例详解
Jul 12 Python
详解python eval函数的妙用
Nov 16 Python
python使用turtle库绘制时钟
Mar 25 Python
Python、 Pycharm、Django安装详细教程(图文)
Apr 12 Python
Python如何使用BeautifulSoup爬取网页信息
Nov 26 Python
Python根据字符串调用函数过程解析
Nov 05 Python
python urllib和urllib3知识点总结
Feb 08 Python
python爬不同图片分别保存在不同文件夹中的实现
Apr 02 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 url 加密解密函数代码
2011/08/26 PHP
摘自织梦CMS中的图片处理类
2015/08/08 PHP
WordPress主题制作之模板文件的引入方法
2015/12/28 PHP
PHP使用内置函数生成图片的方法详解
2016/05/09 PHP
thinkPHP简单遍历数组方法分析
2016/05/16 PHP
PHPWind9.0手动屏蔽验证码解决后台关闭验证码但是依然显示的问题
2016/08/12 PHP
详解thinkphp实现excel数据的导入导出(附完整案例)
2016/12/29 PHP
thinkPHP5框架路由常用知识点汇总
2019/09/15 PHP
仅用[]()+!等符号就足以实现几乎任意Javascript代码
2010/03/01 Javascript
JS函数验证总结(方便js客户端输入验证)
2010/10/29 Javascript
extjs实现选择多表自定义查询功能 前台部分(ext源码)
2011/12/20 Javascript
JS Pro-深入面向对象的程序设计之继承的详解
2013/05/07 Javascript
用js将内容复制到剪贴板兼容浏览器
2014/03/18 Javascript
使用GruntJS构建Web程序之安装篇
2014/06/04 Javascript
谈谈impress.js初步理解
2015/09/09 Javascript
使用Javascript写的2048小游戏
2015/11/25 Javascript
JavaScript实现简单Tip提示框效果
2016/04/20 Javascript
十大热门的JavaScript框架和库
2017/03/21 Javascript
Angular2开发——组件规划篇
2017/03/28 Javascript
vue实现底部菜单功能
2018/07/24 Javascript
使用vue 国际化i18n 实现多实现语言切换功能
2018/10/11 Javascript
nodejs制作小爬虫功能示例
2020/02/24 NodeJs
python使用beautifulsoup从爱奇艺网抓取视频播放
2014/01/23 Python
Python实现TCP协议下的端口映射功能的脚本程序示例
2016/06/14 Python
Python有序字典简单实现方法示例
2017/09/28 Python
Pycharm+Python+PyQt5使用详解
2019/09/25 Python
浅谈Python爬虫原理与数据抓取
2020/07/21 Python
Under Armour安德玛法国官网:美国高端运动科技品牌
2018/06/29 全球购物
产品质量承诺书
2014/03/27 职场文书
人事专员岗位说明书
2014/07/29 职场文书
法院反腐倡廉心得体会
2014/09/09 职场文书
2015年九一八事变纪念日演讲稿
2015/03/19 职场文书
2016年寒假社会实践活动总结
2015/03/27 职场文书
心灵点滴观后感
2015/06/02 职场文书
阿里云Nginx配置https实现域名访问项目(图文教程)
2021/03/31 Servers
win10音频服务未响应怎么解决?win10音频服务未响应未修复的解决方法
2022/08/14 数码科技