网络编程
位置:首页>> 网络编程>> Python编程>> Python + selenium + requests实现12306全自动抢票及验证码破解加自动点击功能

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

作者:小酒馆  发布时间:2021-07-24 04:50:52 

标签:python,抢票,验证码,selenium

测试结果: 

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全自动抢票及验证码破解加自动点击功能网站的支持!

来源:http://www.cnblogs.com/mumengyun/p/10001109.html

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com