Esempio n. 1
0
def login():
    """
    用户登录
    :return:
    """
    username = request.json.get('username', None)
    password = request.json.get('password', None)
    if username and password and username == Config().WEB_USER.get('username') and password == Config().WEB_USER.get(
            'password'):
        access_token = create_access_token(identity=username)
        return jsonify(access_token=access_token)
    return jsonify({"msg": "用户名或密码错误"}), 422
Esempio n. 2
0
    def handler_exit(self, *args, **kwargs):
        """
        程序退出
        :param args:
        :param kwargs:
        :return:
        """
        if Config.is_cluster_enabled():
            from py12306.cluster.cluster import Cluster
            Cluster().left_cluster()

        sys.exit()
Esempio n. 3
0
 def order(self):
     """
     开始下单
     下单模式  暂时不清楚,使用正常步骤下单
     :return:
     """
     # Debug
     if Config().IS_DEBUG:
         self.order_id = 'test'
         self.order_did_success()
         return random.randint(0, 10) > 7
     return self.normal_order()
Esempio n. 4
0
    def load_user(self):
        if Config().is_cluster_enabled():
            return
        cookie_path = self.get_cookie_path()

        if path.exists(cookie_path):
            with open(self.get_cookie_path(), 'rb') as f:
                cookie = pickle.load(f)
                self.cookie = True
                self.session.cookies.update(cookie)
                self.did_loaded_user()
                return True
        return None
Esempio n. 5
0
 def send_email_by_smtp(self, to, title, content):
     import smtplib
     from email.message import EmailMessage
     to = to if isinstance(to, list) else [to]
     message = EmailMessage()
     message['Subject'] = title
     message['From'] = Config().EMAIL_SENDER
     message['To'] = to
     message.set_content(content)
     try:
         server = smtplib.SMTP(Config().EMAIL_SERVER_HOST)
         server.login(Config().EMAIL_SERVER_USER,
                      Config().EMAIL_SERVER_PASSWORD)
         server.ehlo()
         server.starttls()
         server.send_message(message)
         server.quit()
         CommonLog.add_quick_log(
             CommonLog.MESSAGE_SEND_EMAIL_SUCCESS).flush()
     except Exception as e:
         CommonLog.add_quick_log(
             CommonLog.MESSAGE_SEND_EMAIL_FAIL.format(e)).flush()
Esempio n. 6
0
def app_available_check():
    # return True  # Debug
    if Config().IS_DEBUG:
        return True
    now = time_now()
    if (now.hour >= 23 and now.minute >= 30) or now.hour < 6:
        CommonLog.add_quick_log(
            CommonLog.MESSAGE_12306_IS_CLOSED.format(time_now())).flush()
        open_time = datetime.datetime(now.year, now.month, now.day, 6)
        if open_time < now:
            open_time += datetime.timedelta(1)
        sleep((open_time - now).seconds)
    return True
Esempio n. 7
0
    def push_to_bark(self, content):
        bark_url = Config().BARK_PUSH_URL
        if not bark_url:
            return False

        response = self.session.request(url=bark_url + '/' + content, method='get')
        result = response.json()
        response_status = result.get('code')
        if response_status == 200:
            CommonLog.add_quick_log(CommonLog.MESSAGE_SEND_BARK_SUCCESS).flush()
        else:
            response_error_message = result.get('message')
            CommonLog.add_quick_log(CommonLog.MESSAGE_SEND_BARK_FAIL.format(response_error_message)).flush()
Esempio n. 8
0
def index():
    file = Config().WEB_ENTER_HTML_PATH
    result = ''
    with open(file, 'r', encoding='utf-8') as f:
        result = f.read()
        config = {
            'API_BASE_URL': ''  # TODO 自定义 Host
        }
        result = re.sub(
            r'<script>[\s\S]*?<\/script>',
            '<script>window.config={}</script>'.format(json.dumps(config)),
            result)

    return result
Esempio n. 9
0
 def load_user_from_remote(self):
     cookie = self.cluster.get_user_cookie(self.key)
     info = self.cluster.get_user_info(self.key)
     if Config().is_slave() and (not cookie or not info):
         while True:  # 子节点只能取
             UserLog.add_quick_log(
                 UserLog.MESSAGE_USER_COOKIE_NOT_FOUND_FROM_REMOTE.format(
                     self.user_name)).flush()
             stay_second(self.retry_time)
             return self.load_user_from_remote()
     if info:
         self.info = info
     if cookie:
         self.session.cookies.update(cookie)
         if not self.cookie:  # 第一次加载
             self.cookie = True
             if not Config().is_slave():
                 self.did_loaded_user()
             else:
                 self.is_ready = True  # 设置子节点用户 已准备好
                 UserLog.print_welcome_user(self)
         return True
     return False
