Python + selenium + requests實現(xiàn)12306全自動搶票及驗證碼破解加自動點擊功能
測試結(jié)果:

整個買票流程可以再快一點,不過為了穩(wěn)定起見,有些地方等待了一些時間
完整程序,拿去可用
整個程序分了三個模塊:購票模塊(主體)、驗證碼識別模塊、余票查詢模塊
購票模塊:
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) #調(diào)用驗證碼識別模塊
c.main()
button.click()
time.sleep(2)
#等待頁面跳轉(zhuǎn),如果驗證碼識別錯誤,就執(zhí)行下面的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):
#調(diào)用余票查詢模塊
check = Check(self.date, self.start, self.end, self.purpose)
start_end = check.look_up_station()
self.num = check.get_info()
#cookie的添加,json.dumps把以漢字形式呈現(xiàn)的起始、終點站轉(zhuǎn)化成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 == '學(xué)生':
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('開始預(yù)訂車票...')
#先查找出所有車次對應(yīng)的預(yù)訂按鈕,再根據(jù)余票查詢模塊返回的車次序號,點擊相應(yīng)的預(yù)訂按鈕
button = browser.find_elements_by_class_name('btn72')
button[self.num-1].click()
time.sleep(3)
button2 = browser.find_element_by_id('normalPassenger_0') #按實際情況,可自行修改,這里就選擇的第一個常用聯(lián)系人,
#第二個是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('車票預(yù)定成功!請在30分鐘內(nèi)完成付款!')
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/' #驗證碼識別網(wǎng)址,返回識別結(jié)果
#確定驗證碼的位置
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
#截取整個網(wǎng)頁頁面
def get_screenshot(self):
screenshot = self.browser.get_screenshot_as_png()
screenshot = Image.open(BytesIO(screenshot))
return screenshot
#從截取的網(wǎng)頁,裁剪出驗證碼圖片,并保存到本地
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
#識別結(jié)果num都以列表形式返回,方便后續(xù)驗證碼的點擊
#實現(xiàn)驗證碼自動點擊
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 == '學(xué)生':
self.purpose = '0X00'
else:
self.purpose = purpose
#查找出車站的英文簡稱,用于構(gòu)造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()
#構(gòu)造請求參數(shù)
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:
#余票的結(jié)果有3種:有、一個具體的數(shù)字(如:18、6等)、無,判斷如果余票是有或者一個具體的數(shù)字就直接輸出對應(yīng)的車次信息,然后返回
if info['二等座'] == '有' or int(info['二等座']):
print('[%d]' % count, info)
return count
except ValueError:
continue
總結(jié)
以上所述是小編給大家介紹的Python + selenium + requests實現(xiàn)12306全自動搶票及驗證碼破解加自動點擊功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
如何在python中實現(xiàn)capl語言里的回調(diào)函數(shù)(推薦)
CAPL是一種程序語言,其中程序塊的執(zhí)行由事件控制,主要介紹了如何在python中實現(xiàn)capl語言里的回調(diào)函數(shù)及事件函數(shù)的作用,需要的朋友可以參考下2022-08-08
Python實現(xiàn)通過文件路徑獲取文件hash值的方法
這篇文章主要介紹了Python實現(xiàn)通過文件路徑獲取文件hash值的方法,結(jié)合實例形式分析了Python針對文件進(jìn)行hash運算的實現(xiàn)方法與相關(guān)注意事項,需要的朋友可以參考下2017-04-04
Django利用Channels+websocket開發(fā)聊天室完整案例
Channels是Django團(tuán)隊研發(fā)的一個給Django提供websocket支持的框架,使用它我們可以輕松開發(fā)需要長鏈接的實時通訊應(yīng)用,下面這篇文章主要給大家介紹了關(guān)于Django利用Channels+websocket開發(fā)聊天室的相關(guān)資料,需要的朋友可以參考下2023-06-06
在Python操作時間和日期之a(chǎn)sctime()方法的使用
這篇文章主要介紹了在Python操作時間和日期之a(chǎn)sctime()方法的使用,是Python入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-05-05
詳解使用django-mama-cas快速搭建CAS服務(wù)的實現(xiàn)
這篇文章主要介紹了詳解使用django-mama-cas快速搭建CAS服務(wù)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
Python文件操作中進(jìn)行字符串替換的方法(保存到新文件/當(dāng)前文件)
這篇文章主要介紹了Python文件操作中進(jìn)行字符串替換的方法(保存到新文件/當(dāng)前文件) ,本文給大家介紹兩種方法,每種方法給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-06-06
Python cookbook(數(shù)據(jù)結(jié)構(gòu)與算法)保存最后N個元素的方法
這篇文章主要介紹了Python數(shù)據(jù)結(jié)構(gòu)與算法 保存最后N個元素的方法,涉及Python基于迭代器與生成器實現(xiàn)歷史記錄功能的相關(guān)操作技巧,需要的朋友可以參考下2018-02-02

