def heart_beat_mode(self): if Config.auto_code_enable: status, msg = self.online_checker() Log.v(msg) if not status: Log.e("心跳登录失败,继续重试中,建议手动检查原因再尝试重启") self.online_checker_now()
def _get_queue_count(self): form_data = { 'train_date': datetime.datetime.strptime( self.ticket_passenger_info['queryLeftTicketRequestDTO']['train_date'], '%Y%m%d').strftime( '%b %a %d %Y 00:00:00 GMT+0800') + ' (中国标准时间)', 'train_no': self.ticket_passenger_info['queryLeftTicketRequestDTO']['train_no'], 'stationTrainCode': self.train.stationTrainCode.value, 'seatType': self.seat_type.sys_code, 'fromStationTelecode': self.train.from_station_code.value, 'toStationTelecode': self.train.to_station_code.value, 'leftTicket': self.ticket_passenger_info['leftTicketStr'], 'purpose_codes': self.ticket_passenger_info['purpose_codes'], 'train_location': self.ticket_passenger_info['train_location'], '_json_att': '', 'REPEAT_SUBMIT_TOKEN': self.token } Log.v("正在获取排队信息以及余票信息中...") json_response = send_requests(LOGIN_SESSION, self.URLS['getQueueCount'], data=form_data) status, msg = submit_response_checker(json_response, ["status"], True, "获取余票信息成功") if status: self.left_tickets = json_response['data']['ticket'] Log.v("票数剩余{0}张, 排队人数为{1}人".format( self.left_tickets, json_response['data']['count'] )) else: BlackTrains.add_train(self.train) return status, msg
def _get_device_fingerprint(self): if not hasattr(Config, "device_fingerprint"): query = dict(parse.parse_qsl(DEVICE_FINGERPRINT)) else: query = dict(parse.parse_qsl(Config.device_fingerprint)) query["timestamp"] = int(time.time() * 1000) data = send_requests(LOGIN_SESSION, DEVICE_FINGERPRINT_MAPPING, params=query) Log.d(data) if not data: return False, "获取设备ID请求失败" m = re.compile(r'callbackFunction\(\'(.*)\'\)') f = m.search(data) msg = "获取设备ID失败" if not f: Log.v(msg) return False, msg result = ast.literal_eval(f.group(1)) # update cookie LOGIN_SESSION.cookies.update( { "RAIL_EXPIRATION": result.get("exp"), "RAIL_DEVICEID": result.get("dfp") } ) Log.v("获取设备ID成功") return True, "OK"
def rk_create(self, im_string, timeout=60): """ im: 图片字节 im_type: 题目类型 """ params = { 'typeid': 6113, 'timeout': timeout, } params.update(self.base_params) files = {'image': ('a.jpg', im_string)} while True: try: r = requests.post('http://api.ruokuai.com/create.json', data=params, files=files, headers=self.headers) # Log.v("使用若快进行验证码识别") data = r.json() break except requests.RequestException: Log.w("提交若快打码请求出现问题, 正在重试中...") continue Log.d(data) return data
def send_email(self, msg_type, **extra_var): """ 邮件通知 :param self: :param msg_type: email content type id. in EMAIL_MESSAGE dict. :param extra_var: format content var dict. :return: """ email_conf = Config.email_config if not Config.email_notice_enable: Log.v("未开启邮箱通知") else: data = MESSAGES[msg_type] try: sender = email_conf.from_email receiver = email_conf.notice_email_list subject = data["subject"] username = email_conf.username password = email_conf.password host = email_conf.email_gateway port = email_conf.email_port s = data["content"].format(**extra_var) msg = MIMEText(s, 'html', 'utf-8') msg['Subject'] = Header(subject, 'utf-8') msg['From'] = sender msg['To'] = ','.join(receiver) smtp = smtplib.SMTP(host) smtp.connect(host, port=port) smtp.login(username, password) smtp.send_message(msg) smtp.quit() Log.v("邮件发送成功") except Exception as e: Log.e("发送失败, 邮件配置有误, 请检查配置")
def verifyhandle_freeapi(self): Log.v("使用免费api进行验证码识别") img_base64 = base64.b64encode(self.generator_image()).decode() r = requests.post(FREE_CAPTCHA_URL, json={"base64": img_base64}) try: check = r.json()["data"]["check"] except (KeyError, JSONDecodeError): return False, "免费打码接口返回出现问题" v = requests.post(FREE_CAPTCHA_CHECK_URL, json={ "=": "", "check": check, "img_buf": img_base64, "logon": 1, "type": "D" }, headers=FREE_CAPTCHA_HEADERS) try: data = ast.literal_eval(v.json()["res"]) except KeyError: return False, "免费打码接口返回出现问题" except SyntaxError: return False, "免费打码接口返回出现问题" if type(data[0]) == int: self.results = ','.join(map(str, list(data))) else: self.results = ','.join(map(str, list(chain(*data)))) return self.check(self.results)
def run(self): status = self.pre_check() if not status: return Log.v("正在查询车次余票信息") count = 1 while True: self.maintain_mode() self.heart_beat_mode() dates = DispatcherTool.query_travel_dates if Config.basic_config.use_station_group: station_groups = [(v.from_station, v.to_station) for v in Config.basic_config.station_groups] else: station_groups = list( product(Config.basic_config.from_stations, Config.basic_config.to_stations)) query_params = list(product(dates, station_groups)) for query_params in query_params: Log.v("查询第 {0} 次".format(count)) n = datetime.datetime.now() data = DispatcherTool.run(query_params) count += 1 self.submit_order(data) DispatcherTool.output_delta_time(n) if self.order_id or self.unfinished_order: break if self.order_id or self.unfinished_order: break self.notice_user()
def login(self): if not LOGIN_SESSION.cookies.get("RAIL_EXPIRATION") or \ not LOGIN_SESSION.cookies.get("RAIL_DEVICEID"): status, msg = self._init() if not status: return status, msg # status, msg = self._get_device_fingerprint() # if not status: # Log.v("设备ID获取失败") # return status, msg # self._init2() captcha = Captcha("normal") status, msg = captcha.verify() if not status: Log.v("验证码校验失败") return status, msg payload = { 'username': Config.train_account.user, 'password': Config.train_account.pwd, 'appid': 'otn', 'answer': captcha.results } json_response = send_requests(LOGIN_SESSION, self.URLS['login'], data=payload) result, msg = json_status(json_response, [], '0') if not result: return (False, json_response.get("result_message", None)) \ if isinstance(json_response, dict) else (False, '登录接口提交返回数据出现问题') self._passportredirect() result, msg, apptk = self._uamtk() if not result: Log.v(msg) return False, msg status, msg = self._uamauthclient(apptk) return status, msg
def maintain_mode(self): if self.check_maintain(): Log.v("12306系统每天 23:00 - 6:00 之间 维护中, 程序暂时停止运行") maintain_time = self.delta_maintain_time() Log.v("{0}小时 {1}分钟 {2}秒之后重新启动".format( maintain_time.seconds // 3600, (maintain_time.seconds // 60) % 60, maintain_time.seconds % 3600 % 60)) time.sleep(self.delta_maintain_time().total_seconds())
def filter_black_trains(self): result = [] for v in self.result: flag = BlackTrains.check(v[1]) if flag: Log.v("{0} 车次已经在小黑屋".format(v[1].stationTrainCode.value)) else: result.append(copy.copy(v)) return result
def _uamauthclient(self, apptk): json_response = send_requests(LOGIN_SESSION, self.URLS['uamauthclient'], data={'tk': apptk}) status, msg = json_status(json_response, ["username", "result_message"]) if status: Log.v("欢迎 {0} 登录".format(json_response["username"])) return status, msg
def _check_order_status_queue(self): params = { 'orderSequence_no': self.order_id, '_json_att': '', 'REPEAT_SUBMIT_TOKEN': self.token, } Log.v("检查已提交的订单的状态中...") json_response = send_requests(LOGIN_SESSION, self.URLS['resultOrderForQueue'], params=params) status, msg = submit_response_checker(json_response, ["status", "data.submitStatus"], True, "订单已经成功提交") return status, msg
def pre_check(self): if Config.cdn_enable: CdnStorage.load_exists() if not self.login(): return False p_status = self.query_passengers() if not p_status: return False if not Config.auto_code_enable: Log.v("未开启自动打码功能, 不检测用户登录状态") return True
def run(self, travel_date): Log.v("当前查询日期为 {}".format(travel_date)) q = Query(travel_date) data = q.filter() if not data: Log.v("日期 {0} 满足条件的车次暂无余票, 正在重新查询".format(travel_date)) for v in data: print("\t\t\t当前座位席别 {}".format(v[0].name)) q.pretty_output(v[1]) return data
def getcaptcha(): while True: try: data = get_captcha_image( LOGIN_SESSION, LOGIN_URL_MAPPING["normal"]["captcha"]) break except ResponseCodeError: Log.v("获取验证码信息失败,重试获取验证码中...") continue img_binary = base64.b64decode(data["image"]) return img_binary
def run(self): Log.v("您已开启cdn加速") Log.v("正在检查cdn列表可用状态....(大概将会花费10分钟左右)") self.pool.map(self.verify, self.raw_cdn_list) self.status = True Log.v("共获取{0}个可用的cdn".format(len(self.result))) Log.v("各个cdn的等级情况如下(level等级越低证明, cdn的连接更快):") level_result = [v.level for v in self.result] level_types = set(level_result) for v in level_types: Log.v("level {0} 共有 {1} 个".format(v, level_result.count(v)))
def run(self): while self.retry_time: for v in FAST_PIPELINE: status, msg = getattr(self, v)() if not status: self.retry_time -= 1 break else: Log.v("提交订单成功") return True Log.v("提交订单失败") return False
def send_weixin(self, msg_type, **extra_var): if not Config.weixin_notice_enable: Log.v("未开启微信通知") return url = "https://sc.ftqq.com/{key}.send".format(key=Config.weixin_sckey) data = MESSAGES[msg_type] subject = data["subject"] s = data["content"].format(**extra_var) r = requests.post(url, data={"text": subject, "desp": s}) if r.status_code == requests.codes.ok: Log.v("微信通知发送成功") else: Log.e("微信通知发送失败")
def run(self, query_data): Log.v("当前查询日期为 **{0}** 出发地 **{1}** 目的地 **{2}**".format( query_data[0], query_data[1][0], query_data[1][1])) q = Query(query_data[0], query_data[1][0], query_data[1][1]) data = q.filter() if not data: Log.v("日期 **{0}** 出发地 **{1}** 目的地 **{2}** 满足条件的车次暂无余票, 正在重新查询". format(query_data[0], query_data[1][0], query_data[1][1])) for v in data: print("\t\t\t当前座位席别 {}".format(v[0].name)) q.pretty_output(v[1]) return data
def filter(self): # 先过滤席位 self.filter_by_seat() # 过滤小黑屋的车次 self.result = self.filter_black_trains() if Config.basic_config.manual_trainnum_enable: self.result = self.filter_train_num() else: self.result = self.filter_train_time() self.result = self.filter_train_type() if self.result: Log.v("查找到符合配置的车次信息: {0}".format(','.join( [v[1].stationTrainCode.value for v in self.result]))) return self.result
def verifyhandle_hand(self): img = Image.open(BytesIO(self.generator_image())) img.show() Log.v(""" ----------------- | 0 | 1 | 2 | 3 | ----------------- | 4 | 5 | 6 | 7 | ----------------- """) results = input("输入验证码索引(见上图,以','分割): ") img.close() trans = self.trans_captcha_results(results) self.results = trans return self.check(trans)
def online_checker(self): # 两分钟检测一次 flag = OnlineCheckerTool.should_check_online(datetime.datetime.now()) if flag: status, msg = OnlineCheckerTool.checker() OnlineCheckerTool.update_check_time() if not status: Log.v("用户登录失效, 正在为您重试登录") login_status = self.login() if not login_status: return False, "重试登录失败" else: return status, msg else: status, msg = True, "用户状态检测:未到检测时间" return status, msg
def _check_order_info(self): form_data = { 'cancel_flag': self.ticket_passenger_info['orderRequestDTO']['cancel_flag'] or '2', 'bed_level_order_num': self.ticket_passenger_info['orderRequestDTO']['bed_level_order_num'] \ or '000000000000000000000000000000', 'passengerTicketStr': build_passenger_ticket_string(self.seat_type, self.passenger_data), 'oldPassengerStr': build_oldpassenger_ticket_string(self.passenger_data), 'tour_flag': self.ticket_passenger_info['tour_flag'] or 'dc', 'randCode': '', 'whatsSelect': '1', '_json_att': '', 'REPEAT_SUBMIT_TOKEN': self.token, } Log.v("正在提交检查订单状态请求") json_response = send_requests(LOGIN_SESSION, self.URLS['checkOrderInfo'], data=form_data) status, msg = submit_response_checker(json_response, ["status", "data.submitStatus"], True, "校验订单成功") return status, msg
def notice_user(self): if self.order_id: Log.v("车票信息:") for order_ticket in self.order_tickets: print(order_ticket) # 抢票成功发邮件信息 NoticeTool.notice( msg_type=2, **{ "order_no": self.order_id, "ticket_info": "</br>".join([v.to_html() for v in self.order_tickets]) }) else: Log.v("您有未完成订单, 请及时处理后再运行程序") NoticeTool.notice(msg_type=3)
def check(self, results): form_data = { 'randCode': results, 'rand': 'sjrand', } json_response = send_requests( LOGIN_SESSION, LOGIN_URL_MAPPING["other"]["captchaCheck"], data=form_data) Log.v('other login captcha verify: %s' % json_response) def verify(response): return response['status'] and self.success_code == response[ 'data']['result'] v = verify(json_response) return v, "Error" if not v else v
def _get_submit_token(self): html = send_requests(LOGIN_SESSION, self.URLS['getExtraInfo']) Log.v("获取token中....") result = re.findall(r"var globalRepeatSubmitToken = '(.*)'", html) ticket_passenger_info = re.findall(r'var ticketInfoForPassengerForm=(.*);', html) if result: self.token = result[0] if ticket_passenger_info: try: self.ticket_passenger_info = json.loads(ticket_passenger_info[0].replace("'", "\"")) except TypeError: Log.w("获取submit info失败") return False if self.token and self.ticket_passenger_info: Log.v("成功获取token与以及车次信息") return True else: return False
def check_current_mode(self): if (not Config.presale_enable) or self.pre_sale_end: return False else: now = datetime.datetime.now() open_times = list( map(format_time, Config.presale_config.start_times)) f = lambda x: x - now <= self.delta_stop_time and now - x <= self.delta_continue_time result = any(filter(f, open_times)) if result: Log.v("当前处于预售模式,不再处理正常模式下的日期查询") return True check_result = list( filter(lambda x: now > x + self.delta_continue_time, open_times)) if check_result and all(check_result): self.pre_sale_end = True return False return False
def _confirm_single_or_go_for_queue(self): form_data = { 'passengerTicketStr': build_passenger_ticket_string(self.seat_type, self.passenger_data), 'oldPassengerStr': build_oldpassenger_ticket_string(self.passenger_data), 'randCode': '', 'purpose_codes': self.ticket_passenger_info['purpose_codes'], 'key_check_isChange': self.ticket_passenger_info['key_check_isChange'], 'leftTicketStr': self.ticket_passenger_info['leftTicketStr'], 'train_location': self.ticket_passenger_info['train_location'], 'choose_seats': '', # 暂时未加选座 'seatDetailType': '000', 'whatsSelect': '1', 'roomType': '00', 'dwAll': 'N', '_json_att': '', 'REPEAT_SUBMIT_TOKEN': self.token, } Log.v("正在为你请求排队提交订单") json_response = send_requests(LOGIN_SESSION, self.URLS['confirmForQueue'], data=form_data) status, msg = submit_response_checker(json_response, ["status", "data.submitStatus"], True, "请求排队成功") if not status: BlackTrains.add_train(self.train) return status, msg
def _wait_for_order_id(self): # 排队逻辑 t = datetime.datetime.now() # 排队10分钟 delta = datetime.timedelta(minutes=10) while not self.order_id: loop_time = datetime.datetime.now() status, msg = self._query_order_wait_time() Log.v(msg) s, data = find_by_phrase(msg) if s: self.break_submit, self.break_msg = False, data["msg"] return self.break_submit, self.break_msg # 5s 获取排队信息 time.sleep(5) if self.order_id: return True, "OK" if loop_time > t + delta: BlackTrains.add_train(self.train) return False, "提交超时" return False, "排队失败"
def _query_order_wait_time(self): params = { 'random': '%10d' % (time.time() * 1000), 'tourFlag': self.ticket_passenger_info['tour_flag'] or 'dc', '_json_att': '', 'REPEAT_SUBMIT_TOKEN': self.token } Log.v("获取订单排队信息...") json_response = send_requests(LOGIN_SESSION, self.URLS['queryOrderWaitTime'], params=params) status, msg = submit_response_checker(json_response, ["status"], True, "排队请求成功") if status: self.wait_time = json_response['data']['waitTime'] self.order_id = json_response['data']['orderId'] people_count = json_response["data"]["waitCount"] msg += " 排队等待时间预计还剩 {0} ms, 排队人数还剩 {1} 人".format( self.wait_time, people_count) if not self.order_id: msg += "\t 订单暂未生成" if "msg" in json_response["data"]: msg += "\t {0}".format(json_response["data"]["msg"]) return status, msg