Esempio n. 10
0
    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})
Esempio n. 11
0
 def send_to_telegram_bot(self, content):
     bot_api_url = Config().TELEGRAM_BOT_API_URL
     if not bot_api_url:
         return False
     data = {
         'text': content
     }
     response = self.session.request(url=bot_api_url, method='POST', data=data)
     result = response.json().get('result')
     response_status = result.get('statusCode')
     if response_status == 200:
         CommonLog.add_quick_log(CommonLog.MESSAGE_SEND_TELEGRAM_SUCCESS).flush()
     else:
         response_error_message = result.get('description')
         CommonLog.add_quick_log(CommonLog.MESSAGE_SEND_TELEGRAM_FAIL.format(response_error_message)).flush()
Esempio n. 12
0
 def get_user_passengers(self):
     if self.passengers:
         return self.passengers
     response = self.session.post(API_USER_PASSENGERS)
     result = response.json()
     if result.get('data.normal_passengers'):
         self.passengers = result.get('data.normal_passengers')
         # 将乘客写入到文件
         with open(Config().USER_PASSENGERS_FILE % self.user_name,
                   'w',
                   encoding='utf-8') as f:
             f.write(
                 json.dumps(self.passengers, indent=4, ensure_ascii=False))
         return self.passengers
     else:
         UserLog.add_quick_log(
             UserLog.MESSAGE_GET_USER_PASSENGERS_FAIL.format(
                 result.get('messages',
                            CommonLog.MESSAGE_RESPONSE_EMPTY_ERROR),
                 self.retry_time)).flush()
         if Config().is_slave():
             self.load_user_from_remote()  # 加载最新 cookie
         stay_second(self.retry_time)
         return self.get_user_passengers()
Esempio n. 13
0
def app_available_check():
    if Config().IS_DEBUG:
        return True
    now = time_now()
    if now.weekday() == 1 and (now.hour > 23 and now.minute > 30 or now.hour < 5):
        CommonLog.add_quick_log(CommonLog.MESSAGE_12306_IS_CLOSED.format(time_now())).flush()
        open_time = datetime.datetime(now.year, now.month, now.day, 5)
        if open_time < now:
            open_time += datetime.timedelta(1)
        sleep((open_time - now).seconds)
    elif 1 < now.hour < 5:
        CommonLog.add_quick_log(CommonLog.MESSAGE_12306_IS_CLOSED.format(time_now())).flush()
        open_time = datetime.datetime(now.year, now.month, now.day, 5)
        sleep((open_time - now).seconds)
    return True
Esempio n. 14
0
    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
Esempio n. 15
0
 def flush(cls, sep='\n', end='\n', file=None, exit=False, publish=True):
     from py12306.cluster.cluster import Cluster
     self = cls()
     logs = self.get_logs()
     # 输出到文件
     if file == None and Config(
     ).OUT_PUT_LOG_TO_FILE_ENABLED and not Const.IS_TEST:  # TODO 文件无法写入友好提示
         file = open(Config().OUT_PUT_LOG_TO_FILE_PATH,
                     'a',
                     encoding='utf-8')
     if not file: file = None
     # 输出日志到各个节点
     if publish and self.quick_log and Config().is_cluster_enabled(
     ) and Cluster().is_ready:  #
         f = io.StringIO()
         with redirect_stdout(f):
             print(*logs, sep=sep, end='' if end == '\n' else end)
         out = f.getvalue()
         Cluster().publish_log_message(out)
     else:
         print(*logs, sep=sep, end=end, file=file)
     self.empty_logs(logs)
     if exit:
         sys.exit()
Esempio n. 16
0
 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)
     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=True)
     self.is_cdn = False
     return self.query.session.get(url, timeout=self.query_time_out, allow_redirects=True)
Esempio n. 17
0
 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
