python寫12306搶票
阿新 • • 發佈:2018-12-18
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 ''' 4 利用splinter寫的一個手動過驗證及自動搶票的例子, 5 大家可以自己擴充套件或者弄錯窗體、web端。 6 本例子只做參考。 7 本程式碼釋出於2018.12.18(如果報錯請檢視官網是否改動) 8 ''' 9 import re 10 from splinter.browser import Browser 11 from time import sleep 12 import sys 13 importdemohttplib2 14 from urllib import parse 15 import smtplib 16 from email.mime.text import MIMEText 17 18 19 class BrushTicket(object): 20 """買票類及實現方法""" 21 22 def __init__(self,train_date, user_name, password, passengers, from_time, from_station, to_station, seat_type, receiver_mobile, receiver_email,isHave=False,):23 """定義例項屬性,初始化""" 24 # 有票就行 25 self.isHave = isHave 26 # 1206賬號密碼 27 self.user_name = user_name 28 self.password = password 29 # 乘客姓名 30 self.passengers = passengers 31 # 起始站和終點站 32 self.from_station = from_station33 self.to_station = to_station 34 # 乘車日期 35 self.from_time = from_time 36 #發車時間 37 self.train_date=train_date 38 # 座位型別所在td位置 39 if seat_type == '商務座特等座': 40 seat_type_index = 1 41 seat_type_value = 9 42 elif seat_type == '一等座': 43 seat_type_index = 2 44 seat_type_value = 'M' 45 elif seat_type == '二等座': 46 seat_type_index = 3 47 seat_type_value = 0 48 elif seat_type == '高階軟臥': 49 seat_type_index = 4 50 seat_type_value = 6 51 elif seat_type == '軟臥': 52 seat_type_index = 5 53 seat_type_value = 4 54 elif seat_type == '動臥': 55 seat_type_index = 6 56 seat_type_value = 'F' 57 elif seat_type == '硬臥': 58 seat_type_index = 7 59 seat_type_value = 3 60 elif seat_type == '軟座': 61 seat_type_index = 8 62 seat_type_value = 2 63 elif seat_type == '硬座': 64 seat_type_index = 9 65 seat_type_value = 1 66 elif seat_type == '無座': 67 seat_type_index = 10 68 seat_type_value = 1 69 elif seat_type == '其他': 70 seat_type_index = 11 71 seat_type_value = 1 72 else: 73 seat_type_index = 7 74 seat_type_value = 3 75 self.seat_type_index = seat_type_index 76 self.seat_type_value = seat_type_value 77 # 通知資訊 78 self.receiver_mobile = receiver_mobile 79 self.receiver_email = receiver_email 80 # 主要頁面網址 81 self.login_url = 'https://kyfw.12306.cn/otn/login/init' 82 self.init_my_url = 'https://kyfw.12306.cn/otn/view/index.html' 83 self.ticket_url = 'https://kyfw.12306.cn/otn/leftTicket/init' 84 # 瀏覽器驅動資訊,驅動下載頁:https://sites.google.com/a/chromium.org/chromedriver/downloads 85 self.driver_name = 'chrome' 86 #驅動的位置 87 self.executable_path = 'C:/Program Files (x86)/Google/Chrome/Application/chromedriver.exe' 88 89 def do_login(self): 90 """登入功能實現,手動識別驗證碼進行登入""" 91 self.driver.visit(self.login_url) 92 sleep(1) 93 self.driver.fill('loginUserDTO.user_name', self.user_name) 94 self.driver.fill('userDTO.password', self.password) 95 print('請輸入驗證碼……') 96 while True: 97 if self.driver.url != self.init_my_url: 98 sleep(1) 99 else: 100 break 101 102 def start_brush(self): 103 """買票功能實現""" 104 self.driver = Browser(driver_name=self.driver_name,executable_path=self.executable_path) 105 # 瀏覽器視窗的大小 106 # self.driver.driver.set_window_size(900, 700) 107 self.do_login() 108 self.driver.visit(self.ticket_url) 109 try: 110 print('開始刷票……') 111 # 載入車票查詢資訊 112 self.driver.cookies.add({"_jc_save_fromStation": self.from_station})#出發位置 113 self.driver.cookies.add({"_jc_save_toStation": self.to_station})#目的地 114 self.driver.cookies.add({"_jc_save_fromDate": self.from_time})#出發時間 115 self.driver.reload() 116 count = 0 117 while self.driver.url.split('?')[0] == self.ticket_url: 118 try: 119 self.wait_time('query_ticket') 120 elemt= self.driver.find_by_xpath('//select[@id="cc_start_time"]//option[@value="'+str(self.train_date)+'"]',).first 121 elemt.click() 122 sleep(1) 123 self.driver.find_by_text('查詢').click() 124 self.wait_time('train_type_btn_all') 125 count += 1 126 print('第%d次點選查詢……' % count) 127 128 elems = self.driver.find_by_id('queryLeftTable')[0].find_by_xpath('//tr[starts-with(@id,"ticket_")]') 129 while len(elems)==0: 130 sleep(0.5) 131 elems = self.driver.find_by_id('queryLeftTable')[0].find_by_xpath('//tr[starts-with(@id,"ticket_")]') 132 #是不是有票就行 133 if(self.isHave): 134 for current_tr in elems: 135 if(current_tr.text==''): 136 print('沒票') 137 continue 138 # 下標索引 139 if current_tr.find_by_tag('td')[self.seat_type_index].text == '--' or current_tr.find_by_tag('td')[self.seat_type_index].text == '無': 140 print('無此座位型別出售!') 141 continue 142 else: 143 # 有票,嘗試預訂 144 print('刷到票了(餘票數:' + str(current_tr.find_by_tag('td')[self.seat_type_index].text) + '),開始嘗試預訂……') 145 current_tr.find_by_css('td.no-br>a')[0].click() 146 key_value = 1 147 # 等待頁面載入完畢 148 self.wait_time('normalPassenger_' +str(int(key_value-1))) 149 150 for p in self.passengers: 151 # 選擇使用者 152 print('開始選擇使用者……') 153 self.driver.find_by_text(p).last.click() 154 # 選擇座位型別 155 print('開始選擇席別……') 156 if self.seat_type_value != 0: 157 sleep(1) 158 seat_select = self.driver.find_by_id("seatType_" + str(key_value))[0] 159 seat_select.find_by_xpath("//option[@value='" + str(self.seat_type_value) + "']")[0].click() 160 key_value += 1 161 if p[-1] == ')': 162 self.driver.find_by_id('dialog_xsertcj_ok').click() 163 print('正在提交訂單……') 164 self.driver.find_by_id('submitOrder_id').click() 165 self.wait_time('content_checkticketinfo_id') 166 # 檢視返回結果是否正常 167 submit_false_info = self.driver.find_by_id('orderResultInfo_id')[0].text 168 if submit_false_info != '': 169 print(submit_false_info) 170 self.driver.find_by_id('qr_closeTranforDialog_id').click() 171 self.driver.find_by_id('preStep_id').click() 172 continue 173 print('正在確認訂單……') 174 # 等待載入完畢 175 self.wait_time('qr_submit_id') 176 self.driver.find_by_id('qr_submit_id').click() 177 print('預訂成功,請及時前往支付……') 178 # 傳送通知資訊 179 self.send_mail(self.receiver_email, '恭喜您,搶到票了,請及時前往12306支付訂單!') 180 self.send_sms(self.receiver_mobile, '恭喜您,搶到票了,請及時前往12306支付訂單!') 181 else: 182 for current_tr in elems: 183 if(current_tr.text==''): 184 print('沒票') 185 continue 186 else: 187 # 下標索引 188 print('判斷車票是否存在') 189 if current_tr.find_by_tag('td')[self.seat_type_index].text == '--' or current_tr.find_by_tag('td')[self.seat_type_index].text == '無': 190 print('無此座位型別出售!') 191 continue 192 else: 193 # 有票,嘗試預訂 194 print('刷到票了(餘票數:' + str(current_tr.find_by_tag('td')[self.seat_type_index].text) + '),開始嘗試預訂……') 195 current_tr.find_by_css('td.no-br>a')[0].click() 196 key_value = 1 197 # 等待頁面載入完畢 198 self.wait_time('normalPassenger_' +str(int(key_value-1))) 199 200 for p in self.passengers: 201 # 選擇使用者 202 print('開始選擇使用者……') 203 self.driver.find_by_text(p).last.click() 204 # 選擇座位型別 205 print('開始選擇席別……') 206 if self.seat_type_value != 0: 207 seat_select = self.driver.find_by_id("seatType_" + str(key_value))[0] 208 seat_select.find_by_xpath("//option[@value='" + str(self.seat_type_value) + "']")[0].click() 209 key_value += 1 210 if p[-1] == ')': 211 self.driver.find_by_id('dialog_xsertcj_ok').click() 212 print('正在提交訂單……') 213 self.driver.find_by_id('submitOrder_id').click() 214 self.wait_time('content_checkticketinfo_id') 215 # 檢視返回結果是否正常 216 submit_false_info = self.driver.find_by_id('orderResultInfo_id')[0].text 217 if submit_false_info != '': 218 print(submit_false_info) 219 self.driver.find_by_id('qr_closeTranforDialog_id').click() 220 self.driver.find_by_id('preStep_id').click() 221 continue 222 print('正在確認訂單……') 223 # 等待載入完畢 224 self.wait_time('qr_submit_id') 225 self.driver.find_by_id('qr_submit_id').click() 226 print('預訂成功,請及時前往支付……') 227 # 傳送通知資訊 228 self.send_mail(self.receiver_email, '恭喜您,搶到票了,請及時前往12306支付訂單!') 229 self.send_sms(self.receiver_mobile, '恭喜您,搶到票了,請及時前往12306支付訂單!') 230 231 # self.driver.quit() 232 return 233 except Exception as error_info: 234 print(error_info) 235 except Exception as error_info: 236 print(error_info) 237 238 def wait_time(self, name): 239 while self.driver.is_element_present_by_id(name) == False: 240 sleep(1) 241 242 243 def send_sms(self, mobile, sms_info): 244 """傳送手機通知簡訊,用的是-互億無線-的測試簡訊""" 245 host = "106.ihuyi.com" 246 sms_send_uri = "/webservice/sms.php?method=Submit" 247 account = "C59782899" 248 pass_word = "19d4d9c0796532c7328e8b82e2812655" 249 params = parse.urlencode( 250 {'account': account, 'password': pass_word, 251 'content': sms_info, 'mobile': mobile, 'format': 'json'} 252 ) 253 headers = {"Content-type": "application/x-www-form-urlencoded", 254 "Accept": "text/plain"} 255 conn = httplib2.HTTPConnectionWithTimeout(host, port=80, timeout=30) 256 conn.request("POST", sms_send_uri, params, headers) 257 response = conn.getresponse() 258 response_str = response.read() 259 conn.close() 260 return response_str 261 262 def send_mail(self, receiver_address, content): 263 """傳送郵件通知""" 264 # 連線郵箱伺服器資訊 265 host = 'smtp.qq.com' #QQ 266 sender = '[email protected]' # 你的發件郵箱號碼 267 pwd = 'riebhcallwgzbfei' # 不是登陸密碼,是客戶端授權密碼 268 # 發件資訊 269 receiver = receiver_address 270 body = '<h2>溫馨提醒:</h2><p>' + content + '</p>' 271 msg = MIMEText(body, 'html', _charset="utf-8") 272 msg['subject'] = '搶票成功通知!' 273 msg['from'] = sender 274 msg['to'] = receiver 275 s = smtplib.SMTP(host, port=465, timeout=30) 276 # 開始登陸郵箱,併發送郵件 277 s.login(sender, pwd) 278 s.sendmail(sender, receiver, msg.as_string()) 279 s.close() 280 281 282 if __name__ == '__main__': 283 # 12306使用者名稱 284 user_name = 'XXXXX' 285 # 12306登陸密碼 286 password = 'XXXXX' 287 # 乘客姓名 288 passengers = '張三' 289 # 乘車日期 290 from_time = '2018-12-21' 291 292 #發車時間 293 train_date={ 294 '00:00--24:00':'00002400', 295 '00:00--06:00':'00000600', 296 '06:00--12:00':'06001200', 297 '12:00--18:00':'12001800', 298 '18:00--24:00':'18002400', 299 } 300 301 # 城市cookie字典 302 city_list = {'成都': '%u6210%u90FD%2CCDW', 303 '重慶': '%u91CD%u5E86%2CCQW', 304 '北京': '%u5317%u4EAC%2CBJP', 305 '廣州': '%u5E7F%u5DDE%2CGZQ', 306 '杭州': '%u676D%u5DDE%2CHZH', 307 '宜昌': '%u5B9C%u660C%2CYCN', 308 '鄭州': '%u90D1%u5DDE%2CZZF', 309 '深圳': '%u6DF1%u5733%2CSZQ', 310 '西安': '%u897F%u5B89%2CXAY', 311 '大連': '%u5927%u8FDE%2CDLT', 312 '武漢': '%u6B66%u6C49%2CWHN', 313 '上海': '%u4E0A%u6D77%2CSHH', 314 '南京': '%u5357%u4EAC%2CNJH', 315 '合肥': '%u5408%u80A5%2CHFH'} 316 # 出發站 317 from_station = city_list['廣州'] 318 # 終點站 319 to_station = city_list['武漢'] 320 # 座位型別 321 seat_type = '二等座' 322 # 搶票成功,通知該手機號碼 323 receiver_mobile = 'xxxxxx' 324 #搶票成功,通知該郵件 325 receiver_email = '[email protected]' 326 # 開始搶票 327 ticket = BrushTicket(train_date['18:00--24:00'],user_name, password, passengers.split(","), from_time, from_station, 328 to_station, seat_type, receiver_mobile, receiver_email,True) 329 ticket.start_brush()
環境:python3,chromedriver(請下載對應的版本的瀏覽器驅動)
效果圖:
本程式碼釋出於2018.12.18(如果報錯請檢視包是否引用正確或官網是否改動)