class select: def __init__(self): self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, self.ticke_peoples, self.select_refresh_interval, self.station_trains, self.ticket_black_list_time = self.get_ticket_info() self.is_aotu_code = _get_yaml()["is_aotu_code"] self.aotu_code_type = _get_yaml()["aotu_code_type"] self.order_request_params = {} # 订单提交时的参数 self.ticketInfoForPassengerForm = {} # 初始化当前页面参数 self.current_seats = {} # 席别信息 self.token = "" self.set_type = "" self.user_info = "" self.secretStr = "" self.ticket_black_list = dict() self.is_check_user = dict() self.httpClint = HTTPClient() self.confUrl = urlConf.urls self.login = GoLogin(self.httpClint, self.confUrl, self.is_aotu_code, self.aotu_code_type) def get_ticket_info(self): """ 获取配置信息 :return: """ ticket_info_config = _get_yaml() from_station = ticket_info_config["set"]["from_station"].encode("utf8") to_station = ticket_info_config["set"]["to_station"].encode("utf8") station_dates = ticket_info_config["set"]["station_dates"] set_type = ticket_info_config["set"]["set_type"] is_more_ticket = ticket_info_config["set"]["is_more_ticket"] ticke_peoples = ticket_info_config["set"]["ticke_peoples"] select_refresh_interval = ticket_info_config["select_refresh_interval"] station_trains = ticket_info_config["set"]["station_trains"] ticket_black_list_time = ticket_info_config["ticket_black_list_time"] print "*"*20 print "当前配置:出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票自动提交:{4}\n乘车人:{5}\n刷新间隔:{6}\n候选购买车次:{7}\n僵尸票关小黑屋时长:{8}\n".format\ ( from_station, to_station, station_dates, ",".join(set_type), is_more_ticket, ",".join(ticke_peoples), select_refresh_interval, ",".join(station_trains), ticket_black_list_time, ) print "*"*20 return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, select_refresh_interval, station_trains, ticket_black_list_time def get_order_request_params(self): return self.order_request_params def get_ticketInfoForPassengerForm(self): return self.ticketInfoForPassengerForm def get_current_seats(self): return self.current_seats def get_token(self): return self.token def get_set_type(self): return self.set_type def conversion_int(self, str): return int(str) def station_seat(self, index): """ 获取车票对应坐席 :param seat_type: :return: """ seat = {'商务座': 32, '一等座': 31, '二等座': 30, '特等座': 25, '软卧': 23, '硬卧': 28, '硬座': 29, '无座': 26, } return seat[index] def station_table(self, from_station, to_station): """ 读取车站信息 :param station: :return: """ result = open('station_name.txt') info = result.read().split('=')[1].strip("'").split('@') del info[0] station_name = {} for i in range(0, len(info)): n_info = info[i].split('|') station_name[n_info[1]] = n_info[2] from_station = station_name[from_station.encode("utf8")] to_station = station_name[to_station.encode("utf8")] return from_station, to_station def time(self): """ 获取日期 :return: """ today = datetime.date.today() tomorrow = today+datetime.timedelta(1) return tomorrow.strftime('%Y-%m-%d') def getRepeatSubmitToken(self): """ 获取提交车票请求token :return: token """ initdc_url = self.confUrl["initdc_url"]["req_url"] initdc_result = self.httpClint.send(initdc_url) token_name = re.compile(r"var globalRepeatSubmitToken = '(\S+)'") ticketInfoForPassengerForm_name = re.compile(r'var ticketInfoForPassengerForm=(\{.+\})?') order_request_params_name = re.compile(r'var orderRequestDTO=(\{.+\})?') self.token = re.search(token_name, initdc_result).group(1) re_tfpf = re.findall(ticketInfoForPassengerForm_name, initdc_result) re_orp = re.findall(order_request_params_name, initdc_result) if re_tfpf: self.ticketInfoForPassengerForm = json.loads(re_tfpf[0].replace("'", '"')) else: pass if re_orp: self.order_request_params = json.loads(re_orp[0].replace("'", '"')) else: pass def getPassengerDTOs(self): """ 获取乘客信息 :return: """ get_passengerDTOs = self.confUrl["get_passengerDTOs"]["req_url"] get_data = { '_json_att': None, 'REPEAT_SUBMIT_TOKEN': self.token } jsonData = self.httpClint.send(get_passengerDTOs, get_data) if 'data' in jsonData and jsonData['data'] and 'normal_passengers' in jsonData['data'] and jsonData['data'][ 'normal_passengers']: normal_passengers = jsonData['data']['normal_passengers'] _normal_passenger = [normal_passengers[i] for i in range(len(normal_passengers))if normal_passengers[i]["passenger_name"] in self.ticke_peoples] return _normal_passenger if _normal_passenger else [normal_passengers[0]] # 如果配置乘车人没有在账号,则默认返回第一个用户 else: if 'data' in jsonData and 'exMsg' in jsonData['data'] and jsonData['data']['exMsg']: print(jsonData['data']['exMsg']) elif 'messages' in jsonData and jsonData['messages']: print(jsonData['messages'][0]) else: print("未查找到常用联系人") raise PassengerUserException("未查找到常用联系人,请先添加联系人在试试") def submitOrderRequestFunc(self, from_station, to_station, station_date=None): select_url = self.confUrl["select_url"]["req_url"].format( station_date, from_station, to_station) station_ticket = self.httpClint.send(select_url, is_logger=False) return json.loads(station_ticket) def submitOrderRequestImplement(self, from_station, to_station,): """ 提交车次信息 车次对应字典 {32: '商务座 ', 31: '一等座 ', 30: '二等座 ', 25: '特等座 ', 23: '软卧 ', 28: '硬卧 ', 29: '硬座 ', 26: '无座 ' } 参照station_seat()方法 :return: """ station_tickets = [self.submitOrderRequestFunc(from_station, to_station, station_date) for station_date in self.station_dates] for station_ticket in station_tickets: value = station_ticket['data'] if not value: print ('{0}-{1} 车次坐席查询为空...'.format(self.from_station, self.to_station)) else: if value['result']: for i in value['result']: ticket_info = i.split('|') if ticket_info[11] == "Y" and ticket_info[1].encode("utf8") == "预订": # 筛选未在开始时间内的车次 for j in range(len(self._station_seat)): is_ticket_pass = ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))] # print self._station_seat[j] if is_ticket_pass != '' and is_ticket_pass != '无' and ticket_info[3] in self.station_trains and is_ticket_pass != '*': # 过滤有效目标车次 # tiket_values = [k for k in value['map'].values()] self.secretStr = ticket_info[0] train_no = ticket_info[3] print ('车次: ' + train_no + ' 始发车站: ' + self.from_station + ' 终点站: ' + self.to_station + ' ' + self._station_seat[j].encode("utf8") + ':' + ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))]) if self.ticket_black_list.has_key(train_no) and (datetime.datetime.now() - self.ticket_black_list[train_no]).seconds/60 < int(self.ticket_black_list_time): print("该车次{} 正在被关小黑屋,跳过此车次".format(train_no)) break else: print ('正在尝试提交订票...') # self.submitOrderRequestFunc(from_station, to_station, self.time()) self.submit_station() self.getPassengerTicketStr(self._station_seat[j].encode("utf8")) self.getRepeatSubmitToken() if not self.user_info: # 修改每次都调用用户接口导致用户接口不能用 self.user_info = self.getPassengerDTOs() if self.checkOrderInfo(train_no, self._station_seat[j].encode("utf8")): break else: pass else: pass else: print "车次配置信息有误,或者返回数据异常,请检查 {}".format(station_ticket) def check_user(self): """ 检查用户是否达到订票条件 :return: """ check_user_url = self.confUrl["check_user_url"]["req_url"] data = {"_json_att": ""} check_user = self.httpClint.send(check_user_url, data) check_user_flag = check_user['data']['flag'] if check_user_flag is True: self.is_check_user["user_time"] = datetime.datetime.now() else: if check_user['messages']: print ('用户检查失败:%s,可能未登录,可能session已经失效' % check_user['messages'][0]) print ('正在尝试重新登录') self.call_login() self.is_check_user["user_time"] = datetime.datetime.now() else: print ('用户检查失败: %s,可能未登录,可能session已经失效' % check_user) print ('正在尝试重新登录') self.call_login() self.is_check_user["user_time"] = datetime.datetime.now() def submit_station(self): """ 提交车次 预定的请求参数,注意参数顺序 注意这里为了防止secretStr被urllib.parse过度编码,在这里进行一次解码 否则调用HttpTester类的post方法将会将secretStr编码成为无效码,造成提交预定请求失败 :param self: :param secretStr: 提交车次加密 :return: """ submit_station_url = self.confUrl["submit_station_url"]["req_url"] data = [('secretStr', urllib.unquote(self.secretStr)), # 字符串加密 ('train_date', self.time()), # 出发时间 ('back_train_date', self.time()), # 返程时间 ('tour_flag', 'dc'), # 旅途类型 ('purpose_codes', 'ADULT'), # 成人票还是学生票 ('query_from_station_name', self.from_station), # 起始车站 ('query_to_station_name', self.to_station), # 终点车站 ] submitResult = self.httpClint.send(submit_station_url, data) if 'data' in submitResult and submitResult['data']: if submitResult['data'] == 'N': print ('出票成功') else: print ('出票失败') elif 'messages' in submitResult and submitResult['messages']: raise ticketIsExitsException(submitResult['messages'][0]) def getPassengerTicketStr(self, set_type): """ 获取getPassengerTicketStr 提交对应的代号码 :param str: 坐席 :return: """ passengerTicketStr = { '一等座': 'M', '特等座': 'P', '二等座': 'O', '商务座': 9, '硬座': 1, '无座': 1, '软卧': 4, '硬卧': 3, } self.set_type = str(passengerTicketStr[set_type.replace(' ', '')]) def ticket_type(self): """订单票的类型,目前只考虑成人票,此方法暂时搁置,做备案""" ticket_type = {'adult': "1", 'child': "2", 'student': "3", 'disability': "4"} return ticket_type def getPassengerTicketStrListAndOldPassengerStr(self): """ 获取提交车次人内容格式 passengerTicketStr O,0,1,文贤平,1,43052419950223XXXX,15618715583,N_O,0,1,梁敏,1,43052719920118XXXX,,N oldPassengerStr 文贤平,1,43052719920118XXXX,1_梁敏,1,43052719920118XXXX,1_ :return: """ passengerTicketStrList = [] oldPassengerStr = [] if not self.user_info: raise PassengerUserException("联系人不在列表中,请查证后添加") if len(self.user_info) is 1: passengerTicketStrList.append( '0,' + self.user_info[0]['passenger_type'] + "," + self.user_info[0][ "passenger_name"] + "," + self.user_info[0]['passenger_id_type_code'] + "," + self.user_info[0]['passenger_id_no'] + "," + self.user_info[0]['mobile_no'] + ',N') oldPassengerStr.append( self.user_info[0]['passenger_name'] + "," + self.user_info[0]['passenger_id_type_code'] + "," + self.user_info[0]['passenger_id_no'] + "," + self.user_info[0]['passenger_type'] + '_') else: for i in range(len(self.user_info)): passengerTicketStrList.append( '0,' + self.user_info[i]['passenger_type'] + "," + self.user_info[i][ "passenger_name"] + "," + self.user_info[i]['passenger_id_type_code'] + "," + self.user_info[i][ 'passenger_id_no'] + "," + self.user_info[i]['mobile_no'] + ',N_' + self.set_type) oldPassengerStr.append( self.user_info[i]['passenger_name'] + "," + self.user_info[i]['passenger_id_type_code'] + "," + self.user_info[i]['passenger_id_no'] + "," + self.user_info[i]['passenger_type'] + '_') return passengerTicketStrList, oldPassengerStr def checkOrderInfo(self, train_no, set_type): """ 检查支付订单,需要提交REPEAT_SUBMIT_TOKEN passengerTicketStr : 座位编号,0,票类型,乘客名,证件类型,证件号,手机号码,保存常用联系人(Y或N) oldPassengersStr: 乘客名,证件类型,证件号,乘客类型 :return: """ passengerTicketStrList, oldPassengerStr = self.getPassengerTicketStrListAndOldPassengerStr() checkOrderInfoUrl = self.confUrl["checkOrderInfoUrl"]["req_url"] data = OrderedDict() data['cancel_flag'] = 2 data['bed_level_order_num'] = "000000000000000000000000000000" data['passengerTicketStr'] = self.set_type + "," + ",".join(passengerTicketStrList).rstrip("_{0}".format(self.set_type)) data['oldPassengerStr'] = "".join(oldPassengerStr) data['tour_flag'] = 'dc' data['whatsSelect'] = 1 data['REPEAT_SUBMIT_TOKEN'] = self.token checkOrderInfo = self.httpClint.send(checkOrderInfoUrl, data) if 'data' in checkOrderInfo: if "ifShowPassCode" in checkOrderInfo["data"] and checkOrderInfo["data"]["ifShowPassCode"] == "Y": is_need_code = True if self.getQueueCount(train_no, set_type, is_need_code): return True if "ifShowPassCode" in checkOrderInfo["data"] and checkOrderInfo['data']['submitStatus'] is True: print ('车票提交通过,正在尝试排队') is_need_code = False if self.getQueueCount(train_no, set_type, is_need_code): return True else: if "errMsg" in checkOrderInfo['data'] and checkOrderInfo['data']["errMsg"]: print checkOrderInfo['data']["errMsg"] else: print checkOrderInfo elif 'messages' in checkOrderInfo and checkOrderInfo['messages']: print (checkOrderInfo['messages'][0]) def getQueueCount(self, train_no, set_type, is_need_code): """ # 模拟查询当前的列车排队人数的方法 # 返回信息组成的提示字符串 :param token: :return: """ l_time = time.localtime(time.time()) new_train_date = time.strftime("%a %b %d %Y", l_time) getQueueCountUrl = self.confUrl["getQueueCountUrl"]["req_url"] data = { 'train_date': str(new_train_date) + " 00:00:00 GMT+0800 (中国标准时间)", 'train_no': self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['train_no'], 'stationTrainCode': self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['station_train_code'], 'seatType': self.set_type, 'fromStationTelecode': self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['from_station'], 'toStationTelecode': self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['to_station'], 'leftTicket': self.get_ticketInfoForPassengerForm()['leftTicketStr'], 'purpose_codes': self.get_ticketInfoForPassengerForm()['purpose_codes'], 'train_location': self.get_ticketInfoForPassengerForm()['train_location'], 'REPEAT_SUBMIT_TOKEN': self.get_token(), } getQueueCountResult = self.httpClint.send(getQueueCountUrl, data) if "status" in getQueueCountResult and getQueueCountResult["status"] is True: if "countT" in getQueueCountResult["data"]: ticket = getQueueCountResult["data"]["ticket"] ticket_split = sum(map(self.conversion_int, ticket.split(","))) if ticket.find(",") != -1 else ticket countT = getQueueCountResult["data"]["countT"] if int(countT) is 0: if int(ticket_split) < len(self.user_info): print("当前余票数小于乘车人数,放弃订票") else: print("排队成功, 当前余票还剩余: {0} 张".format(ticket_split)) if self.checkQueueOrder(is_need_code): return True else: print("当前排队人数:" + str(countT) + "当前余票还剩余:{0} 张,继续排队中".format(ticket_split)) else: print("排队发现未知错误{0},将此列车 {1}加入小黑屋".format(getQueueCountResult, train_no)) self.ticket_black_list[train_no] = datetime.datetime.now() elif "messages" in getQueueCountResult and getQueueCountResult["messages"]: print("排队异常,错误信息:{0}, 将此列车 {1}加入小黑屋".format(getQueueCountResult["messages"][0], train_no)) self.ticket_black_list[train_no] = datetime.datetime.now() else: if "validateMessages" in getQueueCountResult and getQueueCountResult["validateMessages"]: print(str(getQueueCountResult["validateMessages"])) self.ticket_black_list[train_no] = datetime.datetime.now() else: print("未知错误 {0}".format("".join(getQueueCountResult))) def checkQueueOrder(self, is_node_code=False): """ 模拟提交订单是确认按钮,参数获取方法还是get_ticketInfoForPassengerForm 中获取 :return: """ passengerTicketStrList, oldPassengerStr = self.getPassengerTicketStrListAndOldPassengerStr() checkQueueOrderUrl = self.confUrl["checkQueueOrderUrl"]["req_url"] data = { "passengerTicketStr": self.set_type + "," + ",".join(passengerTicketStrList).rstrip("_{0}".format(self.set_type)), "oldPassengerStr": "".join(oldPassengerStr), "purpose_codes": self.get_ticketInfoForPassengerForm()["purpose_codes"], "key_check_isChange": self.get_ticketInfoForPassengerForm()["key_check_isChange"], "leftTicketStr": self.get_ticketInfoForPassengerForm()["leftTicketStr"], "train_location": self.get_ticketInfoForPassengerForm()["train_location"], "seatDetailType": "000", # 开始需要选择座位,但是目前12306不支持自动选择作为,那这个参数为默认 "roomType": "00", # 好像是根据一个id来判断选中的,两种 第一种是00,第二种是10,但是我在12306的页面没找到该id,目前写死是00,不知道会出什么错 "dwAll": "N", "whatsSelect": 1, "_json_at": "", "REPEAT_SUBMIT_TOKEN": self.get_token(), } try: for i in range(3): if is_node_code: print("正在使用自动识别验证码功能") checkRandCodeAnsyn = self.confUrl["checkRandCodeAnsyn"]["req_url"] codeImgByOrder = self.confUrl["codeImgByOrder"]["req_url"] randCode = self.login.readImg(codeImgByOrder) randData = { "randCode": randCode, "rand": "randp", "_json_att": None, "REPEAT_SUBMIT_TOKEN": self.get_token() } fresult = self.httpClint.send(checkRandCodeAnsyn, randData) # 校验验证码是否正确 checkcode = fresult['data']['msg'] if checkcode == 'TRUE': print("验证码通过,正在提交订单") data['randCode'] = randCode break else: print ("验证码有误, 接口返回{0} 第{1}次尝试重试".format(fresult, i)) else: print("不需要验证码") break checkQueueOrderResult = self.httpClint.send(checkQueueOrderUrl, data) if "status" in checkQueueOrderResult and checkQueueOrderResult["status"]: c_data = checkQueueOrderResult["data"] if "data" in checkQueueOrderResult else {} if 'submitStatus' in c_data and c_data['submitStatus'] is True: print("提交订单成功!") self.queryOrderWaitTime() else: if 'errMsg' in c_data and c_data['errMsg']: print("提交订单失败,{0}".format(c_data['errMsg'])) else: print(c_data) print('订票失败!很抱歉,请重试提交预订功能!') elif "messages" in checkQueueOrderResult and checkQueueOrderResult["messages"]: print("提交订单失败,错误信息: " + checkQueueOrderResult["messages"]) else: print("提交订单中,请耐心等待:" + str(checkQueueOrderResult["validateMessages"])) except ValueError: print("接口 {} 无响应".format(checkQueueOrderUrl)) def queryOrderWaitTime(self): """ 排队获取订单等待信息,每隔3秒请求一次,最高请求次数为20次! :return: """ num = 1 while True: _random = int(round(time.time() * 1000)) num += 1 if num > 30: print("超出排队时间,自动放弃,正在重新刷票") order_id = self.queryMyOrderNoComplete() # 排队失败,自动取消排队订单 if order_id: self.cancelNoCompleteMyOrder(order_id) break try: data = {"random": _random, "tourFlag": "dc"} queryOrderWaitTimeUrl = self.confUrl["queryOrderWaitTimeUrl"]["req_url"] queryOrderWaitTimeResult = self.httpClint.send(queryOrderWaitTimeUrl, data) except ValueError: queryOrderWaitTimeResult = {} if queryOrderWaitTimeResult: if "status" in queryOrderWaitTimeResult and queryOrderWaitTimeResult["status"]: if "orderId" in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["orderId"] is not None: sendEmail("恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306,访问‘未完成订单’,在30分钟内完成支付!".format(queryOrderWaitTimeResult["data"]["orderId"])) raise ticketIsExitsException("恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306,访问‘未完成订单’,在30分钟内完成支付!".format(queryOrderWaitTimeResult["data"]["orderId"])) elif "msg" in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["msg"]: print queryOrderWaitTimeResult["data"]["msg"] break elif "waitTime"in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["waitTime"]: print("排队等待时间预计还剩 {0} ms".format(0-queryOrderWaitTimeResult["data"]["waitTime"])) else: print ("正在等待中") elif "messages" in queryOrderWaitTimeResult and queryOrderWaitTimeResult["messages"]: print("排队等待失败: " + queryOrderWaitTimeResult["messages"]) else: print("第{}次排队中,请耐心等待".format(num+1)) else: print("排队中") time.sleep(2) else: print(ticketNumOutException("订单提交失败!,正在重新刷票")) def queryMyOrderNoComplete(self): """ 获取订单列表信息 :return: """ self.initNoComplete() queryMyOrderNoCompleteUrl = self.confUrl["queryMyOrderNoCompleteUrl"]["req_url"] data = {"_json_att": ""} try: queryMyOrderNoCompleteResult = self.httpClint.send(queryMyOrderNoCompleteUrl, data) except ValueError: queryMyOrderNoCompleteResult = {} if queryMyOrderNoCompleteResult: if "data" in queryMyOrderNoCompleteResult and queryMyOrderNoCompleteResult["data"] and "orderDBList" in queryMyOrderNoCompleteResult["data"] and queryMyOrderNoCompleteResult["data"]["orderDBList"]: orderId = queryMyOrderNoCompleteResult["data"]["orderDBList"][0]["sequence_no"] return orderId elif "data" in queryMyOrderNoCompleteResult and "orderCacheDTO" in queryMyOrderNoCompleteResult["data"] and queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]: if "message" in queryMyOrderNoCompleteResult["data"]["orderCacheDTO"] and queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]: print(queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]["message"]) raise ticketNumOutException(queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]["message"]) else: if "message" in queryMyOrderNoCompleteResult and queryMyOrderNoCompleteResult["message"]: print queryMyOrderNoCompleteResult["message"] return False else: return False else: print("接口 {} 无响应".format(queryMyOrderNoCompleteUrl)) def initNoComplete(self): """ 获取订单前需要进入订单列表页,获取订单列表页session :return: """ self.httpClint.set_cookies(acw_tc="AQAAAEnFJnekLwwAtGHjZZCr79B6dpXk", current_captcha_type="Z") initNoCompleteUrl = self.confUrl["initNoCompleteUrl"]["req_url"] data = {"_json_att": ""} self.httpClint.send(initNoCompleteUrl, data) def cancelNoCompleteMyOrder(self, sequence_no): """ 取消订单 :param sequence_no: 订单编号 :return: """ cancelNoCompleteMyOrderUrl = self.confUrl["cancelNoCompleteMyOrder"]["req_url"] cancelNoCompleteMyOrderData = { "sequence_no": sequence_no, "cancel_flag": "cancel_order", "_json_att": "" } cancelNoCompleteMyOrderResult = self.httpClint.send(cancelNoCompleteMyOrderUrl, cancelNoCompleteMyOrderData) if "data" in cancelNoCompleteMyOrderResult and "existError" in cancelNoCompleteMyOrderResult["data"] and cancelNoCompleteMyOrderResult["data"]["existError"] == "N": print("排队超时,已为您自动取消订单,订单编号: {0}".format(sequence_no)) time.sleep(2) return True else: print("排队超时,取消订单失败, 订单号{0}".format(sequence_no)) # def call_submit_ticket(self, function_name=None): # """ # 订票失败回调方法,默认执行submitOrderRequest() # 此方法暂不使用 # :param function_name: # :return: # """ # if function_name: # self.function_name() # else: # self.submitOrderRequest() def call_login(self, auth=False): """ 登录回调方法 :return: """ if auth: return self.login.auth() else: self.login.go_login() def main(self): self.call_login() from_station, to_station = self.station_table(self.from_station, self.to_station) self.check_user() time.sleep(0.1) num = 1 while 1: try: num += 1 if "user_time" in self.is_check_user and (datetime.datetime.now() - self.is_check_user["user_time"]).seconds/60 > 5: # 5分钟检查一次用户是否登录 self.check_user() time.sleep(self.select_refresh_interval) if time.strftime('%H:%M:%S', time.localtime(time.time())) > "23:00:00": print "12306休息时间,本程序自动停止,明天早上6点将自动运行" time.sleep(60 * 60 * 7) self.call_login() start_time = datetime.datetime.now() self.submitOrderRequestImplement(from_station, to_station) print "正在第{0}次查询 乘车日期: {1} 车次{2} 查询无票 代理设置 无 总耗时{3}ms".format(num, ",".join(self.station_dates), ",".join(self.station_trains), (datetime.datetime.now()-start_time).microseconds/1000) except PassengerUserException as e: print e.message break except ticketConfigException as e: print e.message break except ticketIsExitsException as e: print e.message break except ticketNumOutException as e: print e.message break except UserPasswordException as e: print e.message break except ValueError as e: if e.message == "No JSON object could be decoded": print("12306接口无响应,正在重试") else: print(e.message) except KeyError as e: print(e.message) except TypeError as e: print("12306接口无响应,正在重试 {0}".format(e.message)) except socket.error as e: print(e.message)
class select: """ 快速提交车票通道 """ def __init__(self): self.cdn_list = open_cdn_file("filter_cdn_list") self.get_ticket_info() self._station_seat = [seat_conf[x] for x in TickerConfig.SET_TYPE] self.auto_code_type = TickerConfig.AUTO_CODE_TYPE self.httpClint = HTTPClient(TickerConfig.IS_PROXY, self.cdn_list) self.httpClint.cdn = self.cdn_list[random.randint(0, 4)] self.urls = urlConf.urls self.login = GoLogin(self, TickerConfig.IS_AUTO_CODE, self.auto_code_type) self.cookies = "" self.queryUrl = "leftTicket/queryO" self.passengerTicketStrList = "" self.passengerTicketStrByAfterLate = "" self.oldPassengerStr = "" self.set_type = "" self.flag = True @staticmethod def get_ticket_info(): """ 获取配置信息 :return: """ print(u"*" * 50) print(f"检查当前版本为: {TickerConfig.RE_VERSION}") version = sys.version.split(" ")[0] print(u"检查当前python版本为:{},目前版本只支持3.6以上".format(version)) if version < "3.6.0": raise Exception print(u"12306刷票小助手,最后更新于2019.09.18,请勿作为商业用途,交流群号:" u" 1群:286271084(已满)\n" u" 2群:649992274(已满)\n" u" 3群:632501142(已满)\n" u" 4群: 606340519(已满)\n" u" 5群: 948526733(已满)\n" u" 7群: 660689659(已满)\n" u" 8群: 620629239(已满)\n" u" 6群: 608792930(未满)\n" u" 9群: 693035807(未满)\n") print( f"当前配置:\n出发站:{TickerConfig.FROM_STATION}\n到达站:{TickerConfig.TO_STATION}\n车次: {','.join(TickerConfig.STATION_TRAINS) or '所有车次'}\n乘车日期:{','.join(TickerConfig.STATION_DATES)}\n坐席:{','.join(TickerConfig.SET_TYPE)}\n是否有票优先提交:{TickerConfig.IS_MORE_TICKET}\n乘车人:{TickerConfig.TICKET_PEOPLES}\n" \ f"刷新间隔: 随机(1-3S)\n僵尸票关小黑屋时长: {TickerConfig.TICKET_BLACK_LIST_TIME}\n下单接口: {TickerConfig.ORDER_TYPE}\n下单模式: {TickerConfig.ORDER_MODEL}\n预售踩点时间:{TickerConfig.OPEN_TIME}") print(u"*" * 50) def station_table(self, from_station, to_station): """ 读取车站信息 :param station: :return: """ path = os.path.join(os.path.dirname(__file__), '../station_name.txt') try: with open(path, encoding="utf-8") as result: info = result.read().split('=')[1].strip("'").split('@') except Exception: with open(path) as result: info = result.read().split('=')[1].strip("'").split('@') del info[0] station_name = {} for i in range(0, len(info)): n_info = info[i].split('|') station_name[n_info[1]] = n_info[2] try: from_station = station_name[from_station.encode("utf8")] to_station = station_name[to_station.encode("utf8")] except KeyError: from_station = station_name[from_station] to_station = station_name[to_station] return from_station, to_station def call_login(self, auth=False): """ 登录回调方法 :return: """ if auth: return self.login.auth() else: configCommon.checkSleepTime(self) # 防止网上启动晚上到点休眠 self.login.go_login() def main(self): l = liftTicketInit(self) l.reqLiftTicketInit() getDrvicesID(self) self.call_login() check_user = checkUser(self) t = threading.Thread(target=check_user.sendCheckUser) t.setDaemon(True) t.start() from_station, to_station = self.station_table( TickerConfig.FROM_STATION, TickerConfig.TO_STATION) num = 0 s = getPassengerDTOs(selectObj=self, ticket_peoples=TickerConfig.TICKET_PEOPLES) passenger = s.sendGetPassengerDTOs() wrapcache.set("user_info", passenger, timeout=9999999) now = datetime.datetime.now() if TickerConfig.ORDER_MODEL is 1: print( f"预售还未开始,阻塞中,预售时间为{TickerConfig.OPEN_TIME}, 当前时间为: {now.strftime('%H:%M:%S')}" ) sleep_time_s = 0.1 sleep_time_t = 0.3 # 测试了一下有微妙级的误差,应该不影响,测试结果:2019-01-02 22:30:00.004555,预售还是会受到前一次刷新的时间影响,暂时没想到好的解决方案 while now.strftime("%H:%M:%S") < TickerConfig.OPEN_TIME: now = datetime.datetime.now() time.sleep(0.0001) print(f"预售开始,开启时间为: {now.strftime('%H:%M:%S')}") else: sleep_time_s = TickerConfig.MIN_TIME sleep_time_t = TickerConfig.MAX_TIME while 1: try: num += 1 now = datetime.datetime.now() # 感谢群里大佬提供整点代码 configCommon.checkSleepTime(self) # 晚上到点休眠 q = query( selectObj=self, from_station=from_station, to_station=to_station, from_station_h=TickerConfig.FROM_STATION, to_station_h=TickerConfig.TO_STATION, _station_seat=self._station_seat, station_trains=TickerConfig.STATION_TRAINS, station_dates=TickerConfig.STATION_DATES, ticke_peoples_num=len(TickerConfig.TICKET_PEOPLES), ) queryResult = q.sendQuery() # 查询接口 if queryResult.get("status"): train_no = queryResult.get("train_no", "") train_date = queryResult.get("train_date", "") stationTrainCode = queryResult.get("stationTrainCode", "") secretStr = queryResult.get("secretStr", "") secretList = queryResult.get("secretList", "") seat = queryResult.get("seat", "") leftTicket = queryResult.get("leftTicket", "") query_from_station_name = queryResult.get( "query_from_station_name", "") query_to_station_name = queryResult.get( "query_to_station_name", "") is_more_ticket_num = queryResult.get( "is_more_ticket_num", len(TickerConfig.TICKET_PEOPLES)) if wrapcache.get(train_no): print(ticket.QUEUE_WARNING_MSG.format(train_no)) else: # 获取联系人 s = getPassengerDTOs( selectObj=self, ticket_peoples=TickerConfig.TICKET_PEOPLES, set_type="" if isinstance(seat, list) else seat_conf_2[seat], # 候补订单需要设置多个坐席 is_more_ticket_num=is_more_ticket_num) getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr( secretStr, secretList) if getPassengerDTOsResult.get("status", False): self.passengerTicketStrList = getPassengerDTOsResult.get( "passengerTicketStrList", "") self.passengerTicketStrByAfterLate = getPassengerDTOsResult.get( "passengerTicketStrByAfterLate", "") self.oldPassengerStr = getPassengerDTOsResult.get( "oldPassengerStr", "") self.set_type = getPassengerDTOsResult.get( "set_type", "") # 提交订单 # 订单分为两种,一种为抢单,一种为候补订单 if secretStr: # 正常下单 if TickerConfig.ORDER_TYPE == 1: # 快速下单 a = autoSubmitOrderRequest( selectObj=self, secretStr=secretStr, train_date=train_date, passengerTicketStr=self. passengerTicketStrList, oldPassengerStr=self.oldPassengerStr, train_no=train_no, stationTrainCode=stationTrainCode, leftTicket=leftTicket, set_type=self.set_type, query_from_station_name= query_from_station_name, query_to_station_name=query_to_station_name, ) a.sendAutoSubmitOrderRequest() elif TickerConfig.ORDER_TYPE == 2: # 普通下单 sor = submitOrderRequest( self, secretStr, from_station, to_station, train_no, self.set_type, self.passengerTicketStrList, self.oldPassengerStr, train_date, TickerConfig.TICKET_PEOPLES) sor.sendSubmitOrderRequest() elif secretList: # 候补订单 c = chechFace(self, secretList, train_no) c.sendChechFace() else: random_time = round( random.uniform(sleep_time_s, sleep_time_t), 2) nateMsg = ' 无候补机会' if TickerConfig.ORDER_TYPE == 2 else "" print( f"正在第{num}次查询 停留时间:{random_time} 乘车日期: {','.join(TickerConfig.STATION_DATES)} 车次:{','.join(TickerConfig.STATION_TRAINS) or '所有车次'} 下单无票{nateMsg} 耗时:{(datetime.datetime.now() - now).microseconds / 1000} {queryResult.get('cdn')}" ) time.sleep(random_time) except PassengerUserException as e: print(e) break except ticketConfigException as e: print(e) break except ticketIsExitsException as e: print(e) break except ticketNumOutException as e: print(e) break except UserPasswordException as e: print(e) break except ValueError as e: if e == "No JSON object could be decoded": print(u"12306接口无响应,正在重试") else: print(e) except KeyError as e: print(e) except TypeError as e: print(u"12306接口无响应,正在重试 {0}".format(e)) except socket.error as e: print(e)
class payorder: """ 快速提交车票通道 """ def __init__(self): self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, \ self.ticke_peoples, self.station_trains, self.ticket_black_list_time, \ self.order_type, self.is_by_time, self.train_types, self.departure_time, \ self.arrival_time, self.take_time, self.order_model, self.open_time, self.is_proxy = self.get_ticket_info() self.is_auto_code = _get_yaml()["is_auto_code"] self.auto_code_type = _get_yaml()["auto_code_type"] self.is_cdn = _get_yaml()["is_cdn"] self.httpClint = HTTPClient(self.is_proxy) self.urls = urlConf.urls self.login = GoLogin(self, self.is_auto_code, self.auto_code_type) self.cdn_list = [] self.queryUrl = "leftTicket/queryZ" self.passengerTicketStrList = "" self.oldPassengerStr = "" self.set_type = "" def get_ticket_info(self): """ 获取配置信息 :return: """ ticket_info_config = _get_yaml() from_station = ticket_info_config["set"]["from_station"] to_station = ticket_info_config["set"]["to_station"] station_dates = ticket_info_config["set"]["station_dates"] set_names = ticket_info_config["set"]["set_type"] set_type = [ seat_conf[x.encode("utf-8")] for x in ticket_info_config["set"]["set_type"] ] is_more_ticket = ticket_info_config["set"]["is_more_ticket"] ticke_peoples = ticket_info_config["set"]["ticke_peoples"] station_trains = ticket_info_config["set"]["station_trains"] ticket_black_list_time = ticket_info_config["ticket_black_list_time"] order_type = ticket_info_config["order_type"] # by time is_by_time = ticket_info_config["set"]["is_by_time"] train_types = ticket_info_config["set"]["train_types"] departure_time = time_to_minutes( ticket_info_config["set"]["departure_time"]) arrival_time = time_to_minutes( ticket_info_config["set"]["arrival_time"]) take_time = time_to_minutes(ticket_info_config["set"]["take_time"]) # 下单模式 order_model = ticket_info_config["order_model"] open_time = ticket_info_config["open_time"] # 代理模式 is_proxy = ticket_info_config["is_proxy"] print(u"*" * 50) print(u"检查当前python版本为:{},目前版本只支持2.7.10-2.7.15".format( sys.version.split(" ")[0])) print( u"12306刷票小助手,最后更新于2019.01.08,请勿作为商业用途,交流群号:286271084(已满), 2群:649992274(已满),请加3群(未满), 群号:632501142、4群(未满), 群号:606340519" ) if is_by_time: method_notie = u"购票方式:根据时间区间购票\n可接受最早出发时间:{0}\n可接受最晚抵达时间:{1}\n可接受最长旅途时间:{2}\n可接受列车类型:{3}\n" \ .format(minutes_to_time(departure_time), minutes_to_time(arrival_time), minutes_to_time(take_time), " , ".join(train_types)) else: method_notie = u"购票方式:根据候选车次购买\n候选购买车次:{0}".format( ",".join(station_trains)) print (u"当前配置:\n出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票优先提交:{4}\n乘车人:{5}\n" \ u"刷新间隔: 随机(1-3S)\n{6}\n僵尸票关小黑屋时长: {7}\n下单接口: {8}\n下单模式: {9}\n预售踩点时间:{10} ".format \ ( from_station, to_station, station_dates, ",".join(set_names), is_more_ticket, ",".join(ticke_peoples), method_notie, ticket_black_list_time, order_type, order_model, open_time, )) print(u"*" * 50) return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, station_trains, \ ticket_black_list_time, order_type, is_by_time, train_types, departure_time, arrival_time, take_time, \ order_model, open_time, is_proxy def station_table(self, from_station, to_station): """ 读取车站信息 :param station: :return: """ path = os.path.join(os.path.dirname(__file__), '../station_name.txt') result = open(path) info = result.read().split('=')[1].strip("'").split('@') del info[0] station_name = {} for i in range(0, len(info)): n_info = info[i].split('|') station_name[n_info[1]] = n_info[2] from_station = station_name[from_station.encode("utf8")] to_station = station_name[to_station.encode("utf8")] return from_station, to_station def call_login(self, auth=False): """ 登录回调方法 :return: """ if auth: return self.login.auth() else: self.login.go_login() def cdn_req(self, cdn): for i in range(len(cdn) - 1): http = HTTPClient(0) urls = self.urls["loginInitCdn"] http._cdn = cdn[i].replace("\n", "") start_time = datetime.datetime.now() rep = http.send(urls) if rep and "message" not in rep and (datetime.datetime.now( ) - start_time).microseconds / 1000 < 500: if cdn[i].replace("\n", "") not in self.cdn_list: # 如果有重复的cdn,则放弃加入 # print(u"加入cdn {0}".format(cdn[i].replace("\n", ""))) self.cdn_list.append(cdn[i].replace("\n", "")) print(u"所有cdn解析完成...") def cdn_certification(self): """ cdn 认证 :return: """ if self.is_cdn == 1: CDN = CDNProxy() all_cdn = CDN.open_cdn_file() if all_cdn: # print(u"由于12306网站策略调整,cdn功能暂时关闭。") print(u"开启cdn查询") print(u"本次待筛选cdn总数为{}, 筛选时间大约为5-10min".format(len(all_cdn))) t = threading.Thread(target=self.cdn_req, args=(all_cdn, )) t.setDaemon(True) # t2 = threading.Thread(target=self.set_cdn, args=()) t.start() # t2.start() else: raise ticketConfigException(u"cdn列表为空,请先加载cdn") def main(self): autoSynchroTime() # 同步时间 self.cdn_certification() l = liftTicketInit(self) l.reqLiftTicketInit() self.call_login() #检查用户登录, 检查间隔为2分钟 check_user = checkUser(self) t = threading.Thread(target=check_user.sendCheckUser) t.setDaemon(True) t.start() from_station, to_station = self.station_table(self.from_station, self.to_station) print("********OKOKOKOKOKO******") driver.get("https://kyfw.12306.cn/otn/view/train_order.html") #获取页面名为wraper的id标签的文本内容 data = driver.page_source print data driver.quit() #打印数据内容 print(data) num = 0 while 1: try: num += 1 now = datetime.datetime.now() # 感谢群里大佬提供整点代码 configCommon.checkSleepTime(self) # 晚上到点休眠 if self.order_model is 1: sleep_time_s = 0.5 sleep_time_t = 0.6 # 测试了一下有微妙级的误差,应该不影响,测试结果:2019-01-02 22:30:00.004555,预售还是会受到前一次刷新的时间影响,暂时没想到好的解决方案 while not now.strftime("%H:%M:%S") == self.open_time: now = datetime.datetime.now() if now.strftime("%H:%M:%S") > self.open_time: break time.sleep(0.0001) else: sleep_time_s = 0.5 sleep_time_t = 3 # pay = payOrder(self) # pay.reqPayorder() except PassengerUserException as e: print(e) break except ticketConfigException as e: print(e) break except ticketIsExitsException as e: print(e) break except ticketNumOutException as e: print(e) break except UserPasswordException as e: print(e) break except ValueError as e: if e == "No JSON object could be decoded": print(u"12306接口无响应,正在重试") else: print(e) except KeyError as e: print(e) except TypeError as e: print(u"12306接口无响应,正在重试 {0}".format(e)) except socket.error as e: print(e)
class select: """ 快速提交车票通道 """ def __init__(self): self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, \ self.ticke_peoples, self.station_trains, self.ticket_black_list_time, \ self.order_type, self.is_by_time, self.train_types, self.departure_time, \ self.arrival_time, self.take_time, self.order_model, self.open_time, self.is_proxy = self.get_ticket_info() self.is_auto_code = _get_yaml()["is_auto_code"] self.auto_code_type = _get_yaml()["auto_code_type"] self.is_cdn = _get_yaml()["is_cdn"] self.httpClint = HTTPClient(self.is_proxy) self.urls = urlConf.urls self.login = GoLogin(self, self.is_auto_code, self.auto_code_type) self.cdn_list = [] self.queryUrl = "leftTicket/queryZ" self.passengerTicketStrList = "" self.oldPassengerStr = "" self.set_type = "" def get_ticket_info(self): """ 获取配置信息 :return: """ ticket_info_config = _get_yaml() from_station = ticket_info_config["set"]["from_station"] to_station = ticket_info_config["set"]["to_station"] station_dates = ticket_info_config["set"]["station_dates"] set_names = ticket_info_config["set"]["set_type"] try: set_type = [ seat_conf[x.encode("utf-8")] for x in ticket_info_config["set"]["set_type"] ] except KeyError: set_type = [ seat_conf[x] for x in ticket_info_config["set"]["set_type"] ] is_more_ticket = ticket_info_config["set"]["is_more_ticket"] ticke_peoples = ticket_info_config["set"]["ticke_peoples"] station_trains = ticket_info_config["set"]["station_trains"] ticket_black_list_time = ticket_info_config["ticket_black_list_time"] order_type = ticket_info_config["order_type"] # by time is_by_time = ticket_info_config["set"]["is_by_time"] train_types = ticket_info_config["set"]["train_types"] departure_time = time_to_minutes( ticket_info_config["set"]["departure_time"]) arrival_time = time_to_minutes( ticket_info_config["set"]["arrival_time"]) take_time = time_to_minutes(ticket_info_config["set"]["take_time"]) # 下单模式 order_model = ticket_info_config["order_model"] open_time = ticket_info_config["open_time"] # 代理模式 is_proxy = ticket_info_config["is_proxy"] print(u"*" * 50) print(u"检查当前python版本为:{},目前版本只支持2.7.10-2.7.15".format( sys.version.split(" ")[0])) print(u"12306刷票小助手,最后更新于2019.01.08,请勿作为商业用途,交流群号:286271084(已满)," u" 2群:649992274(已满)\n" u" 3群:632501142(已满)\n" u" 4群: 606340519(已满)\n" u" 5群: 948526733(已满)\n" u" 6群: 444101020(未满)\n" u" 7群: 660689659(未满)\n") if is_by_time: method_notie = u"购票方式:根据时间区间购票\n可接受最早出发时间:{0}\n可接受最晚抵达时间:{1}\n可接受最长旅途时间:{2}\n可接受列车类型:{3}\n" \ .format(minutes_to_time(departure_time), minutes_to_time(arrival_time), minutes_to_time(take_time), " , ".join(train_types)) else: method_notie = u"购票方式:根据候选车次购买\n候选购买车次:{0}".format( ",".join(station_trains)) print (u"当前配置:\n出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票优先提交:{4}\n乘车人:{5}\n" \ u"刷新间隔: 随机(1-3S)\n{6}\n僵尸票关小黑屋时长: {7}\n下单接口: {8}\n下单模式: {9}\n预售踩点时间:{10} ".format \ ( from_station, to_station, station_dates, ",".join(set_names), is_more_ticket, ",".join(ticke_peoples), method_notie, ticket_black_list_time, order_type, order_model, open_time, )) print(u"*" * 50) return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, station_trains, \ ticket_black_list_time, order_type, is_by_time, train_types, departure_time, arrival_time, take_time, \ order_model, open_time, is_proxy def station_table(self, from_station, to_station): """ 读取车站信息 :param station: :return: """ path = os.path.join(os.path.dirname(__file__), '../station_name.txt') try: with open(path, encoding="utf-8") as result: info = result.read().split('=')[1].strip("'").split('@') except Exception: with open(path) as result: info = result.read().split('=')[1].strip("'").split('@') del info[0] station_name = {} for i in range(0, len(info)): n_info = info[i].split('|') station_name[n_info[1]] = n_info[2] try: from_station = station_name[from_station.encode("utf8")] to_station = station_name[to_station.encode("utf8")] except KeyError: from_station = station_name[from_station] to_station = station_name[to_station] return from_station, to_station def call_login(self, auth=False): """ 登录回调方法 :return: """ if auth: return self.login.auth() else: configCommon.checkSleepTime(self) # 防止网上启动晚上到点休眠 self.login.go_login() def cdn_req(self, cdn): for i in range(len(cdn) - 1): http = HTTPClient(0) urls = self.urls["loginInitCdn"] http._cdn = cdn[i].replace("\n", "") start_time = datetime.datetime.now() rep = http.send(urls) if rep and "message" not in rep and (datetime.datetime.now( ) - start_time).microseconds / 1000 < 500: if cdn[i].replace("\n", "") not in self.cdn_list: # 如果有重复的cdn,则放弃加入 # print(u"加入cdn {0}".format(cdn[i].replace("\n", ""))) self.cdn_list.append(cdn[i].replace("\n", "")) print(u"所有cdn解析完成...") def cdn_certification(self): """ cdn 认证 :return: """ if self.is_cdn == 1: CDN = CDNProxy() all_cdn = CDN.open_cdn_file() if all_cdn: # print(u"由于12306网站策略调整,cdn功能暂时关闭。") print(u"开启cdn查询") print(u"本次待筛选cdn总数为{}, 筛选时间大约为5-10min".format(len(all_cdn))) t = threading.Thread(target=self.cdn_req, args=(all_cdn, )) t.setDaemon(True) # t2 = threading.Thread(target=self.set_cdn, args=()) t.start() # t2.start() else: raise ticketConfigException(u"cdn列表为空,请先加载cdn") def main(self): # autoSynchroTime() # 同步时间 self.cdn_certification() l = liftTicketInit(self) l.reqLiftTicketInit() self.call_login() check_user = checkUser(self) t = threading.Thread(target=check_user.sendCheckUser) t.setDaemon(True) t.start() from_station, to_station = self.station_table(self.from_station, self.to_station) num = 0 s = getPassengerDTOs(session=self, ticket_peoples=self.ticke_peoples) passenger = s.sendGetPassengerDTOs() wrapcache.set("user_info", passenger, timeout=9999999) while 1: try: num += 1 now = datetime.datetime.now() # 感谢群里大佬提供整点代码 configCommon.checkSleepTime(self) # 晚上到点休眠 if self.order_model is 1: sleep_time_s = 0.5 sleep_time_t = 0.6 # 测试了一下有微妙级的误差,应该不影响,测试结果:2019-01-02 22:30:00.004555,预售还是会受到前一次刷新的时间影响,暂时没想到好的解决方案 while not now.strftime("%H:%M:%S") == self.open_time: now = datetime.datetime.now() if now.strftime("%H:%M:%S") > self.open_time: break time.sleep(0.0001) else: sleep_time_s = 0.5 sleep_time_t = 3 q = query( session=self, from_station=from_station, to_station=to_station, from_station_h=self.from_station, to_station_h=self.to_station, _station_seat=self._station_seat, station_trains=self.station_trains, station_dates=self.station_dates, ticke_peoples_num=len(self.ticke_peoples), ) queryResult = q.sendQuery() # 查询接口 if queryResult.get("status", False): train_no = queryResult.get("train_no", "") train_date = queryResult.get("train_date", "") stationTrainCode = queryResult.get("stationTrainCode", "") secretStr = queryResult.get("secretStr", "") seat = queryResult.get("seat", "") leftTicket = queryResult.get("leftTicket", "") query_from_station_name = queryResult.get( "query_from_station_name", "") query_to_station_name = queryResult.get( "query_to_station_name", "") is_more_ticket_num = queryResult.get( "is_more_ticket_num", len(self.ticke_peoples)) if wrapcache.get(train_no): print(ticket.QUEUE_WARNING_MSG.format(train_no)) else: # 获取联系人 s = getPassengerDTOs( session=self, ticket_peoples=self.ticke_peoples, set_type=seat_conf_2[seat], is_more_ticket_num=is_more_ticket_num) getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr( ) if getPassengerDTOsResult.get("status", False): self.passengerTicketStrList = getPassengerDTOsResult.get( "passengerTicketStrList", "") self.oldPassengerStr = getPassengerDTOsResult.get( "oldPassengerStr", "") self.set_type = getPassengerDTOsResult.get( "set_type", "") # 提交订单 if self.order_type == 1: # 快读下单 a = autoSubmitOrderRequest( session=self, secretStr=secretStr, train_date=train_date, passengerTicketStr=self.passengerTicketStrList, oldPassengerStr=self.oldPassengerStr, train_no=train_no, stationTrainCode=stationTrainCode, leftTicket=leftTicket, set_type=self.set_type, query_from_station_name=query_from_station_name, query_to_station_name=query_to_station_name, ) a.sendAutoSubmitOrderRequest() elif self.order_type == 2: # 普通下单 sor = submitOrderRequest( self, secretStr, from_station, to_station, train_no, self.set_type, self.passengerTicketStrList, self.oldPassengerStr, train_date, self.ticke_peoples) sor.sendSubmitOrderRequest() else: random_time = round( random.uniform(sleep_time_s, sleep_time_t), 2) print( u"正在第{0}次查询 随机停留时长:{6} 乘车日期: {1} 车次:{2} 查询无票 cdn轮询IP:{4}当前cdn总数:{5} 总耗时:{3}ms" .format(num, ",".join(self.station_dates), ",".join(self.station_trains), (datetime.datetime.now() - now).microseconds / 1000, queryResult.get("cdn", None), len(self.cdn_list), random_time)) time.sleep(random_time) except PassengerUserException as e: print(e) break except ticketConfigException as e: print(e) break except ticketIsExitsException as e: print(e) break except ticketNumOutException as e: print(e) break except UserPasswordException as e: print(e) break except ValueError as e: if e == "No JSON object could be decoded": print(u"12306接口无响应,正在重试") else: print(e) except KeyError as e: print(e) except TypeError as e: print(u"12306接口无响应,正在重试 {0}".format(e)) except socket.error as e: print(e)
class select: """ 快速提交车票通道 """ def __init__(self): self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, \ self.ticke_peoples, self.station_trains, self.ticket_black_list_time, \ self.order_type = self.get_ticket_info() self.is_auto_code = _get_yaml()["is_auto_code"] self.auto_code_type = _get_yaml()["auto_code_type"] self.is_cdn = _get_yaml()["is_cdn"] self.httpClint = HTTPClient() self.urls = urlConf.urls self.login = GoLogin(self, self.is_auto_code, self.auto_code_type) self.cdn_list = [] self.passengerTicketStrList = "" self.oldPassengerStr = "" def get_ticket_info(self): """ 获取配置信息 :return: """ ticket_info_config = _get_yaml() from_station = ticket_info_config["set"]["from_station"].encode("utf8") to_station = ticket_info_config["set"]["to_station"].encode("utf8") station_dates = ticket_info_config["set"]["station_dates"] set_type = ticket_info_config["set"]["set_type"] is_more_ticket = ticket_info_config["set"]["is_more_ticket"] ticke_peoples = ticket_info_config["set"]["ticke_peoples"] station_trains = ticket_info_config["set"]["station_trains"] ticket_black_list_time = ticket_info_config["ticket_black_list_time"] order_type = ticket_info_config["order_type"] print u"*" * 20 print u"12306刷票小助手,最后更新于2018.8.31,请勿作为商业用途,交流群号:286271084" print u"如果有好的margin,请联系作者,表示非常感激\n" print u"当前配置:出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票自动提交:{4}\n乘车人:{5}\n" \ u"刷新间隔:随机(1-4S)\n候选购买车次:{6}\n僵尸票关小黑屋时长:{7}\n 下单接口:{8}\n".format \ ( from_station, to_station, station_dates, ",".join(set_type), is_more_ticket, ",".join(ticke_peoples), ",".join(station_trains), ticket_black_list_time, order_type, ) print u"*" * 20 return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, station_trains, ticket_black_list_time, order_type def station_table(self, from_station, to_station): """ 读取车站信息 :param station: :return: """ result = open('station_name.txt') info = result.read().split('=')[1].strip("'").split('@') del info[0] station_name = {} for i in range(0, len(info)): n_info = info[i].split('|') station_name[n_info[1]] = n_info[2] from_station = station_name[from_station.encode("utf8")] to_station = station_name[to_station.encode("utf8")] return from_station, to_station def call_login(self, auth=False): """ 登录回调方法 :return: """ if auth: return self.login.auth() else: self.login.go_login() def set_cdn(self): """ 设置cdn :return: """ if self.is_cdn == 1: while True: if self.cdn_list: self.httpClint.cdn = self.cdn_list[random.randint(0, len(self.cdn_list) - 1)] def cdn_req(self, cdn): for i in range(len(cdn) - 1): http = HTTPClient() urls = self.urls["loginInit"] start_time = datetime.datetime.now() http.cdn = cdn[i].replace("\n", "") rep = http.send(urls) if rep and "message" not in rep and (datetime.datetime.now() - start_time).microseconds / 1000 < 500: print("加入cdn {0}".format(cdn[i].replace("\n", ""))) self.cdn_list.append(cdn[i].replace("\n", "")) print(u"所有cdn解析完成...") def cdn_certification(self): """ cdn 认证 :return: """ if self.is_cdn == 1: CDN = CDNProxy() all_cdn = CDN.all_cdn() if all_cdn: print(u"开启cdn查询") print(u"本次待筛选cdn总数为{}".format(len(all_cdn))) t = threading.Thread(target=self.cdn_req, args=(all_cdn,)) t2 = threading.Thread(target=self.set_cdn, args=()) t.start() t2.start() else: raise ticketConfigException(u"cdn列表为空,请先加载cdn") else: pass def query_train_ticket(self, from_station, to_station, station_dates, train_no=None): """查询车次余票 """ self.cdn_certification() l = liftTicketInit(session=self) l.reqLiftTicketInit() checkUser(self).sendCheckUser() num = 0 while num < 5: try: num += 1 # checkUser(self).sendCheckUser() q = QueryTecket(session=self, station_dates=station_dates) # queryResult = q.sendQuery(from_station, to_station, train_no) queryResult = q.get_trains_status(from_station, to_station, train_no, True) # if len(queryResult) == 1: # continue col_name = [u'车次', u'发站', u'到站', u'发车', u'到达', u'耗时', u'出发日期', u'无座', u'硬座', u'硬卧', u'软卧', u'高软', u'二等', u'一等', u'商务', u'动卧'] print json.dumps(col_name, ensure_ascii=False) for ret in queryResult: for en in ret: print json.dumps(en, ensure_ascii=False) return queryResult except Exception as ex: logging.error(traceback.format_exc()) def main(self): self.cdn_certification() l = liftTicketInit(session=self) l.reqLiftTicketInit() self.call_login() checkUser(self).sendCheckUser() from_station, to_station = self.station_table(self.from_station, self.to_station) num = 0 while 1: try: num += 1 checkUser(self).sendCheckUser() if time.strftime('%H:%M:%S', time.localtime(time.time())) > "23:00:00" or time.strftime('%H:%M:%S', time.localtime( time.time())) < "06:00:00": print(ticket.REST_TIME) # while 1: # time.sleep(1) # if "06:00:00" < time.strftime('%H:%M:%S', time.localtime(time.time())) < "23:00:00": # print(ticket.REST_TIME_PAST) # self.call_login() # break start_time = datetime.datetime.now() q = query(session=self, from_station=from_station, to_station=to_station, from_station_h=self.from_station, to_station_h=self.to_station, _station_seat=self._station_seat, station_trains=self.station_trains, station_dates=self.station_dates, ) queryResult = q.sendQuery() # 查询接口 # tmp = queryResult.get("status", False) # assert tmp == False if queryResult.get("status", False): train_no = queryResult.get("train_no", "") train_date = queryResult.get("train_date", "") stationTrainCode = queryResult.get("stationTrainCode", "") set_type = queryResult.get("set_type", "") secretStr = queryResult.get("secretStr", "") leftTicket = queryResult.get("leftTicket", "") query_from_station_name = queryResult.get("query_from_station_name", "") query_to_station_name = queryResult.get("query_to_station_name", "") if wrapcache.get(train_no): print(ticket.QUEUE_WARNING_MSG.format(train_no)) else: # 获取联系人 if not self.passengerTicketStrList and not self.oldPassengerStr: s = getPassengerDTOs(session=self, ticket_peoples=self.ticke_peoples, set_type=set_type) # getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr() if getPassengerDTOsResult.get("status", False): self.passengerTicketStrList = getPassengerDTOsResult.get("passengerTicketStrList", "") self.oldPassengerStr = getPassengerDTOsResult.get("oldPassengerStr", "") set_type = getPassengerDTOsResult.get("set_type", "") # 提交订单 if self.order_type == 1: # 快读下单 a = autoSubmitOrderRequest(session=self, secretStr=secretStr, train_date=train_date, passengerTicketStr=self.passengerTicketStrList, oldPassengerStr=self.oldPassengerStr, train_no=train_no, stationTrainCode=stationTrainCode, leftTicket=leftTicket, set_type=set_type, query_from_station_name=query_from_station_name, query_to_station_name=query_to_station_name, ) a.sendAutoSubmitOrderRequest() elif self.order_type == 2: # 普通下单 sor = submitOrderRequest(self, secretStr, from_station, to_station, train_no, set_type, self.passengerTicketStrList, self.oldPassengerStr, train_date, self.ticke_peoples) sor.sendSubmitOrderRequest() else: random_time = round(random.uniform(1, 4), 2) time.sleep(random_time) print u"正在第{0}次查询 随机停留时长:{6} 乘车日期: {1} 车次:{2} 查询无票 cdn轮询IP:{4}当前cdn总数:{5} 总耗时:{3}ms".format(num, ",".join( self.station_dates), ",".join( self.station_trains), (datetime.datetime.now() - start_time).microseconds / 1000, self.httpClint.cdn, len(self.cdn_list), random_time) except PassengerUserException as e: print e.message break except ticketConfigException as e: print e.message break except ticketIsExitsException as e: print e.message break except ticketNumOutException as e: print e.message break except UserPasswordException as e: print e.message break except ValueError as e: if e.message == "No JSON object could be decoded": print(u"12306接口无响应,正在重试") else: print(e.message) except KeyError as e: print(e.message) except TypeError as e: print(u"12306接口无响应,正在重试 {0}".format(e.message)) except socket.error as e: print(e.message)
class select: """ 快速提交车票通道 """ def __init__(self): self.get_ticket_info() self._station_seat = [seat_conf[x] for x in TickerConfig.SET_TYPE] self.auto_code_type = 2 self.httpClint = HTTPClient(TickerConfig.IS_PROXY) self.urls = urlConf.urls self.login = GoLogin(self, TickerConfig.IS_AUTO_CODE, self.auto_code_type) self.cdn_list = [] self.queryUrl = "leftTicket/queryT" self.passengerTicketStrList = "" self.passengerTicketStrByAfterLate = "" self.oldPassengerStr = "" self.set_type = "" self.flag = True @staticmethod def get_ticket_info(): """ 获取配置信息 :return: """ print(u"*" * 50) print(f"检查当前版本为: {TickerConfig.RE_VERSION}") print(u"检查当前python版本为:{},目前版本只支持3.6以上".format( sys.version.split(" ")[0])) print(u"12306刷票小助手,最后更新于2019.09.03,请勿作为商业用途,交流群号:" u" 1群:286271084(已满)\n" u" 2群:649992274(已满)\n" u" 3群:632501142(已满)\n" u" 4群: 606340519(已满)\n" u" 5群: 948526733(已满)\n" u" 6群: 444101020(未满)\n" u" 7群: 660689659(未满)\n") print( f"当前配置:\n出发站:{TickerConfig.FROM_STATION}\n到达站:{TickerConfig.TO_STATION}\n乘车日期:{','.join(TickerConfig.STATION_DATES)}\n坐席:{','.join(TickerConfig.SET_TYPE)}\n是否有票优先提交:{TickerConfig.IS_MORE_TICKET}\n乘车人:{TickerConfig.TICKET_PEOPLES}\n" \ f"刷新间隔: 随机(1-3S)\n僵尸票关小黑屋时长: {TickerConfig.TICKET_BLACK_LIST_TIME}\n下单接口: {TickerConfig.ORDER_TYPE}\n下单模式: {TickerConfig.ORDER_MODEL}\n预售踩点时间:{TickerConfig.OPEN_TIME}") print(u"*" * 50) def station_table(self, from_station, to_station): """ 读取车站信息 :param station: :return: """ path = os.path.join(os.path.dirname(__file__), '../station_name.txt') try: with open(path, encoding="utf-8") as result: info = result.read().split('=')[1].strip("'").split('@') except Exception: with open(path) as result: info = result.read().split('=')[1].strip("'").split('@') del info[0] station_name = {} for i in range(0, len(info)): n_info = info[i].split('|') station_name[n_info[1]] = n_info[2] try: from_station = station_name[from_station.encode("utf8")] to_station = station_name[to_station.encode("utf8")] except KeyError: from_station = station_name[from_station] to_station = station_name[to_station] return from_station, to_station def call_login(self, auth=False): """ 登录回调方法 :return: """ if auth: return self.login.auth() else: configCommon.checkSleepTime(self) # 防止网上启动晚上到点休眠 self.login.go_login() def cdn_req(self, cdn): for i in range(len(cdn) - 1): http = HTTPClient(0) urls = self.urls["loginInitCdn"] http._cdn = cdn[i].replace("\n", "") start_time = datetime.datetime.now() rep = http.send(urls) if rep and "message" not in rep and (datetime.datetime.now( ) - start_time).microseconds / 1000 < 500: if cdn[i].replace("\n", "") not in self.cdn_list: # 如果有重复的cdn,则放弃加入 # print(u"加入cdn {0}".format(cdn[i].replace("\n", ""))) self.cdn_list.append(cdn[i].replace("\n", "")) print(u"所有cdn解析完成...") def cdn_certification(self): """ cdn 认证 :return: """ if TickerConfig.IS_CDN == 1: CDN = CDNProxy() all_cdn = CDN.open_cdn_file() if all_cdn: # print(u"由于12306网站策略调整,cdn功能暂时关闭。") print(u"开启cdn查询") print(u"本次待筛选cdn总数为{}, 筛选时间大约为5-10min".format(len(all_cdn))) t = threading.Thread(target=self.cdn_req, args=(all_cdn, )) t.setDaemon(True) # t2 = threading.Thread(target=self.set_cdn, args=()) t.start() # t2.start() else: raise ticketConfigException(u"cdn列表为空,请先加载cdn") def main(self): self.cdn_certification() l = liftTicketInit(self) l.reqLiftTicketInit() # getDrvicesID(self) self.call_login() check_user = checkUser(self) t = threading.Thread(target=check_user.sendCheckUser) t.setDaemon(True) t.start() from_station, to_station = self.station_table( TickerConfig.FROM_STATION, TickerConfig.TO_STATION) num = 0 s = getPassengerDTOs(session=self, ticket_peoples=TickerConfig.TICKET_PEOPLES) passenger = s.sendGetPassengerDTOs() wrapcache.set("user_info", passenger, timeout=9999999) while 1: try: num += 1 now = datetime.datetime.now() # 感谢群里大佬提供整点代码 configCommon.checkSleepTime(self) # 晚上到点休眠 if TickerConfig.ORDER_MODEL is 1: sleep_time_s = 0.5 sleep_time_t = 0.6 # 测试了一下有微妙级的误差,应该不影响,测试结果:2019-01-02 22:30:00.004555,预售还是会受到前一次刷新的时间影响,暂时没想到好的解决方案 while not now.strftime( "%H:%M:%S") == TickerConfig.OPEN_TIME: now = datetime.datetime.now() if now.strftime("%H:%M:%S") > TickerConfig.OPEN_TIME: break time.sleep(0.0001) else: sleep_time_s = 0.5 sleep_time_t = 3 q = query( session=self, from_station=from_station, to_station=to_station, from_station_h=TickerConfig.FROM_STATION, to_station_h=TickerConfig.TO_STATION, _station_seat=self._station_seat, station_trains=TickerConfig.STATION_TRAINS, station_dates=TickerConfig.STATION_DATES, ticke_peoples_num=len(TickerConfig.TICKET_PEOPLES), ) queryResult = q.sendQuery() # 查询接口 if queryResult.get("status", False): train_no = queryResult.get("train_no", "") train_date = queryResult.get("train_date", "") stationTrainCode = queryResult.get("stationTrainCode", "") secretStr = queryResult.get("secretStr", "") secretList = queryResult.get("secretList", "") seat = queryResult.get("seat", "") leftTicket = queryResult.get("leftTicket", "") query_from_station_name = queryResult.get( "query_from_station_name", "") query_to_station_name = queryResult.get( "query_to_station_name", "") is_more_ticket_num = queryResult.get( "is_more_ticket_num", len(TickerConfig.TICKET_PEOPLES)) if wrapcache.get(train_no): print(ticket.QUEUE_WARNING_MSG.format(train_no)) else: # 获取联系人 s = getPassengerDTOs( session=self, ticket_peoples=TickerConfig.TICKET_PEOPLES, set_type="" if isinstance(seat, list) else seat_conf_2[seat], # 候补订单需要设置多个坐席 is_more_ticket_num=is_more_ticket_num) getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr( secretStr, secretList) if getPassengerDTOsResult.get("status", False): self.passengerTicketStrList = getPassengerDTOsResult.get( "passengerTicketStrList", "") self.passengerTicketStrByAfterLate = getPassengerDTOsResult.get( "passengerTicketStrByAfterLate", "") self.oldPassengerStr = getPassengerDTOsResult.get( "oldPassengerStr", "") self.set_type = getPassengerDTOsResult.get( "set_type", "") # 提交订单 # 订单分为两种,一种为抢单,一种为候补订单 if secretStr: # 正常下单 if TickerConfig.ORDER_TYPE == 1: # 快速下单 a = autoSubmitOrderRequest( session=self, secretStr=secretStr, train_date=train_date, passengerTicketStr=self. passengerTicketStrList, oldPassengerStr=self.oldPassengerStr, train_no=train_no, stationTrainCode=stationTrainCode, leftTicket=leftTicket, set_type=self.set_type, query_from_station_name= query_from_station_name, query_to_station_name=query_to_station_name, ) a.sendAutoSubmitOrderRequest() elif TickerConfig.ORDER_TYPE == 2: # 普通下单 sor = submitOrderRequest( self, secretStr, from_station, to_station, train_no, self.set_type, self.passengerTicketStrList, self.oldPassengerStr, train_date, TickerConfig.TICKET_PEOPLES) sor.sendSubmitOrderRequest() elif secretList: # 候补订单 c = chechFace(self, secretList) c.sendChechFace() else: random_time = round( random.uniform(sleep_time_s, sleep_time_t), 2) nateMsg = ' 无候补机会' if TickerConfig.ORDER_TYPE == 2 else "" print( f"正在第{num}次查询 随机停留时长:{random_time} 乘车日期: {','.join(TickerConfig.STATION_DATES)} 车次:{'.'.join(TickerConfig.STATION_TRAINS)} 下单无票{nateMsg} 耗时:{(datetime.datetime.now() - now).microseconds / 1000}ms" ) time.sleep(random_time) except PassengerUserException as e: print(e) break except ticketConfigException as e: print(e) break except ticketIsExitsException as e: print(e) break except ticketNumOutException as e: print(e) break except UserPasswordException as e: print(e) break except ValueError as e: if e == "No JSON object could be decoded": print(u"12306接口无响应,正在重试") else: print(e) except KeyError as e: print(e) except TypeError as e: print(u"12306接口无响应,正在重试 {0}".format(e)) except socket.error as e: print(e)
class select: """ 快速提交车票通道 """ def __init__(self): self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, \ self.ticke_peoples, self.station_trains, self.ticket_black_list_time, \ self.order_type, self.is_by_time, self.train_types, self.departure_time, \ self.arrival_time, self.take_time = self.get_ticket_info() self.is_auto_code = _get_yaml()["is_auto_code"] self.auto_code_type = _get_yaml()["auto_code_type"] self.is_cdn = _get_yaml()["is_cdn"] self.httpClint = HTTPClient() self.urls = urlConf.urls self.login = GoLogin(self, self.is_auto_code, self.auto_code_type) self.cdn_list = [] self.passengerTicketStrList = "" self.oldPassengerStr = "" self.set_type = "" def get_ticket_info(self): """ 获取配置信息 :return: """ ticket_info_config = _get_yaml() from_station = ticket_info_config["set"]["from_station"].encode("utf8") to_station = ticket_info_config["set"]["to_station"].encode("utf8") station_dates = ticket_info_config["set"]["station_dates"] set_names = ticket_info_config["set"]["set_type"] set_type = [ seat_conf[x.encode("utf8")] for x in ticket_info_config["set"]["set_type"] ] is_more_ticket = ticket_info_config["set"]["is_more_ticket"] ticke_peoples = ticket_info_config["set"]["ticke_peoples"] station_trains = ticket_info_config["set"]["station_trains"] ticket_black_list_time = ticket_info_config["ticket_black_list_time"] order_type = ticket_info_config["order_type"] # by time is_by_time = ticket_info_config["set"]["is_by_time"] train_types = ticket_info_config["set"]["train_types"] departure_time = time_to_minutes( ticket_info_config["set"]["departure_time"]) arrival_time = time_to_minutes( ticket_info_config["set"]["arrival_time"]) take_time = time_to_minutes(ticket_info_config["set"]["take_time"]) print u"*" * 20 print u"12306刷票小助手,最后更新于2018.9.21,请勿作为商业用途,交流群号:286271084" if is_by_time: method_notie="购票方式:根据时间区间购票\n可接受最早出发时间:{0}\n可接受最晚抵达时间:{1}\n可接受最长旅途时间:{2}\n可接受列车类型:{3}\n"\ .format(minutes_to_time(departure_time),minutes_to_time(arrival_time),minutes_to_time(take_time)," , ".join(train_types)) else: method_notie = "购票方式:根据候选车次购买\n候选购买车次:{0}".format( ",".join(station_trains)) print u"当前配置:\n出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票优先提交:{4}\n乘车人:{5}\n" \ u"刷新间隔:随机(1-3S)\n{6}\n僵尸票关小黑屋时长:{7}\n 下单接口:{8}\n".format \ ( from_station, to_station, station_dates, ",".join(set_names), is_more_ticket, ",".join(ticke_peoples), method_notie, ticket_black_list_time, order_type, ) print u"*" * 20 return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, station_trains, ticket_black_list_time, order_type, is_by_time, train_types, departure_time, arrival_time, take_time def station_table(self, from_station, to_station): """ 读取车站信息 :param station: :return: """ result = open('station_name.txt') info = result.read().split('=')[1].strip("'").split('@') del info[0] station_name = {} for i in range(0, len(info)): n_info = info[i].split('|') station_name[n_info[1]] = n_info[2] from_station = station_name[from_station.encode("utf8")] to_station = station_name[to_station.encode("utf8")] return from_station, to_station def call_login(self, auth=False): """ 登录回调方法 :return: """ if auth: return self.login.auth() else: self.login.go_login() def set_cdn(self): """ 设置cdn :return: """ if self.is_cdn == 1: while True: if self.cdn_list: self.httpClint.cdn = self.cdn_list[random.randint( 0, len(self.cdn_list) - 1)] def cdn_req(self, cdn): for i in range(len(cdn) - 1): http = HTTPClient() urls = self.urls["loginInit"] http.cdn = cdn[i].replace("\n", "") start_time = datetime.datetime.now() rep = http.send(urls) if rep and "message" not in rep and (datetime.datetime.now( ) - start_time).microseconds / 1000 < 500: print("加入cdn {0}".format(cdn[i].replace("\n", ""))) self.cdn_list.append(cdn[i].replace("\n", "")) print(u"所有cdn解析完成...") def cdn_certification(self): """ cdn 认证 :return: """ if self.is_cdn == 1: CDN = CDNProxy() all_cdn = CDN.all_cdn() if all_cdn: print(u"由于12306网站策略调整,cdn功能暂时关闭。") # print(u"开启cdn查询") # print(u"本次待筛选cdn总数为{}, 筛选时间大约为5-10min".format(len(all_cdn))) # t = threading.Thread(target=self.cdn_req, args=(all_cdn,)) # t2 = threading.Thread(target=self.set_cdn, args=()) # t.start() # t2.start() else: raise ticketConfigException(u"cdn列表为空,请先加载cdn") def main(self): self.cdn_certification() l = liftTicketInit(self) l.reqLiftTicketInit() self.call_login() check_user = checkUser(self) check_user.sendCheckUser() from_station, to_station = self.station_table(self.from_station, self.to_station) num = 0 while 1: try: num += 1 check_user.sendCheckUser() if time.strftime('%H:%M:%S', time.localtime( time.time())) > "23:00:00" or time.strftime( '%H:%M:%S', time.localtime( time.time())) < "06:00:00": print(ticket.REST_TIME) while 1: time.sleep(1) if "06:00:00" < time.strftime( '%H:%M:%S', time.localtime( time.time())) < "23:00:00": print(ticket.REST_TIME_PAST) self.call_login() break start_time = datetime.datetime.now() q = query( session=self, from_station=from_station, to_station=to_station, from_station_h=self.from_station, to_station_h=self.to_station, _station_seat=self._station_seat, station_trains=self.station_trains, station_dates=self.station_dates, ticke_peoples_num=len(self.ticke_peoples), ) queryResult = q.sendQuery() # 查询接口 if queryResult.get("status", False): train_no = queryResult.get("train_no", "") train_date = queryResult.get("train_date", "") stationTrainCode = queryResult.get("stationTrainCode", "") secretStr = queryResult.get("secretStr", "") seat = queryResult.get("seat", "") leftTicket = queryResult.get("leftTicket", "") query_from_station_name = queryResult.get( "query_from_station_name", "") query_to_station_name = queryResult.get( "query_to_station_name", "") is_more_ticket_num = queryResult.get( "is_more_ticket_num", len(self.ticke_peoples)) if wrapcache.get(train_no): print(ticket.QUEUE_WARNING_MSG.format(train_no)) else: # 获取联系人 s = getPassengerDTOs( session=self, ticket_peoples=self.ticke_peoples, set_type=seat_conf_2[seat], is_more_ticket_num=is_more_ticket_num) getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr( ) if getPassengerDTOsResult.get("status", False): self.passengerTicketStrList = getPassengerDTOsResult.get( "passengerTicketStrList", "") self.oldPassengerStr = getPassengerDTOsResult.get( "oldPassengerStr", "") self.set_type = getPassengerDTOsResult.get( "set_type", "") # 提交订单 if self.order_type == 1: # 快读下单 a = autoSubmitOrderRequest( session=self, secretStr=secretStr, train_date=train_date, passengerTicketStr=self.passengerTicketStrList, oldPassengerStr=self.oldPassengerStr, train_no=train_no, stationTrainCode=stationTrainCode, leftTicket=leftTicket, set_type=self.set_type, query_from_station_name=query_from_station_name, query_to_station_name=query_to_station_name, ) a.sendAutoSubmitOrderRequest() elif self.order_type == 2: # 普通下单 sor = submitOrderRequest( self, secretStr, from_station, to_station, train_no, self.set_type, self.passengerTicketStrList, self.oldPassengerStr, train_date, self.ticke_peoples) sor.sendSubmitOrderRequest() else: random_time = round(random.uniform(1, 3), 2) time.sleep(random_time) print u"正在第{0}次查询 随机停留时长:{6} 乘车日期: {1} 车次:{2} 查询无票 cdn轮询IP:{4}当前cdn总数:{5} 总耗时:{3}ms".format( num, ",".join(self.station_dates), ",".join(self.station_trains), (datetime.datetime.now() - start_time).microseconds / 1000, wrapcache.get("cdn"), len(self.cdn_list), random_time) except PassengerUserException as e: print e.message break except ticketConfigException as e: print e.message break except ticketIsExitsException as e: print e.message break except ticketNumOutException as e: print e.message break except UserPasswordException as e: print e.message break except ValueError as e: if e.message == "No JSON object could be decoded": print(u"12306接口无响应,正在重试") else: print(e.message) except KeyError as e: print(e.message) except TypeError as e: print(u"12306接口无响应,正在重试 {0}".format(e.message)) except socket.error as e: print(e.message)
class QiangPiao(object): """ 快速提交车票通道 """ def __init__(self, qiangpiao_info=None): if qiangpiao_info is None: self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, \ self.ticke_peoples, self.station_trains, self.ticket_black_list_time, \ self.order_type = self.get_ticket_info() else: pass self.is_auto_code = _get_yaml()["is_auto_code"] self.auto_code_type = _get_yaml()["auto_code_type"] self.is_cdn = _get_yaml()["is_cdn"] self.httpClint = HTTPClient() self.urls = urlConf.urls self.login = GoLogin(self, self.is_auto_code, self.auto_code_type) self.cdn_list = [] self.passengerTicketStrList = "" self.oldPassengerStr = "" self.station_name_map = self.station_table( '../config/station_name.format') def get_ticket_info(self): """ 获取配置信息 :return: """ ticket_info_config = _get_yaml() from_station = ticket_info_config["set"]["from_station"].encode("utf8") to_station = ticket_info_config["set"]["to_station"].encode("utf8") station_dates = ticket_info_config["set"]["station_dates"] set_type = ticket_info_config["set"]["set_type"] is_more_ticket = ticket_info_config["set"]["is_more_ticket"] ticke_peoples = ticket_info_config["set"]["ticke_peoples"] station_trains = ticket_info_config["set"]["station_trains"] ticket_black_list_time = ticket_info_config["ticket_black_list_time"] order_type = ticket_info_config["order_type"] print u"*" * 20 print u"12306刷票小助手,最后更新于2018.12.12,请勿作为商业用途!" print u"*" * 20 return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, station_trains, ticket_black_list_time, order_type def station_table(self, files): """ 读取车站信息 :param station: :return: """ # result = open(files) station_name = {} with open(files) as fp: for line in fp: if line.startswith('#') or len(line.strip()) < 2: continue line_arr = line.strip().decode('utf8').split('\t') station_name[line_arr[1]] = line_arr[2] # info = result.read().split('=')[1].strip("'").split('@') # del info[0] # station_name = {} # for i in range(0, len(info)): # n_info = info[i].split('|') # station_name[n_info[1]] = n_info[2] # from_station = station_name[from_station.encode("utf8")] # to_station = station_name[to_station.encode("utf8")] return station_name def call_login(self, auth=False): """ 登录回调方法 :return: """ if auth: return self.login.auth() else: self.login.go_login() def set_cdn(self): """ 设置cdn :return: """ if self.is_cdn == 1: while True: if self.cdn_list: self.httpClint.cdn = self.cdn_list[random.randint( 0, len(self.cdn_list) - 1)] def cdn_req(self, cdn): for i in range(len(cdn) - 1): http = HTTPClient() urls = self.urls["loginInit"] start_time = datetime.datetime.now() http.cdn = cdn[i].replace("\n", "") rep = http.send(urls) if rep and "message" not in rep and (datetime.datetime.now( ) - start_time).microseconds / 1000 < 500: print("加入cdn {0}".format(cdn[i].replace("\n", ""))) self.cdn_list.append(cdn[i].replace("\n", "")) print(u"所有cdn解析完成...") def cdn_certification(self): """ cdn 认证 :return: """ if self.is_cdn == 1: CDN = CDNProxy() all_cdn = CDN.all_cdn() if all_cdn: print(u"开启cdn查询") print(u"本次待筛选cdn总数为{}".format(len(all_cdn))) t = threading.Thread(target=self.cdn_req, args=(all_cdn, )) t2 = threading.Thread(target=self.set_cdn, args=()) t.start() t2.start() else: raise ticketConfigException(u"cdn列表为空,请先加载cdn") else: pass def query_train_ticket(self, from_station, to_station, station_dates, train_no=None): """查询车次余票 """ self.cdn_certification() l = liftTicketInit(session=self) l.reqLiftTicketInit() checkUser(self).sendCheckUser() num = 0 while num < 5: try: num += 1 # checkUser(self).sendCheckUser() q = QueryTecket(session=self, station_dates=station_dates) # queryResult = q.sendQuery(from_station, to_station, train_no) queryResult = q.get_trains_status(from_station, to_station, train_no, True) # if len(queryResult) == 1: # continue col_name = [ u'车次', u'发站', u'到站', u'发车', u'到达', u'耗时', u'出发日期', u'无座', u'硬座', u'硬卧', u'软卧', u'高软', u'二等', u'一等', u'商务', u'动卧' ] print json.dumps(col_name, ensure_ascii=False) for ret in queryResult: for en in ret: print json.dumps(en, ensure_ascii=False) return queryResult except Exception as ex: logging.error(traceback.format_exc()) def init_login(self): self.cdn_certification() l = liftTicketInit(session=self) l.reqLiftTicketInit() self.call_login() checkUser(self).sendCheckUser() def go_qiangpiao(self, tricket_info, log_info=[], num=1): try: from_station_h = tricket_info['from_station'] to_station_h = tricket_info['to_station'] from_station, to_station = self.station_name_map[ from_station_h], self.station_name_map[to_station_h] except: return log_info.append(u'站点输入有误,请检查!') try: checkUser(self).sendCheckUser() now_time = time.strftime('%H:%M:%S', time.localtime(time.time())) while now_time > "23:00:00" or now_time < "06:00:00": time.sleep(5) now_time = time.strftime('%H:%M:%S', time.localtime(time.time())) if "06:00:00" < now_time < "23:00:00": log_info.append(ticket.REST_TIME_PAST) print(ticket.REST_TIME_PAST) self.call_login() break start_time = datetime.datetime.now() q = query(session=self, from_station=from_station, to_station=to_station, from_station_h=from_station_h, to_station_h=to_station_h, _station_seat=tricket_info['seat'], station_trains=tricket_info['trains'], station_dates=tricket_info['date']) queryResult = q.sendQuery(log_info) # 查询接口 # tmp = queryResult.get("status", False) # assert tmp == False if queryResult.get("status", False): train_no = queryResult.get("train_no", "") train_date = queryResult.get("train_date", "") stationTrainCode = queryResult.get("stationTrainCode", "") set_type = queryResult.get("set_type", "") secretStr = queryResult.get("secretStr", "") leftTicket = queryResult.get("leftTicket", "") query_from_station_name = queryResult.get( "query_from_station_name", "") query_to_station_name = queryResult.get( "query_to_station_name", "") if wrapcache.get(train_no): print(ticket.QUEUE_WARNING_MSG.format(train_no)) log_info.append(ticket.QUEUE_WARNING_MSG.format(train_no)) else: # 获取联系人 if not self.passengerTicketStrList and not self.oldPassengerStr: s = getPassengerDTOs( session=self, ticket_peoples=tricket_info['person_name'], set_type=set_type) # getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr( ) if getPassengerDTOsResult.get("status", False): self.passengerTicketStrList = getPassengerDTOsResult.get( "passengerTicketStrList", "") self.oldPassengerStr = getPassengerDTOsResult.get( "oldPassengerStr", "") set_type = getPassengerDTOsResult.get( "set_type", "") self.order_type = 2 # 提交订单 if self.order_type == 1: # 快读下单 a = autoSubmitOrderRequest( session=self, secretStr=secretStr, train_date=train_date, passengerTicketStr=self.passengerTicketStrList, oldPassengerStr=self.oldPassengerStr, train_no=train_no, stationTrainCode=stationTrainCode, leftTicket=leftTicket, set_type=set_type, query_from_station_name=query_from_station_name, query_to_station_name=query_to_station_name, ) a.sendAutoSubmitOrderRequest(log_info) elif self.order_type == 2: # 普通下单 sor = submitOrderRequest( self, secretStr, from_station, to_station, train_no, set_type, self.passengerTicketStrList, self.oldPassengerStr, train_date, self.ticke_peoples) sor.sendSubmitOrderRequest(log_info) else: random_time = round(random.uniform(1, 4), 2) time.sleep(random_time) mess = u"正在第{0}次查询 随机停留时长:{6}s 乘车日期: {1} 车次:{2} 查询无票 cdn轮询IP:{4}当前cdn总数:{5} 总耗时:{3}ms".format( num, ",".join(tricket_info['date']), tricket_info['trains'], (datetime.datetime.now() - start_time).microseconds / 1000, self.httpClint.cdn, len(self.cdn_list), random_time) print mess log_info.append(mess) except PassengerUserException as e: print e.message log_info.append(e.message) # break except ticketConfigException as e: print e.message log_info.append(e.message) # break except ticketIsExitsException as e: print e.message log_info.append(e.message) # break except ticketNumOutException as e: print e.message log_info.append(e.message) # break except UserPasswordException as e: print e.message log_info.append(e.message) # break except ValueError as e: if e.message == "No JSON object could be decoded": print(u"12306接口无响应,正在重试") log_info.append(u"12306接口无响应,正在重试") else: print(e.message) log_info.append(e.message) except KeyError as e: print(e.message) log_info.append(e.message) except TypeError as e: print(u"12306接口无响应,正在重试 {0}".format(e.message)) log_info.append(u"12306接口无响应,正在重试 {0}".format(e.message)) except socket.error as e: print e log_info.append(e.message) def main(self): from_station, to_station = self.station_table(self.from_station, self.to_station) num = 0 while 1: try: num += 1 checkUser(self).sendCheckUser() if time.strftime('%H:%M:%S', time.localtime( time.time())) > "23:00:00" or time.strftime( '%H:%M:%S', time.localtime( time.time())) < "06:00:00": print(ticket.REST_TIME) # while 1: # time.sleep(1) # if "06:00:00" < time.strftime('%H:%M:%S', time.localtime(time.time())) < "23:00:00": # print(ticket.REST_TIME_PAST) # self.call_login() # break start_time = datetime.datetime.now() q = query( session=self, from_station=from_station, to_station=to_station, from_station_h=self.from_station, to_station_h=self.to_station, _station_seat=self._station_seat, station_trains=self.station_trains, station_dates=self.station_dates, ) queryResult = q.sendQuery() # 查询接口 # tmp = queryResult.get("status", False) # assert tmp == False if queryResult.get("status", False): train_no = queryResult.get("train_no", "") train_date = queryResult.get("train_date", "") stationTrainCode = queryResult.get("stationTrainCode", "") set_type = queryResult.get("set_type", "") secretStr = queryResult.get("secretStr", "") leftTicket = queryResult.get("leftTicket", "") query_from_station_name = queryResult.get( "query_from_station_name", "") query_to_station_name = queryResult.get( "query_to_station_name", "") if wrapcache.get(train_no): print(ticket.QUEUE_WARNING_MSG.format(train_no)) else: # 获取联系人 if not self.passengerTicketStrList and not self.oldPassengerStr: s = getPassengerDTOs( session=self, ticket_peoples=self.ticke_peoples, set_type=set_type) # getPassengerDTOsResult = s.getPassengerTicketStrListAndOldPassengerStr( ) if getPassengerDTOsResult.get("status", False): self.passengerTicketStrList = getPassengerDTOsResult.get( "passengerTicketStrList", "") self.oldPassengerStr = getPassengerDTOsResult.get( "oldPassengerStr", "") set_type = getPassengerDTOsResult.get( "set_type", "") # 提交订单 if self.order_type == 1: # 快读下单 a = autoSubmitOrderRequest( session=self, secretStr=secretStr, train_date=train_date, passengerTicketStr=self.passengerTicketStrList, oldPassengerStr=self.oldPassengerStr, train_no=train_no, stationTrainCode=stationTrainCode, leftTicket=leftTicket, set_type=set_type, query_from_station_name=query_from_station_name, query_to_station_name=query_to_station_name, ) a.sendAutoSubmitOrderRequest() elif self.order_type == 2: # 普通下单 sor = submitOrderRequest( self, secretStr, from_station, to_station, train_no, set_type, self.passengerTicketStrList, self.oldPassengerStr, train_date, self.ticke_peoples) sor.sendSubmitOrderRequest() else: random_time = round(random.uniform(1, 4), 2) time.sleep(random_time) print u"正在第{0}次查询 随机停留时长:{6}s 乘车日期: {1} 车次:{2} 查询无票 cdn轮询IP:{4}当前cdn总数:{5} 总耗时:{3}ms".format( num, ",".join(self.station_dates), ",".join(self.station_trains), (datetime.datetime.now() - start_time).microseconds / 1000, self.httpClint.cdn, len(self.cdn_list), random_time) except PassengerUserException as e: print e.message break except ticketConfigException as e: print e.message break except ticketIsExitsException as e: print e.message break except ticketNumOutException as e: print e.message break except UserPasswordException as e: print e.message break except ValueError as e: if e.message == "No JSON object could be decoded": print(u"12306接口无响应,正在重试") else: print(e.message) except KeyError as e: print(e.message) except TypeError as e: print(u"12306接口无响应,正在重试 {0}".format(e.message)) except socket.error as e: print(e.message)
class select: def __init__(self): self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, self.ticke_peoples, self.select_refresh_interval, self.station_trains, self.ticket_black_list_time = self.get_ticket_info() self.is_aotu_code = _get_yaml()["is_aotu_code"] self.aotu_code_type = _get_yaml()["aotu_code_type"] self.is_cdn = _get_yaml()["is_cdn"] self.order_request_params = {} # 订单提交时的参数 self.ticketInfoForPassengerForm = {} # 初始化当前页面参数 self.current_seats = {} # 席别信息 self.token = "" self.set_type = "" self.user_info = "" self.secretStr = "" self.ticket_black_list = dict() self.is_check_user = dict() self.httpClint = HTTPClient() self.confUrl = urlConf.urls self.login = GoLogin(self.httpClint, self.confUrl, self.is_aotu_code, self.aotu_code_type) self.is_download_img = False self.randCode = "" self.cdn_list = [] self.buy_ticket_time = "" def get_ticket_info(self): """ 获取配置信息 :return: """ ticket_info_config = _get_yaml() from_station = ticket_info_config["set"]["from_station"].encode("utf8") to_station = ticket_info_config["set"]["to_station"].encode("utf8") station_dates = ticket_info_config["set"]["station_dates"] set_type = ticket_info_config["set"]["set_type"] is_more_ticket = ticket_info_config["set"]["is_more_ticket"] ticke_peoples = ticket_info_config["set"]["ticke_peoples"] select_refresh_interval = ticket_info_config["select_refresh_interval"] station_trains = ticket_info_config["set"]["station_trains"] ticket_black_list_time = ticket_info_config["ticket_black_list_time"] print u"*"*20 print u"12306刷票小助手,最后更新于2018.2.28,请勿作为商业用途,交流群号:286271084" print u"如果有好的margin,请联系作者,表示非常感激\n" print u"当前配置:出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票自动提交:{4}\n乘车人:{5}\n刷新间隔:{6}s(如果想随机刷新,请自行修改)\n候选购买车次:{7}\n僵尸票关小黑屋时长:{8}\n".format\ ( from_station, to_station, station_dates, ",".join(set_type), is_more_ticket, ",".join(ticke_peoples), select_refresh_interval, ",".join(station_trains), ticket_black_list_time, ) print u"*"*20 return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, select_refresh_interval, station_trains, ticket_black_list_time def get_order_request_params(self): return self.order_request_params def get_ticketInfoForPassengerForm(self): return self.ticketInfoForPassengerForm def get_current_seats(self): return self.current_seats def get_token(self): return self.token def get_set_type(self): return self.set_type def conversion_int(self, str): return int(str) def station_seat(self, index): """ 获取车票对应坐席 :param seat_type: :return: """ seat = {'商务座': 32, '一等座': 31, '二等座': 30, '特等座': 25, '软卧': 23, '硬卧': 28, '硬座': 29, '无座': 26, } return seat[index] def station_table(self, from_station, to_station): """ 读取车站信息 :param station: :return: """ result = open('station_name.txt') info = result.read().split('=')[1].strip("'").split('@') del info[0] station_name = {} for i in range(0, len(info)): n_info = info[i].split('|') station_name[n_info[1]] = n_info[2] from_station = station_name[from_station.encode("utf8")] to_station = station_name[to_station.encode("utf8")] return from_station, to_station def time(self): """ 获取日期 :return: """ today = datetime.date.today() # tomorrow = today+datetime.timedelta(1) return today.strftime('%Y-%m-%d') def callReadImg(self, code_url): """ 下载验证码 :param code_url: 验证码url :return: """ self.login.readImg(code_url=code_url) self.is_aotu_code = True def callRandCode(self): """ 识别验证码 :return: """ while True: if self.is_aotu_code: self.randCode = self.login.getRandCode() self.is_aotu_code = False def getRepeatSubmitToken(self): """ 获取提交车票请求token :return: token """ initdc_url = self.confUrl["initdc_url"] initdc_result = self.httpClint.send(initdc_url,) token_name = re.compile(r"var globalRepeatSubmitToken = '(\S+)'") ticketInfoForPassengerForm_name = re.compile(r'var ticketInfoForPassengerForm=(\{.+\})?') order_request_params_name = re.compile(r'var orderRequestDTO=(\{.+\})?') self.token = re.search(token_name, initdc_result).group(1) re_tfpf = re.findall(ticketInfoForPassengerForm_name, initdc_result) re_orp = re.findall(order_request_params_name, initdc_result) if re_tfpf: self.ticketInfoForPassengerForm = json.loads(re_tfpf[0].replace("'", '"')) else: pass if re_orp: self.order_request_params = json.loads(re_orp[0].replace("'", '"')) else: pass def GetJS(self): getJSUrl = self.confUrl["GetJS"] self.httpClint.send(getJSUrl) odxmfwgUrl = self.confUrl["odxmfwg"] self.httpClint.send(odxmfwgUrl) def getPassengerDTOs(self): """ 获取乘客信息 :return: """ get_passengerDTOs = self.confUrl["get_passengerDTOs"] get_data = { '_json_att': None, 'REPEAT_SUBMIT_TOKEN': self.token } jsonData = self.httpClint.send(get_passengerDTOs, get_data) if 'data' in jsonData and jsonData['data'] and 'normal_passengers' in jsonData['data'] and jsonData['data'][ 'normal_passengers']: normal_passengers = jsonData['data']['normal_passengers'] _normal_passenger = [normal_passengers[i] for i in range(len(normal_passengers))if normal_passengers[i]["passenger_name"] in self.ticke_peoples] return _normal_passenger if _normal_passenger else [normal_passengers[0]] # 如果配置乘车人没有在账号,则默认返回第一个用户 else: if 'data' in jsonData and 'exMsg' in jsonData['data'] and jsonData['data']['exMsg']: print(jsonData['data']['exMsg']) elif 'messages' in jsonData and jsonData['messages']: print(jsonData['messages'][0]) else: print(u"未查找到常用联系人") raise PassengerUserException(u"未查找到常用联系人,请先添加联系人在试试") def submitOrderRequestFunc(self, from_station, to_station, station_date=None): self.confUrl["select_url"]["req_url"] = self.confUrl["select_url"]["req_url"].format( station_date, from_station, to_station) station_ticket = self.httpClint.send(self.confUrl["select_url"]) return json.loads(station_ticket) def submitOrderRequestImplement(self, from_station, to_station,): """ 提交车次信息 车次对应字典 {32: '商务座 ', 31: '一等座 ', 30: '二等座 ', 25: '特等座 ', 23: '软卧 ', 28: '硬卧 ', 29: '硬座 ', 26: '无座 ' } 参照station_seat()方法 :return: """ station_tickets = [self.submitOrderRequestFunc(from_station, to_station, station_date) for station_date in self.station_dates] for station_ticket in station_tickets: value = station_ticket['data'] if not value: print (u'{0}-{1} 车次坐席查询为空...'.format(self.from_station, self.to_station)) else: if value['result']: for i in value['result']: ticket_info = i.split('|') if ticket_info[11] == "Y" and ticket_info[1].encode("utf8") == "预订": # 筛选未在开始时间内的车次 for j in range(len(self._station_seat)): is_ticket_pass = ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))] # print self._station_seat[j] if is_ticket_pass != '' and is_ticket_pass != '无' and ticket_info[3] in self.station_trains and is_ticket_pass != '*': # 过滤有效目标车次 # tiket_values = [k for k in value['map'].values()] self.secretStr = ticket_info[0] train_no = ticket_info[3] print (u'车次: ' + train_no + ' 始发车站: ' + self.from_station + ' 终点站: ' + self.to_station + ' ' + self._station_seat[j].encode("utf8") + ':' + ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))]) if self.ticket_black_list.has_key(train_no) and (datetime.datetime.now() - self.ticket_black_list[train_no]).seconds/60 < int(self.ticket_black_list_time): print(u"该车次{} 正在被关小黑屋,跳过此车次".format(train_no)) break else: print (u'正在尝试提交订票...') self.buy_ticket_time = datetime.datetime.now() # self.submitOrderRequestFunc(from_station, to_station, self.time()) self.submit_station() self.getPassengerTicketStr(self._station_seat[j].encode("utf8")) self.getRepeatSubmitToken() if not self.user_info: # 修改每次都调用用户接口导致用户接口不能用 self.user_info = self.getPassengerDTOs() codeImgByOrder = self.confUrl["codeImgByOrder"] self.login.readImg(codeImgByOrder) if self.checkOrderInfo(train_no, self._station_seat[j].encode("utf8")): break else: pass else: pass # time.sleep(self.expect_refresh_interval) else: print u"车次配置信息有误,或者返回数据异常,请检查 {}".format(station_ticket) def check_user(self): """ 检查用户是否达到订票条件 :return: """ check_user_url = self.confUrl["check_user_url"] data = {"_json_att": ""} check_user = self.httpClint.send(check_user_url, data) check_user_flag = check_user['data']['flag'] if check_user_flag is True: self.is_check_user["user_time"] = datetime.datetime.now() else: if check_user['messages']: print (u'用户检查失败:%s,可能未登录,可能session已经失效' % check_user['messages'][0]) print (u'正在尝试重新登录') self.call_login() self.is_check_user["user_time"] = datetime.datetime.now() else: print (u'用户检查失败: %s,可能未登录,可能session已经失效' % check_user) print (u'正在尝试重新登录') self.call_login() self.is_check_user["user_time"] = datetime.datetime.now() def submit_station(self): """ 提交车次 预定的请求参数,注意参数顺序 注意这里为了防止secretStr被urllib.parse过度编码,在这里进行一次解码 否则调用HttpTester类的post方法将会将secretStr编码成为无效码,造成提交预定请求失败 :param self: :param secretStr: 提交车次加密 :return: """ submit_station_url = self.confUrl["submit_station_url"] data = [('secretStr', urllib.unquote(self.secretStr)), # 字符串加密 ('train_date', self.station_dates[0]), # 出发时间 ('back_train_date', self.time()), # 返程时间 ('tour_flag', 'dc'), # 旅途类型 ('purpose_codes', 'ADULT'), # 成人票还是学生票 ('query_from_station_name', self.from_station), # 起始车站 ('query_to_station_name', self.to_station), # 终点车站 ] submitResult = self.httpClint.send(submit_station_url, data) if 'data' in submitResult and submitResult['data']: if submitResult['data'] == 'N': print (u'出票成功') else: print (u'出票失败') elif 'messages' in submitResult and submitResult['messages']: raise ticketIsExitsException(submitResult['messages'][0]) def getPassengerTicketStr(self, set_type): """ 获取getPassengerTicketStr 提交对应的代号码 :param str: 坐席 :return: """ passengerTicketStr = { '一等座': 'M', '特等座': 'P', '二等座': 'O', '商务座': 9, '硬座': 1, '无座': 1, '软卧': 4, '硬卧': 3, } self.set_type = str(passengerTicketStr[set_type.replace(' ', '')]) def ticket_type(self): """订单票的类型,目前只考虑成人票,此方法暂时搁置,做备案""" ticket_type = {'adult': "1", 'child': "2", 'student': "3", 'disability': "4"} return ticket_type def getPassengerTicketStrListAndOldPassengerStr(self): """ 获取提交车次人内容格式 passengerTicketStr O,0,1,文贤平,1,43052419950223XXXX,15618715583,N_O,0,1,梁敏,1,43052719920118XXXX,,N oldPassengerStr 文贤平,1,43052719920118XXXX,1_梁敏,1,43052719920118XXXX,1_ :return: """ passengerTicketStrList = [] oldPassengerStr = [] if not self.user_info: raise PassengerUserException(u"联系人不在列表中,请查证后添加") if len(self.user_info) is 1: passengerTicketStrList.append( '0,' + self.user_info[0]['passenger_type'] + "," + self.user_info[0][ "passenger_name"] + "," + self.user_info[0]['passenger_id_type_code'] + "," + self.user_info[0]['passenger_id_no'] + "," + self.user_info[0]['mobile_no'] + ',N') oldPassengerStr.append( self.user_info[0]['passenger_name'] + "," + self.user_info[0]['passenger_id_type_code'] + "," + self.user_info[0]['passenger_id_no'] + "," + self.user_info[0]['passenger_type'] + '_') else: for i in range(len(self.user_info)): passengerTicketStrList.append( '0,' + self.user_info[i]['passenger_type'] + "," + self.user_info[i][ "passenger_name"] + "," + self.user_info[i]['passenger_id_type_code'] + "," + self.user_info[i][ 'passenger_id_no'] + "," + self.user_info[i]['mobile_no'] + ',N_' + self.set_type) oldPassengerStr.append( self.user_info[i]['passenger_name'] + "," + self.user_info[i]['passenger_id_type_code'] + "," + self.user_info[i]['passenger_id_no'] + "," + self.user_info[i]['passenger_type'] + '_') return passengerTicketStrList, oldPassengerStr def checkOrderInfo(self, train_no, set_type): """ 检查支付订单,需要提交REPEAT_SUBMIT_TOKEN passengerTicketStr : 座位编号,0,票类型,乘客名,证件类型,证件号,手机号码,保存常用联系人(Y或N) oldPassengersStr: 乘客名,证件类型,证件号,乘客类型 :return: """ passengerTicketStrList, oldPassengerStr = self.getPassengerTicketStrListAndOldPassengerStr() checkOrderInfoUrl = self.confUrl["checkOrderInfoUrl"] data = collections.OrderedDict() data['cancel_flag'] = 2 data['bed_level_order_num'] = "000000000000000000000000000000" data['passengerTicketStr'] = self.set_type + "," + ",".join(passengerTicketStrList).rstrip("_{0}".format(self.set_type)) data['oldPassengerStr'] = "".join(oldPassengerStr) data['tour_flag'] = 'dc' data['whatsSelect'] = 1 data['REPEAT_SUBMIT_TOKEN'] = self.token checkOrderInfo = self.httpClint.send(checkOrderInfoUrl, data) if 'data' in checkOrderInfo: if "ifShowPassCode" in checkOrderInfo["data"] and checkOrderInfo["data"]["ifShowPassCode"] == "Y": is_need_code = True if self.getQueueCount(train_no, set_type, is_need_code): return True if "ifShowPassCode" in checkOrderInfo["data"] and checkOrderInfo['data']['submitStatus'] is True: print (u'车票提交通过,正在尝试排队') is_need_code = False if self.getQueueCount(train_no, set_type, is_need_code): return True else: if "errMsg" in checkOrderInfo['data'] and checkOrderInfo['data']["errMsg"]: print checkOrderInfo['data']["errMsg"] else: print checkOrderInfo elif 'messages' in checkOrderInfo and checkOrderInfo['messages']: print (checkOrderInfo['messages'][0]) def getQueueCount(self, train_no, set_type, is_need_code): """ # 模拟查询当前的列车排队人数的方法 # 返回信息组成的提示字符串 :param token: :return: """ l_time = time.localtime(time.time()) new_train_date = time.strftime("%a %b %d %Y", l_time) getQueueCountUrl = self.confUrl["getQueueCountUrl"] data = collections.OrderedDict() data['train_date'] = str(new_train_date) + " 00:00:00 GMT+0800 (中国标准时间)", data['train_no'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['train_no'], data['stationTrainCode'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['station_train_code'], data['seatType'] = self.set_type, data['fromStationTelecode'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['from_station'], data['toStationTelecode'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['to_station'], data['leftTicket'] = self.get_ticketInfoForPassengerForm()['leftTicketStr'], data['purpose_codes'] = self.get_ticketInfoForPassengerForm()['purpose_codes'], data['train_location'] = self.get_ticketInfoForPassengerForm()['train_location'], data['REPEAT_SUBMIT_TOKEN'] = self.get_token(), getQueueCountResult = self.httpClint.send(getQueueCountUrl, data) if "status" in getQueueCountResult and getQueueCountResult["status"] is True: if "countT" in getQueueCountResult["data"]: ticket = getQueueCountResult["data"]["ticket"] ticket_split = sum(map(self.conversion_int, ticket.split(","))) if ticket.find(",") != -1 else ticket countT = getQueueCountResult["data"]["countT"] if int(countT) is 0: if int(ticket_split) < len(self.user_info): print(u"当前余票数小于乘车人数,放弃订票") else: print(u"排队成功, 当前余票还剩余: {0} 张".format(ticket_split)) if self.checkQueueOrder(is_need_code): return True else: print(u"当前排队人数: {1} 当前余票还剩余:{0} 张,继续排队中".format(ticket_split, countT)) else: print(u"排队发现未知错误{0},将此列车 {1}加入小黑屋".format(getQueueCountResult, train_no)) self.ticket_black_list[train_no] = datetime.datetime.now() elif "messages" in getQueueCountResult and getQueueCountResult["messages"]: print(u"排队异常,错误信息:{0}, 将此列车 {1}加入小黑屋".format(getQueueCountResult["messages"][0], train_no)) self.ticket_black_list[train_no] = datetime.datetime.now() else: if "validateMessages" in getQueueCountResult and getQueueCountResult["validateMessages"]: print(str(getQueueCountResult["validateMessages"])) self.ticket_black_list[train_no] = datetime.datetime.now() else: print(u"未知错误 {0}".format("".join(getQueueCountResult))) def checkRandCodeAnsyn(self, randCode): """ 识别验证码 :return: 识别结果 """ checkRandCodeAnsyn = self.confUrl["checkRandCodeAnsyn"] randData = { "randCode": randCode, "rand": "randp", "_json_att": None, "REPEAT_SUBMIT_TOKEN": self.get_token() } fresult = self.httpClint.send(checkRandCodeAnsyn, randData) # 校验验证码是否正确 return fresult['data']['msg'] def checkQueueOrder(self, is_node_code=False): """ 模拟提交订单是确认按钮,参数获取方法还是get_ticketInfoForPassengerForm 中获取 :return: """ passengerTicketStrList, oldPassengerStr = self.getPassengerTicketStrListAndOldPassengerStr() checkQueueOrderUrl = self.confUrl["checkQueueOrderUrl"] data = { "passengerTicketStr": self.set_type + "," + ",".join(passengerTicketStrList).rstrip("_{0}".format(self.set_type)), "oldPassengerStr": "".join(oldPassengerStr), "purpose_codes": self.get_ticketInfoForPassengerForm()["purpose_codes"], "key_check_isChange": self.get_ticketInfoForPassengerForm()["key_check_isChange"], "leftTicketStr": self.get_ticketInfoForPassengerForm()["leftTicketStr"], "train_location": self.get_ticketInfoForPassengerForm()["train_location"], "seatDetailType": "000", # 开始需要选择座位,但是目前12306不支持自动选择作为,那这个参数为默认 "roomType": "00", # 好像是根据一个id来判断选中的,两种 第一种是00,第二种是10,但是我在12306的页面没找到该id,目前写死是00,不知道会出什么错 "dwAll": "N", "whatsSelect": 1, "_json_at": "", "randCode": "", "choose_seats": "", "REPEAT_SUBMIT_TOKEN": self.get_token(), } try: if is_node_code: print(u"正在使用自动识别验证码功能") for i in range(3): randCode = self.login.getRandCode() checkcode = self.checkRandCodeAnsyn(randCode) if checkcode == 'TRUE': print(u"验证码通过,正在提交订单") data['randCode'] = randCode break else: print (u"验证码有误, {0}次尝试重试".format(i+1)) print(u"验证码超过限定次数3次,放弃此次订票机会!") else: print(u"不需要验证码") buy_end_time = (datetime.datetime.now() - self.buy_ticket_time).seconds print(u"总共花费时长{0}S".format(buy_end_time)) time.sleep(8-buy_end_time if buy_end_time<8 else 0) checkQueueOrderResult = self.httpClint.send(checkQueueOrderUrl, data) if "status" in checkQueueOrderResult and checkQueueOrderResult["status"]: c_data = checkQueueOrderResult["data"] if "data" in checkQueueOrderResult else {} if 'submitStatus' in c_data and c_data['submitStatus'] is True: print(u"提交订单成功!") self.queryOrderWaitTime() else: if 'errMsg' in c_data and c_data['errMsg']: print(u"提交订单失败,{0}".format(c_data['errMsg'])) else: print(c_data) print(u'订票失败!很抱歉,请重试提交预订功能!') elif "messages" in checkQueueOrderResult and checkQueueOrderResult["messages"]: print(u"提交订单失败,错误信息: " + checkQueueOrderResult["messages"]) else: print(u"提交订单中,请耐心等待:" + checkQueueOrderResult["message"]) except ValueError: print(u"接口 {} 无响应".format(checkQueueOrderUrl)) def queryOrderWaitTime(self): """ 排队获取订单等待信息,每隔3秒请求一次,最高请求次数为20次! :return: """ num = 1 while True: _random = int(round(time.time() * 1000)) num += 1 if num > 30: print(u"超出排队时间,自动放弃,正在重新刷票") order_id = self.queryMyOrderNoComplete() # 排队失败,自动取消排队订单 if order_id: self.cancelNoCompleteMyOrder(order_id) break try: data = {"random": _random, "tourFlag": "dc"} queryOrderWaitTimeUrl = self.confUrl["queryOrderWaitTimeUrl"] queryOrderWaitTimeResult = self.httpClint.send(queryOrderWaitTimeUrl, data) except ValueError: queryOrderWaitTimeResult = {} if queryOrderWaitTimeResult: if "status" in queryOrderWaitTimeResult and queryOrderWaitTimeResult["status"]: if "orderId" in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["orderId"] is not None: sendEmail(u"恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306,访问‘未完成订单’,在30分钟内完成支付!".format(queryOrderWaitTimeResult["data"]["orderId"])) raise ticketIsExitsException(u"恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306,访问‘未完成订单’,在30分钟内完成支付!".format(queryOrderWaitTimeResult["data"]["orderId"])) elif "msg" in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["msg"]: print queryOrderWaitTimeResult["data"]["msg"] break elif "waitTime"in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["waitTime"]: print(u"排队等待时间预计还剩 {0} ms".format(0-queryOrderWaitTimeResult["data"]["waitTime"])) else: print ("正在等待中") elif "messages" in queryOrderWaitTimeResult and queryOrderWaitTimeResult["messages"]: print(u"排队等待失败: " + queryOrderWaitTimeResult["messages"]) else: print(u"第{}次排队中,请耐心等待".format(num+1)) else: print(u"排队中") time.sleep(2) else: print(ticketNumOutException(u"订单提交失败!,正在重新刷票")) def queryMyOrderNoComplete(self): """ 获取订单列表信息 :return: """ self.initNoComplete() queryMyOrderNoCompleteUrl = self.confUrl["queryMyOrderNoCompleteUrl"] data = {"_json_att": ""} try: queryMyOrderNoCompleteResult = self.httpClint.send(queryMyOrderNoCompleteUrl, data) except ValueError: queryMyOrderNoCompleteResult = {} if queryMyOrderNoCompleteResult: if "data" in queryMyOrderNoCompleteResult and queryMyOrderNoCompleteResult["data"] and "orderDBList" in queryMyOrderNoCompleteResult["data"] and queryMyOrderNoCompleteResult["data"]["orderDBList"]: orderId = queryMyOrderNoCompleteResult["data"]["orderDBList"][0]["sequence_no"] return orderId elif "data" in queryMyOrderNoCompleteResult and "orderCacheDTO" in queryMyOrderNoCompleteResult["data"] and queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]: if "message" in queryMyOrderNoCompleteResult["data"]["orderCacheDTO"] and queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]: print(queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]["message"]) raise ticketNumOutException(queryMyOrderNoCompleteResult["data"]["orderCacheDTO"]["message"]["message"]) else: if "message" in queryMyOrderNoCompleteResult and queryMyOrderNoCompleteResult["message"]: print queryMyOrderNoCompleteResult["message"] return False else: return False else: print(u"接口 {} 无响应".format(queryMyOrderNoCompleteUrl)) def initNoComplete(self): """ 获取订单前需要进入订单列表页,获取订单列表页session :return: """ self.httpClint.set_cookies(acw_tc="AQAAAEnFJnekLwwAtGHjZZCr79B6dpXk", current_captcha_type="Z") initNoCompleteUrl = self.confUrl["initNoCompleteUrl"] data = {"_json_att": ""} self.httpClint.send(initNoCompleteUrl, data) def cancelNoCompleteMyOrder(self, sequence_no): """ 取消订单 :param sequence_no: 订单编号 :return: """ cancelNoCompleteMyOrderUrl = self.confUrl["cancelNoCompleteMyOrder"] cancelNoCompleteMyOrderData = { "sequence_no": sequence_no, "cancel_flag": "cancel_order", "_json_att": "" } cancelNoCompleteMyOrderResult = self.httpClint.send(cancelNoCompleteMyOrderUrl, cancelNoCompleteMyOrderData) if "data" in cancelNoCompleteMyOrderResult and "existError" in cancelNoCompleteMyOrderResult["data"] and cancelNoCompleteMyOrderResult["data"]["existError"] == "N": print(u"排队超时,已为您自动取消订单,订单编号: {0}".format(sequence_no)) time.sleep(2) return True else: print(u"排队超时,取消订单失败, 订单号{0}".format(sequence_no)) def set_cdn(self): """ 设置cdn :return: """ if self.is_cdn == 1: while True: if self.cdn_list: self.httpClint.cdn = self.cdn_list[random.randint(0, len(self.cdn_list)-1)] break else: pass def call_login(self, auth=False): """ 登录回调方法 :return: """ if auth: return self.login.auth() else: self.login.go_login() def cdn_req(self, cdn): for i in range(len(cdn)-1): http = HTTPClient() urls = self.confUrl["loginInit"] start_time = datetime.datetime.now() http.cdn = cdn[i].replace("\n", "") rep = http.send(urls) if rep and "message" not in rep and (datetime.datetime.now() - start_time).microseconds / 1000 < 200: self.cdn_list.append(cdn[i].replace("\n", "")) print(u"所有cdn解析完成...") def cdn_certification(self): """ cdn 认证 :return: """ if self.is_cdn == 1: CDN = CDNProxy() all_cdn = CDN.all_cdn() if all_cdn: print(u"开启cdn查询") print(u"本次待筛选cdn总数为{}".format(len(all_cdn))) t = threading.Thread(target=self.cdn_req, args=(all_cdn,)) t.start() else: raise ticketConfigException(u"cdn列表为空,请先加载cdn") else: pass def main(self): self.cdn_certification() self.set_cdn() self.call_login() from_station, to_station = self.station_table(self.from_station, self.to_station) self.check_user() time.sleep(0.1) num = 1 while 1: try: num += 1 if "user_time" in self.is_check_user and (datetime.datetime.now() - self.is_check_user["user_time"]).seconds/60 > 5: # 5分钟检查一次用户是否登录 self.check_user() time.sleep(self.select_refresh_interval) if time.strftime('%H:%M:%S', time.localtime(time.time())) > "23:00:00" or time.strftime('%H:%M:%S', time.localtime(time.time())) < "06:00:00": print(u"12306休息时间,本程序自动停止,明天早上6点将自动运行") while 1: time.sleep(1) if time.strftime('%H:%M:%S', time.localtime(time.time())) > "06:00:00": print(u"休息时间已过,重新开启检票功能") self.call_login() break start_time = datetime.datetime.now() self.submitOrderRequestImplement(from_station, to_station) print u"正在第{0}次查询 乘车日期: {1} 车次{2} 查询无票 cdn轮询IP {4} 当前cdn总数{5} 总耗时{3}ms".format(num, ",".join(self.station_dates), ",".join(self.station_trains), (datetime.datetime.now()-start_time).microseconds/1000, self.httpClint.cdn, len(self.cdn_list)) self.set_cdn() except PassengerUserException as e: print e.message break except ticketConfigException as e: print e.message break except ticketIsExitsException as e: print e.message break except ticketNumOutException as e: print e.message break except UserPasswordException as e: print e.message break except ValueError as e: if e.message == "No JSON object could be decoded": print(u"12306接口无响应,正在重试") else: print(e.message) except KeyError as e: print(e.message) except TypeError as e: print(u"12306接口无响应,正在重试 {0}".format(e.message)) except socket.error as e: print(e.message)