Esempio n. 18
0
 def request(self, *args, **kwargs):  # 拦截所有错误
     try:
         if not 'timeout' in kwargs:
             from py12306.config import Config
             kwargs['timeout'] = Config().TIME_OUT_OF_REQUEST
         response = super().request(*args, **kwargs)
         return response
     except RequestException as e:
         from py12306.log.common_log import CommonLog
         if e.response:
             response = e.response
         else:
             response = HTMLResponse(HTMLSession)
             # response.status_code = 500
             expand_class(response, 'json', Request.json)
         response.reason = response.reason if response.reason else CommonLog.MESSAGE_RESPONSE_EMPTY_ERROR
         return response
Esempio n. 19
0
    def request_device_id(self):
        """
        :return:
        """
        print("cookie获取中")
        driver = webdriver.Chrome(executable_path=Config().CHROME_PATH)
        driver.get("https://www.12306.cn/index/index.html")
        time.sleep(10)

        for c in driver.get_cookies():
            print()
            cookie = dict()
            if c.get("name") == "RAIL_DEVICEID" or c.get(
                    "name") == "RAIL_EXPIRATION":
                cookie[c.get('name')] = c.get('value')
                # print(f"获取cookie: {cookie}")
            self.session.cookies.update(cookie)
Esempio n. 20
0
 def send_voice_code_of_dingxin(self, phone, name='', info={}):
     """
     发送语音验证码 ( 鼎信 )
     购买地址 https://market.aliyun.com/products/56928004/cmapi026600.html?spm=5176.2020520132.101.2.51547218rkAXxy
     :return:
     """
     appcode = Config().NOTIFICATION_API_APP_CODE
     if not appcode:
         CommonLog.add_quick_log(CommonLog.MESSAGE_EMPTY_APP_CODE).flush()
         return False
     data = {
         'tpl_id':
         'TP1901174',
         'phone':
         phone,
         'param':
         'name:{name},job_name:{left_station}到{arrive_station}{set_type},orderno:{orderno}'
         .format(name=name,
                 left_station=info.get('left_station'),
                 arrive_station=info.get('arrive_station'),
                 set_type=info.get('set_type'),
                 orderno=info.get('orderno'))
     }
     response = self.session.request(
         url=API_NOTIFICATION_BY_VOICE_CODE_DINGXIN,
         method='POST',
         data=data,
         headers={'Authorization': 'APPCODE {}'.format(appcode)})
     result = response.json()
     response_message = result.get('return_code')
     if response.status_code in [400, 401, 403]:
         return CommonLog.add_quick_log(
             CommonLog.MESSAGE_VOICE_API_FORBID).flush()
     if response.status_code == 200 and result.get(
             'return_code') == '00000':
         CommonLog.add_quick_log(
             CommonLog.MESSAGE_VOICE_API_SEND_SUCCESS.format(
                 response_message)).flush()
         return True
     else:
         return CommonLog.add_quick_log(
             CommonLog.MESSAGE_VOICE_API_SEND_FAIL.format(
                 response_message)).flush()
Esempio n. 21
0
    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)
Esempio n. 22
0
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)
Esempio n. 23
0
    def check_master(self):
        """
        检测主节点是否可用
        :return:
        """
        master = self.have_master()
        if master == self.node_name:  # 动态提升
            self.is_master = True
        else:
            self.is_master = False

        if not master:
            if Config().NODE_SLAVE_CAN_BE_MASTER:
                # 提升子节点为主节点
                slave = list(self.nodes)[0]
                self.session.hset(self.KEY_NODES, slave, self.KEY_MASTER)
                self.publish_log_message(ClusterLog.MESSAGE_ASCENDING_MASTER_NODE.format(slave,
                                                                                         ClusterLog.get_print_nodes(
                                                                                             self.get_nodes())))
                return True
            else:
                self.publish_log_message(ClusterLog.MESSAGE_MASTER_DID_LOST.format(self.retry_time))
                stay_second(self.retry_time)
                os._exit(1)  # 退出整个程序
