def handle_response(self, response): """ 错误判断 余票判断 小黑屋判断 座位判断 乘车人判断 :param result: :return: """ results = self.get_results(response) if not results: return False for result in results: self.ticket_info = ticket_info = result.split('|') if not self.is_trains_number_valid(): # 车次是否有效 continue QueryLog.add_log( QueryLog.MESSAGE_QUERY_LOG_OF_EVERY_TRAIN.format( self.get_info_of_train_number())) if not self.is_has_ticket(ticket_info): continue allow_seats = self.allow_seats if self.allow_seats else list( Config.SEAT_TYPES.values()) # 未设置 则所有可用 TODO 合法检测 self.handle_seats(allow_seats, ticket_info) if not self.is_alive: return
def start(self): """ 处理单个任务 根据日期循环查询, 展示处理时间 :param job: :return: """ while True and self.is_alive: app_available_check() QueryLog.print_job_start(self.job_name) for station in self.stations: self.refresh_station(station) for date in self.left_dates: self.left_date = date response = self.query_by_date(date) self.handle_response(response) QueryLog.add_query_time_log( time=response.elapsed.total_seconds(), is_cdn=self.is_cdn) if not self.is_alive: return self.safe_stay() if is_main_thread(): QueryLog.flush(sep='\t\t', publish=False) if not Config().QUERY_JOB_THREAD_ENABLED: QueryLog.add_quick_log('').flush(publish=False) break else: QueryLog.add_log('\n').flush(sep='\t\t', publish=False) if Const.IS_TEST: return
def update_query_jobs(self, auto=False): self.query_jobs = Config().QUERY_JOBS if auto: QueryLog.add_quick_log(QueryLog.MESSAGE_JOBS_DID_CHANGED).flush() self.refresh_jobs() if not Config().is_slave(): jobs_do(self.jobs, 'check_passengers')
def safe_stay(self): origin_interval = get_interval_num(self.interval) interval = origin_interval + self.interval_additional QueryLog.add_stay_log('%s + %s' % (origin_interval, self.interval_additional) if self.interval_additional else origin_interval) stay_second(interval)
def query_by_date(self, date): """ 通过日期进行查询 :return: """ from py12306.helpers.cdn import Cdn QueryLog.add_log(('\n' if not is_main_thread() else '') + QueryLog.MESSAGE_QUERY_START_BY_DATE.format( date, self.left_station, self.arrive_station)) url = LEFT_TICKETS.get('url').format( left_date=date, left_station=self.left_station_code, arrive_station=self.arrive_station_code, type=self.query.api_type) print("ticket query url=%s" % url) if Config.is_cdn_enabled() and Cdn().is_ready: self.is_cdn = True print("12306 cdn is enabled.") return self.query.session.cdn_request(url, timeout=self.query_time_out, allow_redirects=False) self.is_cdn = False return self.query.session.get(url, timeout=self.query_time_out, allow_redirects=False)
def check_passengers(self): if not self.passengers: QueryLog.add_quick_log(QueryLog.MESSAGE_CHECK_PASSENGERS.format(self.job_name)).flush() passengers = User.get_passenger_for_members(self.members, self.account_key) if passengers: self.set_passengers(passengers) else: # 退出当前查询任务 self.destroy() return True
def get_results(self, response): """ 解析查询返回结果 :param response: :return: """ if response.status_code != 200: QueryLog.print_query_error(response.reason, response.status_code) result = response.json().get('data.result') return result if result else False
def destroy(self): """ 退出任务 :return: """ from py12306.query.query import Query self.is_alive = False QueryLog.add_quick_log(QueryLog.MESSAGE_QUERY_JOB_BEING_DESTROY.format(self.job_name)).flush() # sys.exit(1) # 无法退出线程... # 手动移出jobs 防止单线程死循环 index = Query().jobs.index(self) Query().jobs.pop(index)
def query_by_date(self, date): """ 通过日期进行查询 :return: """ QueryLog.add_log(('\n' if not is_main_thread() else '') + QueryLog.MESSAGE_QUERY_START_BY_DATE.format(date, self.left_station, self.arrive_station)) url = LEFT_TICKETS.get('url').format(left_date=date, left_station=self.left_station_code, arrive_station=self.arrive_station_code, type='leftTicket/queryZ') return self.query.session.get(url)
def get_results(self, response): """ 解析查询返回结果 :param response: :return: """ if response.status_code != 200: QueryLog.print_query_error(response.reason, response.status_code) try: result_data = response.json().get('data', {}) result = result_data.get('result', []) except: pass # TODO return result if result else False
def handle_seats(self, allow_seats, ticket_info): for seat in allow_seats: # 检查座位是否有票 self.set_seat(seat) ticket_of_seat = ticket_info[self.current_seat] if not self.is_has_ticket_by_seat(ticket_of_seat): # 座位是否有效 continue QueryLog.print_ticket_seat_available( left_date=self.get_info_of_left_date(), train_number=self.get_info_of_train_number(), seat_type=seat, rest_num=ticket_of_seat) if not self.is_member_number_valid(ticket_of_seat): # 乘车人数是否有效 if self.allow_less_member: self.member_num_take = int(ticket_of_seat) QueryLog.print_ticket_num_less_than_specified( ticket_of_seat, self) else: QueryLog.add_quick_log( QueryLog. MESSAGE_GIVE_UP_CHANCE_CAUSE_TICKET_NUM_LESS_THAN_SPECIFIED ).flush() continue if Const.IS_TEST: return # 检查完成 开始提交订单 QueryLog.print_ticket_available( left_date=self.get_info_of_left_date(), train_number=self.get_info_of_train_number(), rest_num=ticket_of_seat) self.check_passengers() order = Order(user=self.get_user(), query=self) order.order()
def get_results(self, response): """ 解析查询返回结果 :param response: :return: """ if response.status_code != 200: QueryLog.print_query_error(response.reason, response.status_code) if self.interval_additional < self.interval_additional_max: self.interval_additional += self.interval.get('min') else: self.interval_additional = 0 result = response.json().get('data.result') return result if result else False
def start(self): # return # DEBUG self.init_jobs() QueryLog.print_init_jobs(jobs=self.jobs) stay_second(1) while True: app_available_check() if config.QUERY_JOB_THREAD_ENABLED: # 多线程 create_thread_and_run(jobs=self.jobs, callback_name='run') else: for job in self.jobs: job.run() if Const.IS_TEST: return
def judge_date_legal(self, date): date_now = datetime.datetime.now() date_query = datetime.datetime.strptime(str(date), "%Y-%m-%d") diff = (date_query - date_now).days if date_now.day == date_query.day: diff = 0 if diff < 0: msg = '乘车日期错误,比当前时间还早!!' QueryLog.add_quick_log(msg).flush(publish=False) raise RuntimeError(msg) elif diff > self.max_buy_time: msg = '乘车日期错误,超出一个月预售期!!' QueryLog.add_quick_log(msg).flush(publish=False) raise RuntimeError(msg) else: pass
def get_query_api_type(cls): import re self = cls() if self.api_type: return self.api_type response = self.session.get(API_QUERY_INIT_PAGE) if response.status_code == 200: res = re.search(r'var CLeftTicketUrl = \'(.*)\';', response.text) try: self.api_type = res.group(1) except IndexError: pass if not self.api_type: QueryLog.add_quick_log('查询地址获取失败, 正在重新获取...').flush() sleep(1) return cls.get_query_api_type()
def start(self): # return # DEBUG QueryLog.init_data() stay_second(3) # 多线程 while True: if Config().QUERY_JOB_THREAD_ENABLED: # 多线程 if not self.is_in_thread: self.is_in_thread = True create_thread_and_run(jobs=self.jobs, callback_name='run', wait=Const.IS_TEST) if Const.IS_TEST: return stay_second(self.retry_time) else: if not self.jobs: break self.is_in_thread = False jobs_do(self.jobs, 'run') if Const.IS_TEST: return
def refresh_jobs(self): """ 更新任务 :return: """ allow_jobs = [] for job in self.query_jobs: id = md5(job) job_ins = objects_find_object_by_key_value(self.jobs, 'id', id) # [1 ,2] if not job_ins: job_ins = self.init_job(job) if Config().QUERY_JOB_THREAD_ENABLED: # 多线程重新添加 create_thread_and_run(jobs=job_ins, callback_name='run', wait=Const.IS_TEST) allow_jobs.append(job_ins) for job in self.jobs: # 退出已删除 Job if job not in allow_jobs: job.destroy() QueryLog.print_init_jobs(jobs=self.jobs)
def get_results(self, response): """ 解析查询返回结果 :param response: :return: """ if response.status_code != 200: QueryLog.print_query_error(response.reason, response.status_code) if self.interval_additional < self.interval_additional_max: self.interval_additional += self.interval.get('min') else: self.interval_additional = 0 result = response.json() #QueryLog.add_quick_log("result:" + str(result)) if result and result['data'] and result['data']['result']: result = result.get('data').get('result') else: result = None return result if result else False
def query_by_date(self, date): """ 通过日期进行查询 :return: """ from py12306.helpers.cdn import Cdn QueryLog.add_log(('\n' if not is_main_thread() else '') + QueryLog.MESSAGE_QUERY_START_BY_DATE.format( date, self.left_station, self.arrive_station)) url = LEFT_TICKETS.get('url').format( left_date=date, left_station=self.left_station_code, arrive_station=self.arrive_station_code, type='leftTicket/queryZ') if Config.is_cdn_enabled() and Cdn().is_ready: self.is_cdn = True return self.query.session.cdn_request(url, timeout=self.query_time_out, allow_redirects=False) self.is_cdn = False if Config.is_zf(): headers = ZFProxyUtil.getProxySign() proxy = ZFProxyUtil.getProxy() yp_by_data = self.query.session.get(url, headers=headers, proxies=proxy, verify=False, allow_redirects=False, timeout=self.query_time_out) else: yp_by_data = self.query.session.get(url, verify=False, allow_redirects=False, timeout=self.query_time_out) return yp_by_data
def dashboard(): """ 状态统计 任务数量,用户数量,查询次数 节点信息(TODO) :return: """ from py12306.log.query_log import QueryLog query_job_count = len(Query().jobs) user_job_count = len(User().users) query_count = QueryLog().data.get('query_count') return jsonify({ 'query_job_count': query_job_count, 'user_job_count': user_job_count, 'query_count': query_count })
def start(self): """ 处理单个任务 根据日期循环查询 展示处理时间 :param job: :return: """ QueryLog.print_job_start() for date in self.left_dates: self.left_date = date response = self.query_by_date(date) self.handle_response(response) self.safe_stay() if is_main_thread(): QueryLog.flush(sep='\t\t') if is_main_thread(): QueryLog.add_quick_log('').flush() else: QueryLog.add_log('\n').flush(sep='\t\t')
def dashboard(): """ 状态统计 任务数量,用户数量,查询次数 节点信息(TODO) :return: """ from py12306.log.query_log import QueryLog query_job_count = len(Query().jobs) user_job_count = len(User().users) query_count = QueryLog().data.get('query_count') res = { 'query_job_count': query_job_count, 'user_job_count': user_job_count, 'query_count': query_count, } if Config().CDN_ENABLED: from py12306.helpers.cdn import Cdn res['cdn_count'] = len(Cdn().available_items) return jsonify(res)
def init_jobs(self): for job in self.query_jobs: self.init_job(job) QueryLog.print_init_jobs(jobs=self.jobs)
def handle_seats(self, allow_seats, ticket_info): for seat in allow_seats: # 检查座位是否有票 self.set_seat(seat) ticket_of_seat = ticket_info[self.current_seat] if not self.is_has_ticket_by_seat(ticket_of_seat): # 座位是否有效 continue QueryLog.print_ticket_seat_available( left_date=self.get_info_of_left_date(), train_number=self.get_info_of_train_number(), seat_type=seat, rest_num=ticket_of_seat) if not self.is_member_number_valid(ticket_of_seat): # 乘车人数是否有效 if self.allow_less_member: self.member_num_take = int(ticket_of_seat) QueryLog.print_ticket_num_less_than_specified( ticket_of_seat, self) else: QueryLog.add_quick_log( QueryLog. MESSAGE_GIVE_UP_CHANCE_CAUSE_TICKET_NUM_LESS_THAN_SPECIFIED ).flush() continue if Const.IS_TEST: return # 检查完成 开始提交订单 QueryLog.print_ticket_available( left_date=self.get_info_of_left_date(), train_number=self.get_info_of_train_number(), rest_num=ticket_of_seat) if User.is_empty(): QueryLog.add_quick_log( QueryLog.MESSAGE_USER_IS_EMPTY_WHEN_DO_ORDER.format( self.retry_time)) return stay_second(self.retry_time) order_result = False user = self.get_user() if not user: QueryLog.add_quick_log( QueryLog.MESSAGE_ORDER_USER_IS_EMPTY.format( self.retry_time)) return stay_second(self.retry_time) lock_id = Cluster.KEY_LOCK_DO_ORDER + '_' + user.key if Config().is_cluster_enabled(): if self.cluster.get_lock( lock_id, Cluster.lock_do_order_time, {'node': self.cluster.node_name}): # 获得下单锁 order_result = self.do_order(user) if not order_result: # 下单失败,解锁 self.cluster.release_lock(lock_id) else: QueryLog.add_quick_log( QueryLog.MESSAGE_SKIP_ORDER.format( self.cluster.get_lock_info(lock_id).get('node'), user.user_name)) stay_second(self.retry_time) # 防止过多重复 else: order_result = self.do_order(user) # 任务已成功 通知集群停止任务 if order_result: Event().job_destroy({'name': self.job_name})
def safe_stay(self): interval = get_interval_num(self.interval) QueryLog.add_stay_log(interval) stay_second(interval)
def check_passengers(self): if not self.passengers: QueryLog.add_quick_log(QueryLog.MESSAGE_CHECK_PASSENGERS).flush() self.set_passengers( User.get_passenger_for_members(self.members, self.account_key)) return True
def update_query_jobs(self, auto=False): self.query_jobs = Config().QUERY_JOBS if auto: QueryLog.add_quick_log(QueryLog.MESSAGE_JOBS_DID_CHANGED).flush() self.refresh_jobs()