ある投資会社の財テク製品の事前購入を自動的に奪う


友达はある投資会社の財テク製品の事前購入を自動的に奪うように手伝ってもらいました.
主に2点を学びました.
  • で使用されるターゲットアドレスはモバイル側であり、cookiesはありません.HTTPSヘッダにAuthorizationフィールドを追加し、値が「Bearer」+tokenであることで、ログインユーザを判断します.大体の過程は以下の通りです.
  • はログインアドレスにpostを発行し、ユーザー名とパスワード(json)を持ってtokenを返します.
  • 製品の予約にはユーザ情報が必要なので、まずユーザ情報を取得する:HTTPSヘッダにAuthorizationフィールドを付け、値は‘Bearer’+token(tokenは第1ステップログイン後にサーバが返すtoken値)であり、ユーザ情報を取得したアドレスにgetを発行する.
  • 予約製品:同様にHTTPSヘッダにtokenを持ち込み、ユーザー情報と財テク製品のidをjson dataとして構築し、postを発行する必要があります.
  • 
    headers = {
        'Authorization': 'Bearer ' + token, #token     
        'Host': 'api.***.com',
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json;charset=UTF-8',
        'Referer': 'https://m.***.com',
        'Origin': 'https://m.***.com',
        'User-Agent': self._get_user_agent()
    }
    
    
      async with aiohttp.ClientSession() as session:
      	async with session.post(self.urls['order'], json=data, headers=self.headers, verify_ssl=False, timeout=self.time_out) as response:
          if response.status == 200:
              return await response.json()
    
  • 小さな会社ですが、製品の買い取り人はあまり多くありません.毎回手伝う人も多くありません(毎期最大で10人ぐらいです).実は合併しなくてもいいです.見積もってみると、10人も1-2秒のことです.しかし、最終的には同時バージョンを開発し、ちょうどpython asyncio aiohttpを練習した.
  • の概略フローは、ユーザ情報ファイル(jsonフォーマット)を読み取ることによって、すべてのユーザがログインし、情報を取得し、予約する3つの前後プロセスを使用して、共発を使用する.
  • サーバがhttpを使用するため、aiohttpはget、postでverify_を使用する限りSSLエラーをプロンプトします.ssl=Falseでいいです.
  • を併用ものはasyncioである.gather()は、すべてのタスクをtaskにカプセル化して同時実行しました.しかし,タイムアウト再送の処理中に突然呆然とし,併発した場合にどのように再開するか分からなかった.最初はタイムアウトしたリクエストをasyncioに戻す方法を考えていました.loopでは、どうしても結果を得る良い方法はありません.その後、タイムアウト異常(aiohttp.ServerTimeoutError)を処理するときに、await自体という非同期関数を再び処理します.


  • 完全なコードは次のとおりです:user.py
    # -*- coding: utf-8 -*-
    import random
    import aiohttp
    import asyncio
    
    
    class User:
        """
          
        number:       
        pwd:  
        order_amt:    
        urls: url  :  url,      url,    url
        semaphore:    
        time_out:   
        retry_times:     
        """
    
        def __init__(self, number, pwd, order_amt, urls, semaphore, time_out, retry_times):
            self.number = number
            self.pwd = pwd
            self.order_amt = order_amt
            self.urls = urls
            self.semaphore = semaphore
            self.time_out = time_out
            self.RETRY_TIMES = retry_times
            self.retry = retry_times
    
            self.token = None
            self.login_msg = ''
            self.headers = {}
            self.msg = {}
    
        async def login(self):
            """    """
            self.retry -= 1
            async with self.semaphore:
                try:
                    async with aiohttp.ClientSession() as session:
                        async with session.post(self.urls['login'], json={'phoneNo': self.number, 'password': self.pwd},
                                                verify_ssl=False, timeout=self.time_out) as response:
                            if response.status == 200:
                                return await response.json()
                            else:
                                return {'msg': 'response_status {}'.format(response.status)}
                except aiohttp.ServerTimeoutError as e:
                    retry_msg = '{}     '.format(self.number)
                    false_msg = '{}     '.format(self.number)
                    await self._handle_timeout(self.login, self.parse_login, retry_msg, false_msg, e)
                except Exception as e:
                    raise e
    
        def parse_login(self, task):
            """      ,  token,   headers"""
            self.retry = self.RETRY_TIMES
            data = task.result()
            self.login_msg = data.get('msg', '')
            if self.login_msg == '    ':
                self.token = data['data']['token']
                self.make_headers()
    
        def _get_user_agent(self):
            """    User-Agent"""
            USER_AGENT_LIST = [
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60",
                "Opera/8.0 (Windows NT 5.1; U; en)",
                "Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50",
                "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0",
                "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36",
                "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11",
                "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36",
                "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER",
                "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER) ",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)",
                "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)"
            ]
            return random.choice(USER_AGENT_LIST)
    
        def make_headers(self):
            """  requests HTML    ,      token"""
            if self.token:
                self.headers = {
                    'Authorization': 'Bearer ' + self.token,
                    'Host': 'api.***.com',
                    'Accept': 'application/json, text/plain, */*',
                    'Content-Type': 'application/json;charset=UTF-8',
                    'Referer': 'https://m.***.com',
                    'Origin': 'https://m.***.com',
                    'User-Agent': self._get_user_agent()
                }
    
        async def get_msg(self):
            """           """
            if self.headers:
                self.retry -= 1
                async with self.semaphore:
                    try:
                        async with aiohttp.ClientSession() as session:
                            async with session.get(self.urls['getuser'], headers=self.headers,
                                                   verify_ssl=False, timeout=self.time_out) as response:
                                if response.status == 200:
                                    return await response.json()
                                else:
                                    return {'msg': 'response_status {}'.format(response.status)}
                    except aiohttp.ServerTimeoutError as e:
                        retry_msg = '{}         '.format(self.number)
                        false_msg = '{}         '.format(self.number)
                        await self._handle_timeout(self.get_msg, self.parse_msg, retry_msg, false_msg, e)
                    except Exception as e:
                        raise e
    
        def parse_msg(self, task):
            """      """
            self.retry = self.RETRY_TIMES
            data = task.result()
            msg = data['msg']
            if msg == 'success':
                self.msg = data['data']
            else:
                print('get_user_msg server back_error: ', self.number, msg)
                raise Exception('get_user_msg server back_error: ', self.number, msg)
    
        async def order(self, product_id):
            """  """
            if self.headers and self.msg:
                self.retry -= 1
                data = {
                    "productId": product_id,
                    "phoneNo": self.msg.get('phoneNo', ''),
                    "certNo": self.msg.get('certNo', ''),
                    "preOrderAmt": self.order_amt,
                    "bankInfo": self.msg.get('bankInfo', ''),
                    "bankCode": self.msg.get('bankCode', ''),
                    "introducer": self.msg.get('introducer', ''),
                    "custType": self.msg.get('custType', '')
                }
                async with self.semaphore:
                    try:
                        async with aiohttp.ClientSession() as session:
                            async with session.post(self.urls['order'], json=data, headers=self.headers,
                                                    verify_ssl=False, timeout=self.time_out) as response:
                                if response.status == 200:
                                    return await response.json()
                                else:
                                    return {'msg': 'response_status {}'.format(response.status)}
                    except aiohttp.ServerTimeoutError as e:
                        retry_msg = '{}     '.format(self.number)
                        false_msg = '{}     '.format(self.number)
                        await self._handle_timeout(self.order, self.parse_order, retry_msg, false_msg, e, product_id)
                    except Exception as e:
                        raise e
            else:
                print('{}     :           '.format(self.number))
                raise Exception('{}     :           '.format(self.number))
    
        def parse_order(self, task):
            """         """
            self.retry = self.RETRY_TIMES
            data = task.result()
            print('{}   :{}'.format(self.msg['custName'], data['msg']))
    
        async def _handle_timeout(self, func, callback, retry_msg, false_msg, e, para=None):
            if self.retry:
                print(retry_msg)
                if para:
                    task = asyncio.create_task(func(para))
                else:
                    task = asyncio.create_task(func())
                task.add_done_callback(callback)
                await task
            else:
                print(false_msg)
                self.retry = self.RETRY_TIMES
                raise e
    
    

    users.py
    # -*- coding: utf-8 -*-
    import asyncio
    from pprint import pp
    
    from .user import User
    
    
    class Users:
        """
             
        config:     :  、    、   、     
        """
    
        def __init__(self, config):
            self.users = []
            self.logined, self.not_logined_msg = [], []
            time_out = config['time_out']
            retry_times = config['retry_times']
            semaphore = asyncio.Semaphore(config['concurrent_num'])
    
            for u in config['users']:
                user = User(u['number'], u['pwd'], u['order_amt'], config['urls'], semaphore, time_out, retry_times)
                self.users.append(user)
    
        async def login(self):
            """      ,              """
            tasks = []
            for user in self.users:
                task = asyncio.create_task(user.login())
                task.add_done_callback(user.parse_login)
                tasks.append(task)
            await asyncio.gather(*tasks)
    
            self.logined = [user for user in self.users if user.token]
            self.not_logined_msg = ['{}: {}'.format(user.number, user.login_msg) for user in self.users if
                                    user.token is None]
            if self.not_logined_msg:
                print('

    \t{}'
    .format('
    \t'
    .join(self.not_logined_msg))) async def get_logined_users_msg(self): """ """ tasks = [] for user in self.logined: task = asyncio.create_task(user.get_msg()) task.add_done_callback(user.parse_msg) tasks.append(task) await asyncio.gather(*tasks) def show_logined_users(self): """ """ print(' :{} '.format(len(self.logined))) for user in self.logined: pp(user.msg) print('
    '
    ) async def order(self, product_id): """ """ tasks = [] for user in self.logined: task = asyncio.create_task(user.order(product_id)) task.add_done_callback(user.parse_order) tasks.append(task) await asyncio.gather(*tasks)

    orderer.py
    # -*- coding: utf-8 -*-
    from .users import Users
    
    
    class Orderer:
        """
              
        """
    
        def __init__(self, config):
            self.product_id = ''
            self.users = Users(config)
    
        async def go(self):
            """       :  、           """
            await self.users.login()
            await self.users.get_logined_users_msg()
            await self.run()
    
        async def run(self):
            """        """
            while True:
                print('

    \t[1]-
    \t[2]- ID
    \t[3]- ({})
    \t[4]- '
    .format(self.product_id)) choice = input(' :') if choice == '1': self.users.show_logined_users() elif choice == '2': self.product_id = input(' ID: ') elif choice == '3': if not self.product_id: print('
    *** ID ***'
    ) else: await self.users.order(self.product_id) elif choice == '4': break else: print('
    *** ***'
    )

    main.py
    # -*- coding: utf-8 -*-
    """
             V3
    2020-05-27
      :     (5 )  
    2020-05-22
      :     
      :             、urls、   
    """
    import os
    import asyncio
    from orderer import Orderer
    from tools import init_logger, get_config
    
    logger = init_logger('Production')
    config_file = os.path.join(os.path.dirname(__file__), 'config.json')
    
    if __name__ == '__main__':
        try:
            config = get_config(config_file)
            order = Orderer(config)
            asyncio.run(order.go())
        except Exception as e:
            logger.error(e, exc_info=True)
            print(e)
            input('      ')