Esempio n. 24
0
 def send_voice_code_of_yiyuan(self, phone, name='', content=''):
     """
     发送语音验证码
     购买地址 https://market.aliyun.com/products/57126001/cmapi019902.html?spm=5176.2020520132.101.5.37857218O6iJ3n
     :return:
     """
     appcode = Config().NOTIFICATION_API_APP_CODE
     if not appcode:
         CommonLog.add_quick_log(CommonLog.MESSAGE_EMPTY_APP_CODE).flush()
         return False
     body = {'userName': name, 'mailNo': content}
     params = {
         'content': body,
         'mobile': phone,
         'sex': 2,
         'tNum': 'T170701001056'
     }
     response = self.session.request(
         url=API_NOTIFICATION_BY_VOICE_CODE +
         urllib.parse.urlencode(params),
         method='GET',
         headers={'Authorization': 'APPCODE {}'.format(appcode)})
     result = response.json()
     response_message = result.get('showapi_res_body.remark')
     if response.status_code in [400, 401, 403]:
         return CommonLog.add_quick_log(
             CommonLog.MESSAGE_VOICE_API_FORBID).flush()
     if response.status_code == 200 and result.get('showapi_res_body.flag'):
         CommonLog.add_quick_log(
             CommonLog.MESSAGE_VOICE_API_SEND_SUCCESS.format(
                 response_message)).flush()
         return True
     else:
         return CommonLog.add_quick_log(
             CommonLog.MESSAGE_VOICE_API_SEND_FAIL.format(
                 response_message)).flush()
Esempio n. 25
0
    def test_send_notifications(cls):
        if Config().NOTIFICATION_BY_VOICE_CODE:  # 语音通知
            CommonLog.add_quick_log(
                CommonLog.MESSAGE_TEST_SEND_VOICE_CODE).flush()
            Notification.voice_code(
                Config().NOTIFICATION_VOICE_CODE_PHONE, '张三',
                OrderLog.
                MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT.
                format('北京', '深圳'))
        if Config().EMAIL_ENABLED:  # 语音通知
            CommonLog.add_quick_log(CommonLog.MESSAGE_TEST_SEND_EMAIL).flush()
            Notification.send_email(Config().EMAIL_RECEIVER, '测试发送邮件',
                                    'By py12306')

        if Config().DINGTALK_ENABLED:  # 钉钉通知
            CommonLog.add_quick_log(
                CommonLog.MESSAGE_TEST_SEND_DINGTALK).flush()
            Notification.dingtalk_webhook('测试发送信息')

        if Config().TELEGRAM_ENABLED:  # Telegram通知
            CommonLog.add_quick_log(
                CommonLog.MESSAGE_TEST_SEND_TELEGRAM).flush()
            Notification.send_to_telegram('测试发送信息')
Esempio n. 26
0
    def send_notification(self):
        num = 0  # 通知次数
        sustain_time = self.notification_sustain_time
        if Config().EMAIL_ENABLED:  # 邮件通知
            Notification.send_email(
                Config().EMAIL_RECEIVER,
                OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE,
                OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT.
                format(self.order_id))
        if Config().DINGTALK_ENABLED:  # 钉钉通知
            Notification.dingtalk_webhook(
                OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT.
                format(self.order_id))
        if Config().TELEGRAM_ENABLED:  # Telegram推送
            Notification.send_to_telegram(
                OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT.
                format(self.order_id))
        while sustain_time:  # TODO 后面直接查询有没有待支付的订单就可以
            num += 1
            if Config().NOTIFICATION_BY_VOICE_CODE:  # 语音通知
                OrderLog.add_quick_log(
                    OrderLog.
                    MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_START_SEND
                    .format(num))
                Notification.voice_code(
                    Config().NOTIFICATION_VOICE_CODE_PHONE,
                    self.user_ins.get_name(),
                    OrderLog.
                    MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT.
                    format(self.query_ins.left_station,
                           self.query_ins.arrive_station))
            else:
                break
            sustain_time -= self.notification_interval
            sleep(self.notification_interval)

        OrderLog.add_quick_log(OrderLog.MESSAGE_JOB_CLOSED).flush()
Esempio n. 27
0
 def __init__(self, session):
     self.data_path = Config().RUNTIME_DIR
     self.session = session
Esempio n. 28
0
 def update_query_interval(self, auto=False):
     self.interval = init_interval_by_number(Config().QUERY_INTERVAL)
     if auto:
         jobs_do(self.jobs, 'update_interval')
Esempio n. 29
0
 def run_session(self):
     debug = False
     if is_main_thread():
         debug = Config().IS_DEBUG
     self.session.run(debug=debug, port=Config().WEB_PORT, host='0.0.0.0')
Esempio n. 30
0
 def start(self):
     if not Config().WEB_ENABLE or Config().is_slave(): return
     # if Config().IS_DEBUG:
     #     self.run_session()
     # else:
     create_thread_and_run(self, 'run_session', wait=False)