首页 > 编程 > Python > 正文

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

2020-01-04 14:00:10
字体:
来源:转载
供稿:网友

测试结果: 

Python,selenium,requests,12306,全自动抢票,验证码

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

完整程序,拿去可用

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

购票模块:

from selenium import webdriverfrom selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException, ElementNotVisibleExceptionimport timeimport requestsfrom urllib.parse import urlencodefrom pyquery import PyQuery as pqfrom check_ticket import Checkfrom verify import Codeimport jsonclass 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 requestsfrom PIL import Imagefrom selenium.webdriver import ActionChainsimport timefrom io import BytesIOclass 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 requestsfrom urllib.parse import urlencodeclass 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全自动抢票及验证码破解加自动点击功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对VEVB武林网网站的支持!


注:相关教程知识阅读请移步到python教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表