Python實現全自動購買火車票!搶票回家過年咯
這個是實現結果,因為一天只能取消三次,所以最后一步點擊確認被我注釋了。

1.首先實現使用selenium登陸12306
關于使用selenium實現12306登陸可以看我的另一篇文章 這里實現了使用selenium登陸12306,這次是基于上次的代碼進行修改實現全自動購買車票的 實現全自動登陸12306鏈接。
2.根據上面實現登陸后,實現購買火車票還需兩步
這里只進行了二等座的查詢和購票,想要買其他的自己也可以進行修改 1.進行車票的查詢 這里面需要注意的是在輸入目的地和起始地時需要先click一下文本框browser.find_element_by_id(‘fromStationText’).click() 不然輸入的地址無效 還有將日期的只讀屬性去掉。
- def search_railway_ticket(fromstation,tostation,train_date):
- # 火車票頁面查詢url
- search_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'
- # 轉到查詢車次頁面
- browser.get(search_url)
- time.sleep(2)
- #輸入出發地
- WebDriverWait(browser, 1000).until(
- EC.presence_of_element_located((By.ID, 'fromStationText'))
- )
- #先點擊一下
- browser.find_element_by_id('fromStationText').click()
- browser.find_element_by_id('fromStationText').send_keys(fromstation)
- browser.find_element_by_id('fromStationText').send_keys(Keys.ENTER)
- time.sleep(1)
- WebDriverWait(browser, 1000).until(
- EC.presence_of_element_located((By.ID, 'toStationText'))
- )
- #輸入目的地
- browser.find_element_by_id('toStationText').click()
- browser.find_element_by_id('toStationText').send_keys(tostation)
- browser.find_element_by_id('toStationText').send_keys(Keys.ENTER)
- time.sleep(5)
- #將日期的只讀屬性去掉
- js = 'document.getElementById("train_date").removeAttribute("readonly")'
- browser.execute_script(js)
- #去掉原本的時間
- WebDriverWait(browser, 1000).until(
- EC.presence_of_element_located((By.ID, 'train_date'))
- )
- browser.find_element_by_id("train_date").clear()
- #輸入出發時間
- browser.find_element_by_id('train_date').send_keys(train_date)
- # 等待查詢按鈕是否可用
- WebDriverWait(browser, 1000).until(
- EC.element_to_be_clickable((By.ID, 'query_ticket'))
- )
- searBtn = browser.find_element_by_id('query_ticket')
- searBtn.click()
- print('點擊按鈕')
2.購買火車票 在這個函數中需要注意的是最好把最后一步注釋掉 browser.find_element_by_id(‘qr_submit_id’).click() 因為一天只能取消3次訂單。
- def buy_ticket(fromstation,tostation,train_date,train_number,passenger):
- #查詢火車票
- search_railway_ticket(fromstation,tostation,train_date)
- time.sleep(5)
- #獲取每一個車次的信息
- tr_list = browser.find_elements_by_xpath('.//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')
- for tr in tr_list:
- #獲取車次號
- number = tr.find_element_by_class_name('number').text
- if number in train_number:
- #獲取是否還有票
- left_ticket = tr.find_element_by_xpath('./td[4]').text
- if left_ticket =='有'or left_ticket.isdigit:
- print(f'{number}還有票')
- #點擊預訂
- orderBtn = tr.find_element_by_class_name('btn72')
- orderBtn.click()
- time.sleep(5)
- #獲取12306中乘客的信息
- passenger_list = browser.find_elements_by_xpath('//*[@id="normal_passenger_id"]/li')
- for li in passenger_list:
- name = li.find_element_by_xpath('./label').text
- print(name)
- #配對12306人名
- if name == passenger:
- li.find_element_by_tag_name('input').click()
- #提交訂單
- submit = browser.find_element_by_id('submitOrder_id')
- submit.click()
- WebDriverWait(browser, 1000).until(
- EC.element_to_be_clickable((By.ID, 'qr_submit_id'))
- )
- #一天只能取消3次 所以最好把最后一步注釋了
- browser.find_element_by_id('qr_submit_id').click()
- print('已經提交訂單')
- break
下面是源代碼
測試的時候可以把#click_captcha()這個點擊驗證碼的去掉自己手動點擊,這樣就不用扣超級鷹的積分(有錢的話當我沒說),留下了貧窮的淚水。
- from selenium import webdriver
- from selenium.webdriver import Actionchains
- import time
- from PIL import Image
- import requests
- from hashlib import md5
- from selenium.webdriver import ChromeOptions
- #驗證碼識別處理
- from selenium.webdriver.common.keys import Keys
- from selenium.webdriver.common.by import By
- from selenium.webdriver.support.wait import WebDriverWait
- from selenium.webdriver.support import expected_conditions as EC
- class Chaojiying_Client(object):
- def __init__(self, username, password, soft_id):
- self.username = username
- password = password.encode('utf8')
- self.password = md5(password).hexdigest()
- self.soft_id = soft_id
- self.base_params = {
- 'user': self.username,
- 'pass2': self.password,
- 'softid': self.soft_id,
- }
- self.headers = {
- 'Connection': 'Keep-Alive',
- 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
- }
- def PostPic(self, im, codetype):
- """
- im: 圖片字節
- codetype: 題目類型 參考 http://www.chaojiying.com/price.html
- """
- params = {
- 'codetype': codetype,
- }
- params.update(self.base_params)
- files = {'userfile': ('ccc.jpg', im)}
- r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
- return r.json()
- def ReportError(self, im_id):
- """
- im_id:報錯題目的圖片ID
- """
- params = {
- 'id': im_id,
- }
- params.update(self.base_params)
- r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
- return r.json()
- def login(username,password):
- # 填寫賬號密碼
- browser.find_element_by_id('J-userName').send_keys(username)
- browser.find_element_by_id('J-password').send_keys(password)
- # 獲取驗證碼
- get_captcha()
- # 填寫驗證碼
- click_captcha()
- #點擊登錄
- time.sleep(4)
- browser.find_element_by_id('J-login').click()
- time.sleep(4)
- #滑動驗證碼
- slider()
- print('成功登陸')
- time.sleep(5)
- def slider():
- #滑動驗證碼
- WebDriverWait(browser, 1000).until(
- EC.presence_of_element_located((By.XPATH, '//*[@id="nc_1_n1z"]'))
- )
- span = browser.find_element_by_xpath('//*[@id="nc_1_n1z"]')
- # 對div_tag進行滑動操作
- action = Actionchains(browser)
- # 點擊長按指定的標簽
- action.click_and_hold(span).perform()
- action.drag_and_drop_by_offset(span, 400, 0).perform()
- def click_captcha():
- # 獲取驗證碼需要的為點擊位置
- chaojiying = Chaojiying_Client('自己的用戶名', '密碼', '軟件id') # 用戶中心>>軟件ID 生成一個替換 96001
- im = open('./captcha.png', 'rb').read() # 本地圖片文件路徑 來替換 a.jpg 有時WIN系統須要//
- location = chaojiying.PostPic(im, 9004)['pic_str'] # 1902 驗證碼類型 官方網站>>價格體系 3.4+版 print 后要加()
- print(chaojiying.PostPic(im, 9004))
- # 將位置進行分割成 [ [ ], [ ], [ ] ]類型
- location_list = [i.split(',') for i in location.split('|')]
- for l in location_list:
- x = l[0]
- y = l[1]
- Actionchains(browser).move_to_element_with_offset(browser.find_element_by_class_name('login-pwd-code'), int(x),int(y)).click().perform()
- time.sleep(0.5)
- def get_captcha():
- # 獲取網頁的截圖
- allscreen = browser.get_screenshot_as_file('allscreen.png')
- # 獲取captcha
- captcha = browser.find_element_by_class_name('login-pwd-code')
- # 獲取captcha的左上角位置
- location = captcha.location
- # 獲取圖片大小
- size = captcha.size
- # 裁取captcha
- rangle = (location['x'],location['y'],(location['x']+size['width']),(location['y']+size['height']))
- i = Image.open('./allscreen.png')
- captcha_img = './captcha.png'
- frame = i.crop(rangle)
- frame.save(captcha_img)
- def buy_ticket(fromstation,tostation,train_date,train_number,passenger):
- #查詢火車票
- search_railway_ticket(fromstation,tostation,train_date)
- time.sleep(5)
- tr_list = browser.find_elements_by_xpath('.//tbody[@id="queryLeftTable"]/tr[not(@datatran)]')
- for tr in tr_list:
- number = tr.find_element_by_class_name('number').text
- if number in train_number:
- left_ticket = tr.find_element_by_xpath('./td[4]').text
- if left_ticket =='有'or left_ticket.isdigit:
- print(f'{number}還有票')
- orderBtn = tr.find_element_by_class_name('btn72')
- orderBtn.click()
- time.sleep(5)
- passenger_list = browser.find_elements_by_xpath('//*[@id="normal_passenger_id"]/li')
- for li in passenger_list:
- name = li.find_element_by_xpath('./label').text
- if name == passenger:
- li.find_element_by_tag_name('input').click()
- submit = browser.find_element_by_id('submitOrder_id')
- submit.click()
- WebDriverWait(browser, 1000).until(
- EC.element_to_be_clickable((By.ID, 'qr_submit_id'))
- )
- #一天只能取消3次 所以把最后一步注釋了
- # browser.find_element_by_id('qr_submit_id').click()
- print('已經提交訂單')
- break
- def search_railway_ticket(fromstation,tostation,train_date):
- # 火車票頁面查詢url
- search_url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc'
- # 轉到查詢車次頁面
- browser.get(search_url)
- time.sleep(2)
- #輸入出發地
- WebDriverWait(browser, 1000).until(
- EC.presence_of_element_located((By.ID, 'fromStationText'))
- )
- #先點擊一下
- browser.find_element_by_id('fromStationText').click()
- browser.find_element_by_id('fromStationText').send_keys(fromstation)
- browser.find_element_by_id('fromStationText').send_keys(Keys.ENTER)
- time.sleep(1)
- WebDriverWait(browser, 1000).until(
- EC.presence_of_element_located((By.ID, 'toStationText'))
- )
- #輸入目的地
- browser.find_element_by_id('toStationText').click()
- browser.find_element_by_id('toStationText').send_keys(tostation)
- browser.find_element_by_id('toStationText').send_keys(Keys.ENTER)
- time.sleep(5)
- #將日期的只讀屬性去掉
- js = 'document.getElementById("train_date").removeAttribute("readonly")'
- browser.execute_script(js)
- #去掉原本的時間
- WebDriverWait(browser, 1000).until(
- EC.presence_of_element_located((By.ID, 'train_date'))
- )
- browser.find_element_by_id("train_date").clear()
- #輸入出發時間
- browser.find_element_by_id('train_date').send_keys(train_date)
- # 等待查詢按鈕是否可用
- WebDriverWait(browser, 1000).until(
- EC.element_to_be_clickable((By.ID, 'query_ticket'))
- )
- searBtn = browser.find_element_by_id('query_ticket')
- searBtn.click()
- print('點擊按鈕')
- if __name__ == '__main__':
- option = ChromeOptions() # 實例化一個ChromeOptions對象
- option.add_experimental_option('excludeSwitches', ['enable-automation']) # 以鍵值對的形式加入參數
- option.add_experimental_option('useAutomationExtension', False)
- browser = webdriver.Chrome(options=option)
- # 獲取響應
- browser.get('https://kyfw.12306.cn/otn/resources/login.html')
- script = 'Object.defineProperty(navigator,"webdriver",{get:()=>undefined,});'
- browser.execute_script(script)
- browser.maximize_window()
- time.sleep(1)
- # 點擊賬號登陸
- browser.find_element_by_class_name('login-hd-account').click()
- #登陸12306的賬號密碼
- login('用戶名','密碼')
- time.sleep(4)
- #例buy_ticket('南昌','撫州北','2020-12-15','D2241','xx')
- buy_ticket('起始地','目的地','出發日期','車次','姓名')
【編輯推薦】