예제 #1
0
class XmlyFMLogin:

    def __init__(self, username: str = None, password: str = None):
        self.site = 'xmly'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Host': 'www.ximalaya.com',
            'Referer': 'https://www.ximalaya.com/',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }

        # 密码错误重置初始化
        self.reset_flag = False

        with open('signature.js', 'rb') as f:
            js = f.read().decode()

        self.ctx = execjs.compile(js)

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def check_islogin(self, cookies):
        res = self.session.get('https://www.ximalaya.com/revision/main/getCurrentUser', cookies=cookies).json()
        if res['ret'] == 200:
            nickname = res['data']['nickname']
            self.logger.info('登录成功!')
            self.logger.info('Hello, {}! '.format(nickname))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        return False

    def _get_token(self):
        url = 'https://www.ximalaya.com/passport/token/login'
        res = self.session.get(url).json()
        if res['ret'] == 0:
            return res['token']
        return False

    def _get_signature(self, params):
        return self.ctx.call('get_signature', params)

    def _encrypt_pwd(self, token):
        return self.ctx.call('encrypwd', self.password, token)

    def _verify_account(self, token):
        """
        验证账号是否存在
        :return:
        """
        api = 'https://www.ximalaya.com/passport/login/checkAccount'

        data = {
            'email': self.username,
            'nonce': token,
        }

        params = ''
        for key, value in data.items():
            params += key + '=' + value + '&'
        params += "e1996c7d6e0ff0664b28af93a2eeff8f8cae84b2402d158f7bb115b735a1663d"
        signature = self._get_signature(params)

        data.update({
            'signature': signature
        })

        res = self.session.post(api, data=data).json()
        if res['success']:
            return True
        return False

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        模拟登录
        :return:
        """
        api = 'https://www.ximalaya.com/passport/v4/security/popupLogin'
        token = self._get_token()

        if token:
            if not self._verify_account(token):
                self.logger.error('账号不存在! ')
                return False

        # token 是一次性的
        token = self._get_token()
        if token:
            encrypt_pwd = self._encrypt_pwd(token)

            data = {
                'password': encrypt_pwd,
                'rememberMe': 'true',
                'account': self.username
            }

            res = self.session.post(api, data=data)
            cookies = res.cookies.get_dict()
            if self.check_islogin(cookies):
                return cookies
            if res.json()['errorMsg'] == '账号或密码不正确!':
                self.reset_flag = True
                raise Exception('账号或密码错误! ')
            raise Exception('登录失败: {} '.format(res.json()['errorMsg']))

    @check_user()
    def run(self, load_cookies=True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login()
예제 #2
0
class ZhipinLogin:

    def __init__(self, username: str = None, password: str = None):
        self.site = 'zhipin'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)

    async def check_islogin(self, cookies):
        """
        检查登录状态: 访问首页, 出现用户名则登录成功
        :param page:
        :return:
        """

        url = 'https://www.zhipin.com/geek/new/index/recommend?ka=header-personal'

        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299'
        }

        res = requests.get(url, headers=headers, cookies=cookies)

        if '登录' not in res.text:
            self.logger.info('Cookies 有效! ')
            nickname = re.search('name:"(.*?)"', res.text).group(1)
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        return False

    @staticmethod
    def input_time_random():
        return random.randint(150, 201)

    def retry_if_result_none(self, result):
        self.logger.warning('滑块判定失败, 重试!')
        return result is None

    async def login(self):

        browser = await launch(
            {
                'headless': False,
                'args': ['--no-sandbox', '--disable-infobars'],
            },
            # userDataDir=r'D:\login\userdata',   # 这个文件会记录pyppeteer浏览器的cookie
            args=['--window-size=1366, 768']
        )
        page = await browser.newPage()  # 启动个新的浏览器页面
        await page.setJavaScriptEnabled(enabled=True)  # 启用js
        await page.setUserAgent(
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299'
        )  # 设置模拟浏览器

        self.logger.info('尝试登录...')

        await page.goto('https://www.zhipin.com/user/login.html')
        await self.page_evaluate(page)

        time.sleep(2)

        time.sleep(1)
        await page.type('input[name="account"]', self.username, {'delay': self.input_time_random() - 50})
        time.sleep(1)
        await page.type('input[name="password"]', self.password, {'delay': self.input_time_random()})

        # await page.screenshot({'path': './headless-test-result.png'})   # 截图测试
        time.sleep(2)

        self.logger.info('拉动滑块验证...')
        # await page.screenshot({'path': './headless-login-slide.png'})   # 截图测试
        flag = await self.mouse_slide(page=page)  # js拉动滑块
        if flag:
            # await page.keyboard.press('Enter')
            await page.click('button.btn')
            await page.waitFor(20)
            await page.waitForNavigation()  # 等待跳转
            try:
                global error
                error = await page.Jeval('.dialog-con', 'node => node.textContent')  # 检测是否是账号密码错误
            except Exception as e:
                error = None
                self.logger.info("登录成功! ")
            finally:
                if error:
                    error = await (await (await page.xpath('//div[@class="dialog-con"]'))[0].getProperty('textContent')).jsonValue()
                    self.logger.info(error)
                else:
                    await asyncio.sleep(3)
                    cookies = await page.cookies()
                    # cookies = {item['name']: item['value'] for item in cookies}
                    self.redis_client.save_cookies(self.site, self.username, cookies)
        else:
            self.logger.error('验证失败! ')

        await self.page_close(browser)

    async def page_evaluate(self, page):

        await page.evaluate(
            '''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => undefined } }) }''')  # 以下为插入中间js,将淘宝会为了检测浏览器而调用的js修改其结果。
        await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')
        await page.evaluate(
            '''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')
        await page.evaluate(
            '''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')

    async def page_close(self, browser):
        """
        关闭浏览器驱动
        :param browser:
        :return:
        """
        for _page in await browser.pages():
            await _page.close()
        await browser.close()

    # @retry(retry_on_result=retry_if_result_none, )
    async def mouse_slide(self, page=None):
        await asyncio.sleep(3)
        try:
            # 鼠标移动到滑块,按下,滑动到头(然后延时处理),松开按键
            await page.hover('.btn_slide')
            await page.mouse.down()  # 模拟按下鼠标
            await page.mouse.move(2000, 0, {'delay': random.randint(1000, 2000)})  # js模拟拖动
            await page.mouse.up()  # 模拟松开鼠标
        except Exception as e:
            return None, page
        else:
            await asyncio.sleep(2)
            slider_again = await page.Jeval('.nc-lang-cnt', 'node => node.textContent')  # 判断是否通过
            if slider_again != '验证通过':
                return None, page
            else:
                # await page.screenshot({'path': './headless-slide-result.png'}) # 截图测试
                self.logger.info('验证通过! ')
                return 1, page

    @check_user()
    async def run(self, load_cookies: bool = True):
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            cookies = {item['name']: item['value'] for item in cookies}
            if cookies:
                if await self.check_islogin(cookies):
                    return True
                self.logger.warning('cookies 已过期! ')

        await self.login()
예제 #3
0
class LOLLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'lol'
        self.username = username
        self.password = password
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Connection':
            'keep-alive',
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Firefox/68.0'
        }
        # 密码错误重置初始化
        self.reset_flag = False

        with open('encrypt.js', 'rb') as f:
            js = f.read().decode()
        self.ctx = execjs.compile(js)

    def check_islogin(self, cookies):
        params = {
            'use':
            'zm,uid,acc',
            'area':
            '19',
            'season':
            's9',
            'callback':
            'jQuery191005632563829884707_{}'.format(int(time.time() * 1000)),
            '_':
            int(time.time() * 1000)
        }
        url = 'https://lol.ams.game.qq.com/lol/autocms/v1/transit/LOL/LOLWeb/Official/MobilePlayerInfo,PlayerCommunityInfo,PlayerInfo,PlayerBattleSummary,PlayerHonor,PlayerProperty,PlayerRankInfo?' + urlencode(
            params)
        res = self.session.get(url, cookies=cookies)
        result = json.loads(
            re.search(r'{}\((.*?)\)'.format(params['callback']),
                      res.text).group(1))
        if result['MobilePlayerInfo']['status'] == 0:
            self.logger.info('Cookies 有效! ')
            nickname = result['MobilePlayerInfo']['msg']['res'][
                'uuid_prifle_list'][0]['nick']
            self.logger.info('Hello, {}! '.format(nickname))
            gamename = result['PlayerInfo']['msg']['name']
            self.logger.info('你的游戏昵称: {}'.format(gamename))
            self.logger.info('查看战绩请按 1, 结束请按 0 >>')
            flag = int(input())
            if flag:
                seasons = result['PlayerBattleSummary']['msg']['data'][
                    'item_list']
                for season in seasons:
                    self.logger.info(season)
                return True
            return True
        return False

    def _init_cookies(self):
        self.session.get('https://mail.qq.com/')

    def _get_login_sig(self):
        res = self.session.get(
            'https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https://game.qq.com/comm-htdocs/milo/proxy.html&appid=21000501&target=top&s_url=https%3A%2F%2Flol.qq.com%2Fmain.shtml&style=20&daid=8'
        )
        cookies = res.cookies.get_dict()
        login_sig = cookies['pt_login_sig']
        return cookies, login_sig

    def _get_salt(self, login_sig):
        url = 'https://ssl.ptlogin2.qq.com/check?'

        params = {
            'regmaster': '',
            'pt_tea': '2',
            'pt_vcode': '1',
            'uin': self.username,
            'appid': 21000501,
            'js_ver': '19072517',
            'js_type': 1,
            'login_sig': login_sig,
            'u1': 'https://lol.qq.com/main.shtml',
            'r': self.ctx.call('get_random_num'),
            'pt_uistyle': '40'
        }

        res = self.session.get(url, params=params)
        pt_verifysession_v1 = res.text.split(',')[3].replace("'", '')
        verify_code = res.text.split(',')[1].replace("'", '')
        salt = res.text.split(',')[2].replace("'", '')
        salt = salt.encode().decode('unicode_escape')
        ptdrvs = res.text.split(',')[5].replace("'", '').replace(')',
                                                                 '').strip()

        return pt_verifysession_v1, verify_code, salt, ptdrvs

    def _encrypt_pwd(self, salt, verify_code):
        return self.ctx.call('encrypt_pwd', self.password, salt, verify_code)

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        self._init_cookies()
        login_api = 'https://ssl.ptlogin2.qq.com/login?'

        login_sig = self._get_login_sig()

        pt_verifysession_v1, verify_code, salt, ptdrvs = self._get_salt(
            login_sig)
        pwd = self._encrypt_pwd(salt, verify_code)

        params = {
            'u': self.username,
            'verifycode': verify_code,
            'pt_vcode_v1': '0',
            'pt_verifysession_v1': pt_verifysession_v1,
            'p': pwd,
            'pt_randsalt': '2',
            'u1': 'https://lol.qq.com/main.shtml',
            'ptredirect': '1',
            'h': '1',
            't': '1',
            'g': '1',
            'from_ui': '1',
            'ptlang': '2052',
            'action': f'1-0-{int(time.time() * 1000)}',
            'js_ver': '19072517',
            'js_type': '1',
            'login_sig': login_sig,
            'pt_uistyle': '40',
            'aid': 21000501,
            'daid': '8',
            'ptdrvs': ptdrvs,
            '': ''
        }

        res = self.session.get(login_api, params=params)
        result = re.search(r'ptuiCB\((.*?)\)',
                           res.text).group(1).replace("'", '')
        result = result.split(',')

        if result[0] == '0':
            url = result[2]
            resp = self.session.get(url, allow_redirects=False)
            if resp.status_code == 302 and resp.headers[
                    'location'] == 'https://lol.qq.com/main.shtml':
                self.logger.info('登录成功! ')
                nickname = result[-1]
                self.logger.info('Hello, {}! '.format(nickname))
                cookies = resp.cookies.get_dict()
                self.redis_client.save_cookies(self.site, self.username,
                                               cookies)
                return True
            raise Exception('登录失败! ')
        elif '密码不正确' in result[-2]:
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        elif '二维码登录' in res.text:
            self.logger.warning('为了更好的保护您的QQ,请使用扫描二维码登录! ')
            return False
        raise Exception('登录失败: {} '.format(result[-2]))

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.warning('Cookies 已过期')

        self.login()
예제 #4
0
class IQiyiLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'iqiyi'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Accept':
            'application/json, text/javascript, */*; q=0.01',
            'Content-Type':
            'application/x-www-form-urlencoded; charset=UTF-8',
            'Origin':
            'http://www.iqiyi.com',
            'Referer':
            'http://www.iqiyi.com/iframe/loginreg?ver=1',
            "User-Agent":
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
        }
        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        url = 'http://www.iqiyi.com/u/point'
        res = self.session.get(url, cookies=cookies)
        if 'ucbannerName' in res.text:
            self.logger.info('Cookies 有效! ')
            bsobj = BeautifulSoup(res.text, 'lxml')
            nickname = bsobj.select('#ucbannerName')[0].get_text().strip()
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        return False

    def _encrypt_pwd(self):
        """
        加密密码
        :return:
        """
        with open('iqiyiPwdEncrypt.js', 'r') as f:
            js = f.read()

        ctx = execjs.compile(js)
        return ctx.call('rsaFun', self.password)

    def _get_areacode(self):
        """
        获取地区编码
        :return:
        """
        url = 'https://passport.iqiyi.com/apis/phone/get_support_areacode.action'
        data = {
            'use_case': '1',
            'local': '1',
            'agenttype': '1',
            'fromSDK': '1',
            'ptid': '01010021010000000000',
            'sdk_version': '1.0.0'
        }
        r = self.session.post(url, data=data).json()
        code_dict = r['data']['acode']
        return code_dict

    def get_dfp(self):
        """
        获取页面初始化参数 dfp
        :return:
        """
        url = 'https://cook.iqiyi.com/security/dfp_pcw/sign'

        data = {
            'dim':
            'eyJqbiI6Ik1vemlsbGEvNS4wIChXaW5kb3dzIE5UIDEwLjA7IFdpbjY0OyB4NjQpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS83NS4wLjM3NzAuODAgU2FmYXJpLzUzNy4zNiIsImNtIjoiemgtQ04iLCJndSI6MjQsInVmIjoxLCJqciI6WzEzNjYsNzY4XSwiZGkiOlsxMzY2LDcyOF0sInpwIjotNDgwLCJ1aCI6MSwic2giOjEsImhlIjoxLCJ6byI6MSwicnYiOiJ1bmtub3duIiwibngiOiJXaW4zMiIsIml3IjoidW5rbm93biIsInFtIjpbIkNocm9tZSBQREYgUGx1Z2luOjpQb3J0YWJsZSBEb2N1bWVudCBGb3JtYXQ6OmFwcGxpY2F0aW9uL3gtZ29vZ2xlLWNocm9tZS1wZGZ cGRmIiwiQ2hyb21lIFBERiBWaWV3ZXI6Ojo6YXBwbGljYXRpb24vcGRmfnBkZiIsIk5hdGl2ZSBDbGllbnQ6Ojo6YXBwbGljYXRpb24veC1uYWNsfixhcHBsaWNhdGlvbi94LXBuYWNsfiJdLCJ3ciI6ImI3NzY2NGM3MTcwNzdhZmZmMzNhN2QyODM2ZTIzNzdjIiwid2ciOiJlZDI2NTg5MTM1MTJlNTA5MmZlMjE5NDAwOGQ3OWEwZSIsImZrIjpmYWxzZSwicmciOmZhbHNlLCJ4eSI6ZmFsc2UsImptIjpmYWxzZSwiYmEiOmZhbHNlLCJ0bSI6WzAsZmFsc2UsZmFsc2VdLCJhdSI6dHJ1ZSwibWkiOiI5YmU0OTM0MS05MTI2LTg5MjQtNjc2Ni0xOTA3Y2QxNTYxMDgiLCJjbCI6IlBDV0VCIiwic3YiOiIxLjAiLCJqZyI6IjA3NjQ4M2QwODg2NGMzNTE5MWUyNTVjNjhmNWU2YWE3IiwiZmgiOiJvazZxeWc0cXM5YWw5MTA0YjZ0OTJoODEiLCJpZm0iOltmYWxzZSxudWxsLG51bGwsbnVsbF0sImV4IjoiIiwiZHYiOiJvZmYiLCJwdiI6dHJ1ZX0=',
            'plat': 'PCWEB',
            'ver': '1.0',
            'sig': '785042546DC84608E1DF7430A9AE021C2F6F7955',
            'nifc': 'false'
        }
        result = self.session.post(url, data=data).json()
        if result['code'] == 0:
            dfp = result['result']['dfp']
            print('dfp: {}'.format(dfp))
            expire_time = time.strftime(
                "%H:%M:%S",
                time.localtime(result['result']['expireAt'] -
                               int(time.time() * 1000)))
            print('{} 后过期'.format(expire_time))
            return dfp
        return None

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        登录, 只有一个加密参数密码, 其他为定值
        :return:
        """
        url = 'https://passport.iqiyi.com/apis/reglogin/login.action'

        encrypt_pwd = self._encrypt_pwd()

        dfp = self.get_dfp()
        data = {
            'email':
            self.username,
            'fromSDK':
            '1',
            'sdk_version':
            '1.0.0',
            'passwd':
            encrypt_pwd,
            'agenttype':
            '1',
            '__NEW':
            '1',
            'checkExist':
            '1',
            'lang':
            '',
            'ptid':
            '01010021010000000000',
            'nr':
            '1',
            'verifyPhone':
            '1',
            'area_code':
            '86',
            # 'env_token': 'c225a3e03fdf4c90a9227af2f0abd8bb',
            'dfp':
            dfp,
            'envinfo':
            'eyJqbiI6Ik1vemlsbGEvNS4wIChXaW5kb3dzIE5UIDEwLjA7IFdpbjY0OyB4NjQpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS83NS4wLjM3NzAuODAgU2FmYXJpLzUzNy4zNiIsImNtIjoiemgtQ04iLCJndSI6MjQsInVmIjoxLCJqciI6WzEzNjYsNzY4XSwiZGkiOlsxMzY2LDcyOF0sInpwIjotNDgwLCJ1aCI6MSwic2giOjEsImhlIjoxLCJ6byI6MSwicnYiOiJ1bmtub3duIiwibngiOiJXaW4zMiIsIml3IjoidW5rbm93biIsInFtIjpbIkNocm9tZSBQREYgUGx1Z2luOjpQb3J0YWJsZSBEb2N1bWVudCBGb3JtYXQ6OmFwcGxpY2F0aW9uL3gtZ29vZ2xlLWNocm9tZS1wZGZ cGRmIiwiQ2hyb21lIFBERiBWaWV3ZXI6Ojo6YXBwbGljYXRpb24vcGRmfnBkZiIsIk5hdGl2ZSBDbGllbnQ6Ojo6YXBwbGljYXRpb24veC1uYWNsfixhcHBsaWNhdGlvbi94LXBuYWNsfiJdLCJ3ciI6ImI3NzY2NGM3MTcwNzdhZmZmMzNhN2QyODM2ZTIzNzdjIiwid2ciOiJlZDI2NTg5MTM1MTJlNTA5MmZlMjE5NDAwOGQ3OWEwZSIsImZrIjpmYWxzZSwicmciOmZhbHNlLCJ4eSI6ZmFsc2UsImptIjpmYWxzZSwiYmEiOmZhbHNlLCJ0bSI6WzAsZmFsc2UsZmFsc2VdLCJhdSI6dHJ1ZSwibWkiOiI5YmU0OTM0MS05MTI2LTg5MjQtNjc2Ni0xOTA3Y2QxNTYxMDgiLCJjbCI6IlBDV0VCIiwic3YiOiIxLjAiLCJqZyI6IjA3NjQ4M2QwODg2NGMzNTE5MWUyNTVjNjhmNWU2YWE3IiwiZmgiOiJvazZxeWc0cXM5YWw5MTA0YjZ0OTJoODEiLCJpZm0iOltmYWxzZSxudWxsLG51bGwsbnVsbF0sImV4IjoiIiwiZHYiOiJvZmYiLCJwdiI6dHJ1ZX0='
        }

        while True:
            res = self.session.post(url, data=data)
            cookies = res.cookies.get_dict()
            if res.json()['code'] == 'A00000':
                self.logger.info('登录成功! ')
                self.logger.info('Hello, {}! '.format(
                    res.json()['data']['nickname']))
                self.redis_client.save_cookies(self.site, self.username,
                                               cookies)
                return cookies
            elif res.json()['code'] == 'P00117':
                self.reset_flag = True
                raise Exception('账号或密码错误! ')
            token = res.json()['data']['data']['token']
            data.update({'env_token': token})
            self.logger.info(f'{res.json()["msg"]}, env_token更新为: {token}')
            time.sleep(random.random())

    def get_userinfo(self, cookies):
        """
        获取用户信息
        :return:
        """
        url = 'https://passport.iqiyi.com/apis/user/info.action'
        code_dict = self._get_areacode()
        with open('antiCsrf.js', 'rb') as f:
            js = f.read().decode()
        ctx = execjs.compile(js)

        try:
            auth_cookie = cookies['P00001']
            anticsrf = ctx.call('getAnticsrf', auth_cookie)

            data = {
                'agenttype': '1',
                'ptid': '01010021010000000000',
                'lang': '',
                'fromSDK': '1',
                'sdk_version': '1.0.0',
                'authcookie': auth_cookie,
                'antiCsrf': anticsrf,
                'fields': 'insecure_account,userinfo'
            }

            r = requests.post(url, data=data)
            user_info = r.json()['data']['userinfo']
            jointime = time.strftime(
                "%Y-%m-%d %H:%M:%S",
                time.localtime(int(user_info['jointime'])))
            if user_info['gender'] == 1:
                gender = '男'
            else:
                gender = '女'
            area_code = user_info['area_code']
            for code in code_dict.keys():
                if area_code == code:
                    area = code_dict[code]
                    if user_info['birthday']:
                        birthday = time.strftime(
                            "%Y-%m-%d %H:%M:%S",
                            time.localtime(int(user_info['birthday'])))
                        user_info.update({
                            'birthday': birthday,
                            'jointime': jointime,
                            'gender': gender,
                            'area': area
                        })
            # 移除地区代码
            del user_info['area_code']
            self.logger.info(f'您的基本信息为: {user_info}')
            return True
        except:
            return False

    @check_user()
    def run(self, load_cookies: bool = True):
        """
        主函数
        :return:
        """
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    info_flag = input('是否显示用户信息? (yes/no) \n')
                    if info_flag == 'yes':
                        self.get_userinfo(cookies)
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login()
예제 #5
0
class IQiyiLogin:

    def __init__(self, username: str = None, password: str = None):
        self.site = 'iqiyi'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Accept': 'application/json, text/javascript, */*; q=0.01',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'Origin': 'http://www.iqiyi.com',
            'Referer': 'http://www.iqiyi.com/iframe/loginreg?ver=1',
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
        }
        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        url = 'http://www.iqiyi.com/u/point'
        res = self.session.get(url, cookies=cookies)
        if 'ucbannerName' in res.text:
            self.logger.info('Cookies 有效! ')
            bsobj = BeautifulSoup(res.text, 'lxml')
            nickname = bsobj.select('#ucbannerName')[0].get_text().strip()
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        return False

    def _encrypt_pwd(self):
        """
        加密密码
        :return:
        """
        with open('iqiyiPwdEncrypt.js', 'r') as f:
            js = f.read()

        ctx = execjs.compile(js)
        return ctx.call('rsaFun', self.password)

    def _get_areacode(self):
        """
        获取地区编码
        :return:
        """
        url = 'https://passport.iqiyi.com/apis/phone/get_support_areacode.action'
        data = {
            'use_case': '1',
            'local': '1',
            'agenttype': '1',
            'fromSDK': '1',
            'ptid': '01010021010000000000',
            'sdk_version': '1.0.0'
        }
        r = self.session.post(url, data=data).json()
        code_dict = r['data']['acode']
        return code_dict

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        登录, 只有一个加密参数密码, 其他为定值
        :return:
        """
        url = 'https://passport.iqiyi.com/apis/reglogin/login.action'

        encrypt_pwd = self._encrypt_pwd()

        data = {
            'email': self.username,
            'fromSDK': '1',
            'sdk_version': '1.0.0',
            'passwd': encrypt_pwd,
            'agenttype': '1',
            '__NEW': '1',
            'checkExist': '1',
            'lang': '',
            'ptid': '01010021010000000000',
            'nr': '1',
            'verifyPhone': '1',
            'area_code': '86',
            'env_token': 'c225a3e03fdf4c90a9227af2f0abd8bb',
            'dfp': 'a06e54c2dfe5d24ebf8aec1c2d0a8f5afb2fc70fd2a147f7ab9e5aea7cff440f9e',
            'envinfo': 'eyJqbiI6Ik1vemlsbGEvNS4wIChXaW5kb3dzIE5UIDEwLjA7IFdPVzY0OyBydjo2Ny4wKSBHZWNrby8yMDEwMDEwMSBGaXJlZm94LzY3LjAiLCJjbSI6InpoLUNOIiwiZ3UiOjI0LCJ1ZiI6MSwianIiOlsxMzY2LDc2OF0sImRpIjpbMTM2Niw3MjhdLCJ6cCI6LTQ4MCwidWgiOjEsInNoIjoxLCJoZSI6MSwicnYiOiJ1bmtub3duIiwibngiOiJXaW4zMiIsIml3IjoidW5zcGVjaWZpZWQiLCJxbSI6W10sIndyIjoiOWUzYjk5MzFhNzBiMGQwZDI0NGU1ZTg1MTAyZGJiYTAiLCJ3ZyI6IjRlMzVhYWVjZTM2NTU0YTM5MGQwYWU1MDNlZDljOTM0IiwiZmsiOmZhbHNlLCJyZyI6ZmFsc2UsInh5IjpmYWxzZSwiam0iOmZhbHNlLCJiYSI6ZmFsc2UsInRtIjpbMCxmYWxzZSxmYWxzZV0sImF1Ijp0cnVlLCJtaSI6IjQ1MjY1MDUxLWM3MjItNTcyOC00OGY3LWJiMjA3N2NlMGVhMCIsImNsIjoiUENXRUIiLCJzdiI6IjEuMCIsImpnIjoiNTE3YzNiNDk0NzFlMTJiZTc0N2QzYWI3MWY1YTM1OTMiLCJmaCI6ImhydWtvdjY0OW15OGV1YnB4Ym9uMThuayIsImlmbSI6W3RydWUsNDYwLDQyMCwiaHR0cDovL3d3dy5pcWl5aS5jb20vIl0sImV4IjoiIiwicHYiOmZhbHNlfQ=='
        }

        while True:
            res = self.session.post(url, data=data)
            cookies = res.cookies.get_dict()
            if res.json()['code'] == 'A00000':
                self.logger.info('登录成功! ')
                self.logger.info('Hello, {}! '.format(res.json()['data']['nickname']))
                self.redis_client.save_cookies(self.site, self.username, cookies)
                return True
            elif res.json()['code'] == 'P00117':
                self.reset_flag = True
                raise Exception('账号或密码错误! ')
            token = res.json()['data']['data']['token']
            data.update({'env_token': token})
            self.logger.info(f'{res.json()["msg"]}, env_token更新为: {token}')
            time.sleep(random.random())

    def get_userinfo(self, cookies):
        """
        获取用户信息
        :return:
        """
        url = 'https://passport.iqiyi.com/apis/user/info.action'
        code_dict = self._get_areacode()
        with open('antiCsrf.js', 'rb') as f:
            js = f.read().decode()
        ctx = execjs.compile(js)

        try:
            auth_cookie = cookies['P00001']
            anticsrf = ctx.call('getAnticsrf', auth_cookie)

            data = {
                'agenttype': '1',
                'ptid': '01010021010000000000',
                'lang': '',
                'fromSDK': '1',
                'sdk_version': '1.0.0',
                'authcookie': auth_cookie,
                'antiCsrf': anticsrf,
                'fields': 'insecure_account,userinfo'
            }

            r = requests.post(url, data=data)
            user_info = r.json()['data']['userinfo']
            jointime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(user_info['jointime'])))
            if user_info['gender'] == 1:
                gender = '男'
            else:
                gender = '女'
            area_code = user_info['area_code']
            for code in code_dict.keys():
                if area_code == code:
                    area = code_dict[code]
                    if user_info['birthday']:
                        birthday = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(user_info['birthday'])))
                        user_info.update({'birthday': birthday, 'jointime': jointime, 'gender': gender, 'area': area})
            # 移除地区代码
            del user_info['area_code']
            self.logger.info(f'您的基本信息为: {user_info}')
            return True
        except:
            return False

    @check_user()
    def run(self, load_cookies: bool = True):
        """
        主函数
        :return:
        """
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    info_flag = input('是否显示用户信息? (yes/no) \n')
                    if info_flag == 'yes':
                        self.get_userinfo(cookies)
                    return True
                self.logger.warning('Cookies 已过期')

        self.login()
예제 #6
0
class Email163Login:
    def __init__(self, username: str = None, password: str = None):
        self.site = '163email'
        self.username = username
        self.password = password
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Content-Type':
            'application/json',
            'Origin':
            'https://dl.reg.163.com',
            'Referer':
            'https://dl.reg.163.com/webzj/v1.0.1/pub/index_dl2_new.html?cd=https%3A%2F%2Fmimg.127.net%2Fp%2Ffreemail%2Findex%2Funified%2Fstatic%2F2019%2Fcss%2F&cf=urs.163.bc0e7491.css&MGID=1561887066637.6414&wdaId=&pkid=CvViHzl&product=mail163',
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36',
        }
        with open('encryptEnvinfo.js', 'r') as f:
            self.js = f.read()
        self.ctx = execjs.compile(self.js)
        self.rtid = self.ctx.call('getRtid')

        # 密码错误重试初始化
        self.reset_flag = False

    def check_islogin(self, cookies):

        sid = cookies['sid']

        params = {'sid': sid}
        cookie = cookies['cookies']

        resp = self.session.get('http://mail.163.com/js6/main.jsp?',
                                params=params,
                                cookies=cookie)

        if '收件箱' in resp.text:
            self.logger.info('Cookies 有效! ')

            nickname = re.search("'true_name':'(.*?)'", resp.text).group(1)
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        return False

    def _set_data(self, func):
        """
        配置收件箱接口表单参数
        :return:
        """
        with open('data.html', 'r') as f:
            html = f.read()
        data_list = html.split('<?xml version="1.0"?>')
        if func == 'global:sequential':
            return data_list[1]
        elif func == 'mbox:listMessages':
            return data_list[2]
        elif func == 'mbox:readMessage':
            return data_list[3]
        else:
            self.logger.warning('不支持的接口类型, 有需要请自行添加! ')

    @staticmethod
    def _format_date(text):
        """
        格式化日期
        :param date:
        :return:
        """
        date = re.search(r"new Date\((.*?)\)", text, re.S)
        send_time = '-'.join([
            x for x in date.group(1).split(',')[:3]
        ]) + ' ' + ':'.join([x for x in date.group(1).split(',')[3:]])
        return text.replace(date.group(0), send_time)

    def _read_email(self, cookies):
        """
        查看收件箱: 接口返回的数据是字典样式的原生字符串, demjson 格式化后都无法转为 json 格式... 懒得用正则提取了, 将就看
        :return:
        """
        cookie = cookies['cookies']
        sid = cookies['sid']
        self.session.headers.update({
            'Accept':
            'text/javascript',  # 请求头携带这个参数接口返回的是格式化数据, 没有这个参数返回的html源码
            'Content-type':
            'application/x-www-form-urlencoded'
        })
        url = 'https://mail.163.com/js6/s?'
        func_map = {
            '1': 'global:sequential',
            '2': 'mbox:listMessages',
            '3': 'mbox:readMessage'
        }
        sign_list = []
        all_flag = input('是否查看邮箱整体信息? (yes/任意键跳过) >> \n')
        if all_flag == 'yes':
            all_flag = 1
        else:
            all_flag = 0
        if all_flag:
            sign_list.append('1')
        mailbox_flag = input('是否查看收件箱邮件列表? (yes/任意键跳过) >> \n')
        if mailbox_flag == 'yes':
            mailbox_flag = 1
        else:
            mailbox_flag = 0
        if mailbox_flag:
            sign_list.append('2')
        for sign in sign_list:
            params = {
                'sid': sid,
                'func': func_map[sign],
            }
            data = {'var': self._set_data(func_map[sign])}
            res = self.session.post(url,
                                    params=params,
                                    data=data,
                                    cookies=cookie)
            if sign == '1':
                self.logger.info('邮箱整体信息如下:')
                pprint(res.text)
            elif sign == '2':
                self.logger.info('收件箱邮件列表: ')
                ids = re.findall("'id':'(.*?)'", res.text)
                subjects = re.findall("'subject':'(.*?)'", res.text)
                id_dict = {str(index): id_ for index, id_ in enumerate(ids)}
                subject_dict = {
                    str(index): subject
                    for index, subject in enumerate(subjects)
                }
                if id_dict:
                    pprint(subject_dict)
                    view_flag = input('是否需要查看具体邮件信息? (yes/任意键退出) >> \n')
                    if view_flag == 'yes':
                        view_flag = 1
                    else:
                        view_flag = 0
                    while view_flag:
                        email_num = input('请输入邮件编号(左边数字)>> ')
                        params = {
                            'sid': sid,
                            'func': func_map['3'],
                        }
                        origin_id = re.search('"id">(.*?)<',
                                              self._set_data(
                                                  func_map['3'])).group(1)
                        data = {
                            'var':
                            self._set_data(func_map['3']).replace(
                                origin_id, id_dict[email_num])
                        }
                        resp = self.session.post(url,
                                                 params=params,
                                                 data=data,
                                                 cookies=cookie)
                        result = self._format_date(resp.text)
                        pprint(result)
                        view_flag = int(input('继续查看请按 1 , 退出程序请按 0 >> \n'))
                else:
                    self.logger.info('收件箱列表空空如也~ ')

    def _init_cookies(self):
        """
        初始化 Cookies, 关键 Cookie: l_s_mail163CvViHzl, 有这个 Cookie 拿到 tk
        :return:
        """
        url = 'https://dl.reg.163.com/dl/ini?'
        params = {
            "pd": "mail163",
            "pkid": "CvViHzl",
            "pkht": "mail.163.com",
            "channel": "0",
            "topURL": "https://mail.163.com/",
            "rtid": self.rtid,
            "nocache": int(time.time() * 1000)
        }
        self.session.get(url, params=params)

    def _get_token(self):
        url = 'https://dl.reg.163.com/gt?'

        params = {
            'un': self.username,
            'pkid': 'CvViHzl',
            'pd': 'mail163',
            'channel': 0,
            'topURL': 'https://mail.163.com/',
            'rtid': self.rtid,
            'nocache': int(time.time() * 1000)
        }

        res = self.session.get(url, params=params).json()
        token = res['tk']
        return token

    def _encrypt_pwd(self):
        """
        加密密码
        :return:
        """
        return self.ctx.call('encrypt2', self.password)

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        self._init_cookies()
        tk = self._get_token()

        login_api = 'https://dl.reg.163.com/dl/l'

        data = {
            "un": self.username,
            "pw": self._encrypt_pwd(),
            "pd": "mail163",
            "l": 0,
            "channel": 0,
            "d": 10,
            "t": int(time.time() * 1000),
            "pkid": "CvViHzl",
            "domains": "",
            "tk": tk,
            "pwdKeyUp": 1,
            "topURL": "https://mail.163.com/",
            "rtid": self.rtid
        }

        self.session.headers.update({
            'Cookie':
            'JSESSIONID-WYTXZDL=YuenayJO3PfX%2BYyPmO%2Fhr%2FLeuu67nXDZPl50EOxAi9plAsq%5CKwf%5CZtQUUxOLA%2FxMlf%2FfxzPNLbTGxZaHUPTny%2BehaVqiukV7ed%2Fblp101N%2BGIIGYKZ9ODzLdR5w5eK%5ChGHO%2FFs2z4umi4Wj2xDzvxbm%2F8lTJBlIU6b9bF0FJrdn1%2Be%2Fq%3A1565361595090; l_s_mail163CvViHzl=2BDA1093FDDA9283AD02B57FFFEC7E0E75F576DC05D86CE6F6B6F9518A920CC1446CE99EF410B468FEDA27F8B53F2F93244D4991F985FACFD8D854C5298024A35F4A702F5D8A93285EB127782B2C254290B1202774ECFD0CE880601326AA4B229FF48A285C3118029255EAE3F260AA5A'
        })
        res = self.session.post(login_api, data=json.dumps(data)).json()

        if res['ret'] == '201':
            form_data = {
                "style": "-1",
                "df": "mail163_letter",
                "allssl": "true",
                "net": "",
                "language": "-1",
                "from": "web",
                "race": "",
                "iframe": "1",
                "url2": "https://mail.163.com/errorpage/error163.htm",
                "product": "mail163"
            }

            cookies = 'NTES_SESS=' + self.session.cookies.get_dict(
            )['NTES_SESS']
            self.session.headers.update({'Cookie': cookies})
            resp = self.session.post(
                'https://mail.163.com/entry/cgi/ntesdoor?',
                data=form_data,
                allow_redirects=False)
            redirect_url = resp.headers['location']

            if 'sid' in redirect_url:
                self.logger.info('登录成功! ')
                response = self.session.get(redirect_url)

                # 网易邮箱的关键是这个sid, 是session id 的意思, 有了它就可以爬邮箱了, 当然还要有配套的 Cookie
                cookies_item = {
                    'cookies': resp.cookies.get_dict(),
                    'sid': response.cookies.get_dict()['Coremail.sid']
                }
                self.redis_client.save_cookies(self.site, self.username,
                                               cookies_item)
                try:
                    nickname = re.search("'true_name':'(.*?)'",
                                         response.text).group(1)
                    self.logger.info('Hello, {}! '.format(nickname))
                except:
                    self.logger.info('你还没有设置昵称, 快去设置...')
                return True
            raise Exception('登录失败! ')
        elif res['ret'] == '413':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        elif res['ret'] == '445':
            self.logger.warning('验证码校验...')
            return False
        elif res['ret'] == '409':
            self.logger.warning('登录过于频繁, 请稍后再试! ')
            return False
        elif res['ret'] == '423':
            self.logger.warning('风控账号! ')
            return False
        raise Exception('登录失败! ')

    @check_user()
    def run(self, load_cookies: bool = True):
        if '163.com' not in self.username:
            self.username += '@163.com'
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)

            if cookies:
                if self.check_islogin(cookies):
                    read_flag = input('是否需要查看邮箱? (yes/任意键退出) >> \n')
                    if read_flag == 'yes':
                        self._read_email(cookies)
                    return True
                self.logger.warning('Cookies 已过期')

        self.login()
예제 #7
0
class LiepinLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'liepin'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Referer': 'https://www.liepin.com/',
            'User-Agent':
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
            'DNT': '1',
        }
        # 密码错误重置初始化
        self.reset_flag = False
        self.timestamp = str(int(time.time() * 1000))

    def check_islogin(self, cookies):
        url = 'https://c.liepin.com/main/page.json?'
        res = self.session.get(url, cookies=cookies, allow_redirects=False)
        try:
            result = json.loads(res.text)
            if result['status'] == 0 and result['message'] == 'OK':
                self.logger.info('登录成功!')
                self.logger.info('Hello, {}! '.format(
                    result['data']['userCForm']['c_name']))
                self.redis_client.save_cookies(self.site, self.username,
                                               cookies)
                return True
        except:
            return False

    @staticmethod
    def _loads_jsonp(_jsonp):
        """
        解析jsonp数据格式为json
        :return:
        """
        try:
            return json.loads(re.match(".*?({.*}).*", _jsonp, re.S).group(1))
        except ValueError:
            raise ValueError('Invalid Input')

    def _get_token(self):
        """
        获取用户token和加密js
        :return:
        """

        params = {
            'sign': self.username,
            'callback': 'jQuery171029989774566236793_' + self.timestamp,
            '_': self.timestamp,
        }

        response = self.session.get(
            'https://passport.liepin.com/verificationcode/v1/js.json',
            params=params)

        return self._loads_jsonp(response.text)

    def _encrypt_pwd(self):
        md5 = hashlib.md5()
        md5.update(self.password.encode('utf-8'))
        return md5.hexdigest()

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        模拟登录
        :return:
        """
        result = self._get_token()
        token = result.get('data').get('token')
        js = result.get('data').get('js')

        ctx = execjs.compile(js)
        value = ctx.call('encryptData', self.username)

        pwd = self._encrypt_pwd()

        params = {
            'callback': 'jQuery17108618602708711502_' + self.timestamp,
            'login': self.username,
            'pwd': pwd,
            'token': token,
            'value': value,
            'url': '',
            '_bi_source': '0',
            '_bi_role': '0',
            '_': self.timestamp,
        }

        res = self.session.get(
            'https://passport.liepin.com/account/individual/v1/login.json',
            params=params)
        cookies = res.cookies.get_dict()
        result = json.loads(
            re.search(f'{params["callback"]}\((.*)\)', res.text).group(1))
        if self.check_islogin(cookies):
            return True
        if '密码错误' in res.text:
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败: {}'.format(result['msg']))

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.warning('Cookies 已过期')

        self.login()
예제 #8
0
class YYlogin:

    def __init__(self, username: str = None, password: str = None):
        self.site = 'yy'
        self.username = username
        self.password = password
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Referer': 'http://www.yy.com/',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Firefox/68.0'
        }
        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        url = 'http://www.yy.com/yyweb/user/queryUserInfo.json??callback=jQuery1111045940186663574223_{}'.format(int(time.time() * 1000))
        res = self.session.get(url, cookies=cookies).json()
        if res['resultCode'] == 0:
            self.logger.info('Cookies 有效! ')
            self.logger.info('Hello, {}! '.format(res['data']['nick']))
            return True
        return False

    def _init_cookies(self):
        self.session.get('http://www.yy.com/')

    def _get_url(self):
        while True:
            url = 'http://www.yy.com/login/getSdkAuth?embed=true&cssid=5719_1'
            res = self.session.post(url).json()
            if res['success'] == 1:
                ttokensec = res['ttokensec']
                token_url = res['url']
                return ttokensec, token_url
            time.sleep(random.random())

    def _get_token(self, url):
        res = self.session.get(url)
        oauth_token = re.search('oauth_token: "(.*?)"', res.text, re.S).group(1)
        return oauth_token

    def _encrypt_pwd(self):
        with open('encrypt.js', 'rb') as f:
            js = f.read().decode()

        ctx = execjs.compile(js)
        return ctx.call('encryptPwd', self.password)

    def _get_captcha(self, captcha_id):
        base_url = 'https://captcha.yy.com/pickwords/init.do?'
        params = {
            'appid': 5719,
            'random': int(time.time() * 1000),
            'busiId': 'busiid',
            'captchaId': captcha_id,
            'callback': f'JSONP_{int(time.time() * 1000)}'
        }
        res = self.session.get(base_url, params=params)
        with open('captcha.png', 'wb') as f:
            f.write(res.content)
        # img = Image.open('captcha.png')
        # img.show()

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        login_api = 'https://lgn.yy.com/lgn/oauth/x2/s/login_asyn.do'

        self._init_cookies()
        ttokensec, token_url = self._get_url()
        oauth_token = self._get_token(token_url)
        pwd = self._encrypt_pwd()
        data = {
            'username': self.username,
            'pwdencrypt': pwd,
            'oauth_token': oauth_token,
            'denyCallbackURL': 'http://www.yy.com/login/udbCallback?cancel=1',
            'UIStyle': 'xelogin',
            'appid': 5719,
            'cssid': 5719_1,
            'mxc': '',
            'vk': '',
            'isRemMe': '1',
            'mmc': '',
            'vv': '',
            'hiido': '1'
        }
        res = requests.post(login_api, data=data).json()

        if res['code'] == '0':
            callback_url = res['obj']['callbackURL']
            r_cookies = {"_pwcWyy":"066696ef76ca2f85","cookieDate":"1564841513462","hd_newui":"0.970057832001334","hdjs_session_id":"0.5300241632973548","hdjs_session_time":"1564842336414","hiido_ui":"0.7355867355495954","Hm_lpvt_c493393610cdccbddc1f124d567e36ab":"1564842337","Hm_lvt_c493393610cdccbddc1f124d567e36ab":"1564841491,1564841511,1564842337","udboauthtmptoken":"undefined","udboauthtmptokensec":ttokensec}
            resp = self.session.get(callback_url, cookies=r_cookies)

            if 'loginSuccess' in resp.text:
                final_url = re.search(r"writeCrossmainCookieWithCallBack\('(.*?)',", resp.text).group(1)
                response = self.session.get(final_url)
                if 'write cookie for oauth' in response.text:
                    self.logger.info('登录成功!')
                    cookies = response.cookies.get_dict()
                    self.redis_client.save_cookies(self.site, self.username, cookies)
                    return True
            raise Exception('登录失败! ')
        elif res['code'] == '1000010':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        elif res['code'] == '1000001':
            self.logger.warning(res['msg'])
            captcha_id = re.search('captchaId: "(.*?)",', res['obj']['itvjs'], re.S).group(1)
            self._get_captcha(captcha_id)
        elif res['code'] == '1000003':
            self.logger.warning(res['msg'])
            return False
        raise Exception('登录失败! ')

    @check_user()
    def run(self, load_cookies: bool = True):
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.warning('Cookies 已过期')

        self.login()
예제 #9
0
class MeituanLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'meituan'
        self.username = username
        self.password = password
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)

        self.session = requests.session()
        self.session.headers = {
            'Referer':
            'https://epassport.meituan.com/account/unitivelogin?bg_source=3&service=waimai&platform=2&continue=http://e.waimai.meituan.com/v2/epassport/entry&left_bottom_link=%2Faccount%2Funitivesignup%3Fbg_source%3D3%26service%3Dwaimai%26platform%3D2%26continue%3Dhttp%3A%2F%2Fe.waimai.meituan.com%2Fv2%2Fepassport%2FsignUp%26extChannel%3Dwaimaie%26ext_sign_up_channel%3Dwaimaie&right_bottom_link=%2Faccount%2Funitiverecover%3Fbg_source%3D3%26service%3Dwaimai%26platform%3D2%26continue%3Dhttp%3A%2F%2Fe.waimai.meituan.com%2Fv2%2Fepassport%2FchangePwd',
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
        }
        with open('./js/encrypt_pwd.js', 'rb') as f:
            self.pwd_js = f.read().decode()
        with open('./js/slider.js', 'rb') as f:
            self.slider_js = f.read().decode()
        with open('./js/token.js', 'rb') as f:
            self.token_js = f.read().decode()

        # 密码错误重置初始化
        self.reset_flag = False

    @staticmethod
    def check_islogin(cookies):
        """
        检查是否登录成功
        :return:
        """
        url = 'https://www.meituan.com/ptapi/getLoginedUserInfo'
        result = requests.get(
            url,
            cookies=cookies,
            headers={
                'Referer':
                'https://www.meituan.com/',
                'User-Agent':
                'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
            }).json()
        if 'nickName' in set(result.keys()):
            return True
        return False

    @staticmethod
    def _get_fingerprint():
        # 进入浏览器设置
        options = Options()
        # 设置中文
        options.add_argument('lang=zh_CN.UTF-8')
        options.add_argument('--headless')
        options.add_argument(
            'user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"'
        )
        browser = webdriver.Chrome(options=options)

        browser.get('file:///D:/Meituan/fingerprint.html')
        time.sleep(2)
        html = browser.page_source
        fingerprint = re.search('</script>(.*?)</body>', html).group(1)
        browser.quit()
        return fingerprint

    def _get_token(self, url):
        ctx = execjs.compile(self.token_js)
        return ctx.call('get_token', url)

    def _get_behavior_token(self, page_data):
        ctx = execjs.compile(self.slider_js)
        verify_data = ctx.call('get_behavior_token', page_data)
        return verify_data

    def _encrypt_pwd(self):
        """
        RSA加密密码
        :return:
        """
        ctx = execjs.compile(self.pwd_js)
        pwd = ctx.call('encrypt', self.password)
        return pwd

    def _init_slider(self, requests_code):
        """
        初始化滑块
        :param requests_code:
        :return:
        """
        data = {
            'requestCode': requests_code,
            'feVersion': '1.4.0',
            'source': '1'
        }
        url = 'https://verify.meituan.com/v2/ext_api/page_data'
        result = self.session.post(url, data=data).json()
        if result['status']:
            return result['data']
        return None

    def _slider_verify(self, code, request_code):
        """
        滑块风控验证
        :param code:
        :param request_code:
        :return:
        """
        page_data = None
        for _ in range(5):
            page_data = self._init_slider(request_code)
            if page_data:
                break
        if not page_data:
            raise Exception('滑块初始化失败! ')

        url = 'https://verify.meituan.com/v2/ext_api/merchantlogin/verify?id=71'

        verify_data = self._get_behavior_token(page_data)
        self.session.headers.update({
            'Authorization': 'Bearer ' + request_code,
            'Content-Type': 'application/x-www-form-urlencoded',
            'Origin': 'https://epassport.meituan.com',
        })
        data = {
            'request_code': request_code,
            'behavior': verify_data['behavior'],
            'fingerprint': '',
            '_token': verify_data['token'],
        }
        result = self.session.post(url, data=data).json()
        if result['status']:
            self.logger.info('成功通过滑块验证!')
            if code == 121060:
                return code
            elif code == 101190:
                return result['data']['response_code']
            else:
                raise Exception('未知类型请求! ')
        raise Exception('滑块验证失败! ')

    def _init_captcha(self, request_code):
        url = 'https://verify.meituan.com/v2/captcha?'
        params = {
            'request_code': request_code,
            'action': 'login',
            'randomId': '0.6868395303586443',
            '_token': self._get_token(url)
        }
        resp = self.session.get(url, params=params)
        with open('captcha.png', 'wb') as f:
            f.write(resp.content)

        img = Image.open('captcha.png')
        img.show()
        verify_code = input('验证码  >> \n')

        return verify_code

    def _captcha_verify(self, code, verify_code):
        """
        图文识别验证码
        :param code:
        :param verify_code:
        :return:
        """
        url = 'https://verify.meituan.com/v2/ext_api/login/verify?id=1'

        data = {
            'id': '71',
            'request_code': code,
            'captchacode': verify_code,
            '_token': self._get_token(url)
        }

        resp = self.session.post(url, data=data).json()
        if resp['status'] == 1:
            return resp['data']['response_code']
        return None

    def _init_smscode(self, request_code):
        """
        请求手机验证码接口
        :return:
        """
        url = 'https://verify.meituan.com/v2/ext_api/loginverification/info?id=4'
        data = {
            'request_code': request_code,
            'mobile': '',
            'moduleEnable': 'true',
            'listIndex': 0,
            '_token': self._get_token(url)
        }
        resp = self.session.post(url, data=data).json()
        if resp['status'] == 0:
            msg = resp['error']['message']
            self.logger.warning(msg)
            code = resp['error']['code']
            request_code = resp['error']['request_code']
            success = self._slider_verify(code, request_code)
            if success:
                return True
            return False
        elif resp['status'] == 1:
            return True
        return False

    def _smscode_verify(self, request_code):
        """
        发送手机验证码
        :return:
        """
        success = False
        for _ in range(5):
            success = self._init_smscode(request_code)
            if success:
                break
        if not success:
            raise Exception('手机验证码接口请求失败! ')

        url = 'https://verify.meituan.com/v2/ext_api/loginverification/verify?id=4'
        time.sleep(30)
        sms_code = input('请输入手机验证码  >> \n')
        data = {
            'mobile': '',
            'request_code': request_code,
            'smscode': sms_code,
            'listIndex': 0,
            '_token': self._get_token(url)
        }
        resp = self.session.post(url, data=data).json()
        if resp['status'] == 1:
            self.logger.info('成功通过手机验证! ')
            return resp['data']['response_code']
        raise Exception('手机验证失败! ')

    def _get_csrf(self):
        """
        获取认证Csrf参数
        :return:
        """
        url = 'https://passport.meituan.com/account/unitivelogin?service=www&continue=https%3A%2F%2Fwww.meituan.com%2Faccount%2Fsettoken%3Fcontinue%3Dhttp%253A%252F%252Fcd.meituan.com%252F'

        resp = self.session.get(url)
        soup = BeautifulSoup(resp.text, 'lxml')
        csrf = soup.select('input[name="csrf"]')[0]['value']

        return csrf

    def login(self, csrf, request_code='', response_code=''):
        """
        模拟登录
        :return:
        """
        login_api = 'https://passport.meituan.com/account/unitivelogin?risk_partner=0&risk_platform=1&risk_app=-1&uuid=ea8b149299ce4622b486.1568870998.1.0.0&service=www&continue=https%3A%2F%2Fwww.meituan.com%2Faccount%2Fsettoken%3Fcontinue%3Dhttps%253A%252F%252Fhf.meituan.com%252F'

        pwd = self._encrypt_pwd()

        self.session.headers.update({
            'Referer':
            'https://passport.meituan.com/account/unitivelogin?service=www&continue=https%3A%2F%2Fwww.meituan.com%2Faccount%2Fsettoken%3Fcontinue%3Dhttp%253A%252F%252Fcd.meituan.com%252F',
            'X-CSRF-Token': csrf,
            'X-Client': 'javascript',
            'X-Requested-With': 'XMLHttpRequest',
        })
        if 'Authorization' in set(self.session.headers):
            del self.session.headers['Authorization']
        data = {
            'countrycode': '86',
            'email': self.username,
            'password': pwd,
            'origin': 'account-login',
            'csrf': csrf,
            'requestCode': request_code,
            'responseCode': response_code,
            'h5Fingerprint': ''
        }
        result = self.session.post(login_api, data=data).json()

        return result

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login_process(self):
        """
        整体登录流程
        :return:
        """
        csrf = self._get_csrf()
        result = self.login(csrf)
        if 'data' in set(result.keys()):
            self.logger.info('登录成功! ')
            # token = result['data']['token']
            nickname = result['data']['userName']
            self.logger.info('Hello, {}! '.format(nickname))
            cookies = self.session.cookies.get_dict()
            if self.check_islogin(cookies):
                self.logger.info('Cookies 有效! ')
                self.redis_client.save_cookies(self.site, self.username,
                                               cookies)
                return cookies
            else:
                raise Exception('登录失败! ')
        else:
            if result['error']['code'] == 101190:
                msg = result['error']['message']
                self.logger.warning(msg)
                code = result['error']['code']
                request_code = result['error']['data']['requestCode']
                response_code = self._slider_verify(code, request_code)
                result = self.login(csrf, request_code, response_code)
                if result['success']:
                    self.logger.info('登录成功! ')
                    nickname = result['data']['userName']
                    self.logger.info('Hello, {}! '.format(nickname))
                    cookies = self.session.cookies.get_dict()
                    if self.check_islogin(cookies):
                        self.logger.info('Cookies 有效! ')
                        self.redis_client.save_cookies(self.site,
                                                       self.username, cookies)
                        return cookies
                    else:
                        raise Exception('登录失败! ')
                else:
                    if result['error']['code'] == 101157:
                        msg = result['error']['message'].replace('验证', '手机验证')
                        self.logger.warning(msg)
                        request_code = result['error']['data']['param'].split(
                            '&')[1].split('=')[1]
                        response_code = self._smscode_verify(request_code)
                        result = self.login(request_code, response_code)
                        if result.get('data', 0):
                            self.logger.info('登录成功! ')
                            nickname = result['data']['userName']
                            self.logger.info('Hello, {}! '.format(nickname))
                            cookies = self.session.cookies.get_dict()
                            if self.check_islogin(cookies):
                                self.logger.info('Cookies 有效! ')
                                self.redis_client.save_cookies(
                                    self.site, self.username, cookies)
                                return cookies
                            else:
                                raise Exception('Cookies 失效! ')
                        else:
                            raise Exception('登录失败! ')
                    elif result['error']['code'] == 101135:
                        msg = result['error']['message']
                        self.logger.warning(msg)
                        return None
                    else:
                        raise Exception('登录失败: ', result['error']['message'])
            elif result['error']['code'] == 101157:
                msg = result['error']['message'].replace('验证', '手机验证')
                self.logger.warning(msg)
                request_code = result['error']['data']['param'].split(
                    '&')[1].split('=')[1]
                response_code = self._smscode_verify(request_code)
                result = self.login(request_code, response_code)
                if result.get('data', 0):
                    self.logger.info('登录成功! ')
                    nickname = result['data']['userName']
                    self.logger.info('Hello, {}! '.format(nickname))
                    cookies = self.session.cookies.get_dict()
                    if self.check_islogin(cookies):
                        self.logger.info('Cookies 有效! ')
                        self.redis_client.save_cookies(self.site,
                                                       self.username, cookies)
                        return cookies
                    else:
                        raise Exception('Cookies 失效! ')
                else:
                    raise Exception('登录失败! ')
            elif result['error']['code'] == 101135:
                msg = result['error']['message']
                self.logger.warning(msg)
                return None
            raise Exception('登录失败: ', result['error']['message'])

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login_process()
예제 #10
0
class MiguLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'migu'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Referer':
            'https://passport.migu.cn/login?sourceid=220001&apptype=0&forceAuthn=false&isPassive=false&authType=MiguPassport&passwordControl=0&display=web&referer=http://music.migu.cn/v3&logintype=1&qq=null&weibo=null&alipay=null&weixin=null&phoneNumber=&callbackURL=http%3A%2F%2Fmusic.migu.cn%2Fv3&relayState=',
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36',
            'X-Requested-With': 'XMLHttpRequest'
        }
        # 密码错误重置初始化
        self.reset_flag = False
        self.ctx = self._load_js()

    def check_islogin(self, cookies):
        res = self.session.get('http://music.migu.cn/v3/my', cookies=cookies)
        html = res.content.decode(chardet.detect(res.content)['encoding'])
        if '我的收藏' in html:
            bsobj = BeautifulSoup(html, 'lxml')
            nickname = bsobj.find('h4', {
                'class': 'nickname'
            }).get_text().strip()
            self.logger.info('登录成功!')
            self.logger.info('Hello, {}! '.format(nickname))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        return False

    def _load_js(self):
        """
        加载编译js文件
        :return:
        """
        with open('encrypt.js', 'rb') as f:
            js = f.read().decode()
        ctx = execjs.compile(js)
        return ctx

    def encrypt_pwd(self):
        """
        RSA加密密码
        :return:
        """
        encrypt_pwd = self.ctx.call('encryptPwd', self.password)
        # print('加密密码', encrypt_pwd)
        return encrypt_pwd

    def _get_fingerprint(self):
        """
        获取浏览器指纹
        :return:
        """
        finger_print = self.ctx.call('getFingerprint')
        # print('浏览器指纹', finger_print)
        return finger_print

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def _get_token(self):
        """
        模拟登录
        :return:
        """
        login_api = 'https://passport.migu.cn/authn'

        data = {
            'sourceID': '220001',
            'appType': '0',
            'relayState': '',
            'loginID': self.username,
            'enpassword': self.encrypt_pwd(),
            'captcha': '',
            'imgcodeType': '1',
            'rememberMeBox': '1',
            'fingerPrint': self._get_fingerprint()['result'],
            'fingerPrintDetail': self._get_fingerprint()['details'],
            'isAsync': 'true'
        }

        res = self.session.post(login_api, data=data).json()
        if res['status'] == 2000:
            token = res['result']['token']
            return token
        elif res['message'] == '密码验证未通过' or res['message'] == '帐号或密码错误':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败: ', res['message'])

    def login(self):
        """
        登录认证
        :return:
        """
        token = self._get_token()

        if token:
            params = {'callbackURL': '', 'relayState': '', 'token': token}

            res = self.session.get('http://music.migu.cn/v3/user/login?',
                                   params=params)
            cookies = res.cookies.get_dict()
            if self.check_islogin(cookies):
                return True
            return False

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.warning('Cookies 已过期')

        self.login()
예제 #11
0
class WeiboLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'weibo'
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)
        self.username = username
        self.password = password
        self.session = requests.session()
        self.session.headers = {
            'Content-Type':
            'application/x-www-form-urlencoded',
            'Referer':
            'https://weibo.com/',
            'User-Agent':
            'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Mobile Safari/537.36'
        }
        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        """
        检查是否登录成功
        :return:
        """
        res = self.session.get('http://my.sina.com.cn/', cookies=cookies)
        html = res.content.decode(chardet.detect(res.content)['encoding'])
        bsobj = BeautifulSoup(html, 'lxml')
        if bsobj.find('p', {'class': 'me_name'}):
            nickname = bsobj.find('p', {'class': 'me_name'}).get_text()
            self.logger.info('Cookies 有效! ')
            self.logger.info(f'Hello, {nickname}! ')
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        elif '立即登录' in res.text:
            return False
        return False

    @staticmethod
    def _load_js(jsfilename):
        """
        打开js脚本并加载
        :return:
        """
        with open(jsfilename, 'r') as f:
            js = f.read()
        ctx = execjs.compile(js)
        return ctx

    def _get_su(self, ctx):
        """
        获取su参数
        :return:
        """
        su = ctx.call('getSu', self.username)
        return su

    def _get_params(self, su):
        """
        获取pcid, nonce, pubkey, servertime, rsakv
        :param su:
        :return:
        """
        url = 'https://login.sina.com.cn/sso/prelogin.php?'
        params = {
            'entry': 'weibo',
            'callback': 'sinaSSOController.preloginCallBack',
            'su': su,
            'rsakt': 'mod',
            'checkpin': '1',
            'client': 'ssologin.js(v1.4.19)',
            '_': int(time.time() * 1000)
        }

        res = self.session.get(url, params=params).text
        result = json.loads(
            re.search(r'sinaSSOController.preloginCallBack\((.*?)\)',
                      res).group(1))
        pcid = result['pcid']
        nonce = result['nonce']
        pubkey = result['pubkey']
        servertime = result['servertime']
        rsakv = result['rsakv']
        return pcid, nonce, pubkey, servertime, rsakv

    def _get_verifycode(self, pcid):
        captcha_url = f'https://login.sina.com.cn/cgi/pin.php?r=16343619&s=0&p={pcid}'
        img_data = self.session.get(captcha_url).content
        self.logger.info('使用超级鹰识别验证码...')
        ok, result = image_to_text(img_data)
        if ok:
            self.logger.info('成功识别验证码!')
            return result
        raise Exception('验证码识别失败: ', result)

    def _get_sp(self, ctx, pubkey, servertime, nonce):
        """
        获取sp参数
        :param ctx:
        :return:
        """
        sp = ctx.call('getSp', pubkey, servertime, nonce, self.password)
        return sp

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        登录
        :return:
        """
        login_api = f'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)&_={int(time.time()*1000)}'

        ctx = self._load_js('encryptUN.js')
        su = self._get_su(ctx)
        pcid, nonce, pubkey, servertime, rsakv = self._get_params(su)
        verify_code = self._get_verifycode(pcid)
        ctx_ = self._load_js('encryptPW.js')
        sp = self._get_sp(ctx_, pubkey, servertime, nonce)

        data = {
            'entry': 'weibo',
            'gateway': '1',
            'from': '',
            'savestate': '7',
            'qrcode_flag': 'false',
            'useticket': '1',
            'pagerefer':
            'https://login.sina.com.cn/crossdomain2.php?action=logout&r=https%3A%2F%2Fpassport.weibo.com%2Fwbsso%2Flogout%3Fr%3Dhttps%253A%252F%252Fweibo.com%26returntype%3D1',
            'pcid': pcid,
            'door': verify_code,
            'vsnf': '1',
            'su': su,
            'service': 'miniblog',
            'servertime': servertime,
            'nonce': nonce,
            'pwencode': 'rsa2',
            'rsakv': rsakv,
            'sp': sp,
            'sr': '1440*561',  # 屏幕大小
            'encoding': 'UTF-8',
            'cdult': '2',
            'domain': 'weibo.com',
            'prelt': '48',
            'returntype': 'TEXT'
        }
        res = self.session.post(login_api, data=data)
        cookies = res.cookies.get_dict()
        if self.check_islogin(cookies):
            return True
        elif res.json()['reason'] == '登录名或密码错误' or res.json(
        )['reason'] == '请输入正确的密码':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception(res.json()['reason'])

    @check_user()
    def run(self, load_cookies: bool = True):
        """
        主函数运行
        :return:
        """
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.warning('Cookies 已过期! ')

        self.login()
예제 #12
0
class QimaiLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'qimai'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Accept':
            'application/json, text/plain, */*',
            'Content-Type':
            'application/x-www-form-urlencoded; charset=UTF-8',
            'Origin':
            'https://www.qimai.cn',
            'Referer':
            'https://www.qimai.cn/account/signin/r/%2Frank%2Findex%2Fbrand%2Ffree%2Fcountry%2Fcn%2Fgenre%2F5000%2Fdevice%2Fiphone',
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }

        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        url = 'https://api.qimai.cn/account/settingAccount?analysis=eEcbVwJTX0VeRB9DXRBDUQpTdwJTX0VeRHATFVUCCVEFBFQEAAgGAgFwG1U%3D'
        res = self.session.get(url, cookies=cookies).json()
        if res['code'] == 10000 and res['msg'] == '成功':
            self.logger.info('登录成功!')
            self.logger.info('Hello, {}! '.format(
                res['accountInfo']['realname']))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        return False

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def _get_verifycode(self):
        timestamp = int(time.time() * 1000)
        captcha_url = f'https://api.qimai.cn/account/getVerifyCodeImage?{timestamp}'
        img_data = self.session.get(captcha_url).content
        self.logger.info('使用超级鹰识别验证码...')
        ok, result = image_to_text(img_data)
        if ok:
            self.logger.info('成功识别验证码!')
            return result
        raise Exception('验证码识别失败: ', result)

    def _get_synct(self):
        resp = self.session.get('https://www.qimai.cn/rank')
        cookies = resp.cookies.get_dict()
        return cookies.get('synct')

    @staticmethod
    def _get_analysis(synct):
        with open('analysis.js', 'rb') as f:
            js = f.read().decode()
        ctx = execjs.compile(js)
        return ctx.call('getLoginAnalysis', synct)

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self, login_api):
        data = {
            'username': self.username,
            'password': self.password,
            'code': self._get_verifycode()
        }
        res = self.session.post(login_api, data=data)
        cookies = res.cookies.get_dict()
        if self.check_islogin(cookies):
            return cookies
        elif res.json()['msg'] == '用户名或密码错误':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败: ', res.json()['msg'])

    @check_user()
    def run(self, load_cookies: bool = True):
        """
        模拟登录
        :param load_cookies:
        :return:
        """
        synct = self._get_synct()
        url = 'https://api.qimai.cn/account/signinForm?'
        params = {'analysis': self._get_analysis(synct)}
        login_api = url + urlencode(params)
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login(login_api)
예제 #13
0
class QichamaoLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'qichamao'
        self.username = username
        self.password = password
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }

        # 密码错误重置
        self.reset_flag = True

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def _get_verifycode(self):
        captcha_url = 'https://www.qichamao.com/usercenter/varifyimage?'
        img_data = self.session.get(captcha_url).content
        self.logger.info('使用超级鹰识别验证码...')
        ok, result = image_to_text(img_data)
        if ok:
            self.logger.info('成功识别验证码!')
            return result
        raise Exception('验证码识别失败: ', result)

    def check_islogin(self, cookies):
        """
        检查登录状态,访问登录页面跳转则是已登录,
        如登录成功保存当前 Cookies
        :return: bool
        """
        login_url = 'https://www.qichamao.com/usercenter/login'
        headers = {
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299'
        }
        resp = requests.get(login_url, cookies=cookies, headers=headers)
        if 'userhd_name' in resp.text:
            self.logger.info('登录成功! ')
            bsobj = BeautifulSoup(resp.text, 'lxml')
            nickname = bsobj.select('.userhd_name')[0].get_text()
            self.logger.info('Hello, {}! '.format(nickname))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        return False

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        login_api = 'https://www.qichamao.com/usercenter/dologin'

        verify_code = self._get_verifycode()
        data = {
            'userId': self.username,
            'password': self.password,
            'VerifyCode': verify_code,
            'sevenDays': 'false'
        }
        res = self.session.post(login_api, data=data)
        cookies = res.cookies.get_dict()
        if self.check_islogin(cookies):
            return True
        elif '用户名或密码错误' in res.json()['sMsg']:
            raise Exception('账号或密码错误! ')
        raise Exception(json.loads(res.text)['sMsg'])

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.warning('Cookies 已过期')

        self.login()
예제 #14
0
class LrtsLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'lrts'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36',
            'X-Requested-With': 'XMLHttpRequest'
        }
        # 密码错误重置
        self.reset_flag = False

    def check_islogin(self, cookies):
        res = self.session.get('http://www.lrts.me/index', cookies=cookies)
        html = res.content.decode(chardet.detect(res.content)['encoding'])
        bsobj = BeautifulSoup(html, 'lxml')
        if bsobj.select('h4.nowrap a'):
            nickname = bsobj.select('h4.nowrap a')[0].get_text()
            self.logger.info('登录成功!')
            self.logger.info('Hello, {}!'.format(nickname))
            return True
        return False

    def _get_token(self):
        url = 'http://www.lrts.me/user/login_token.do'

        data = {'accountName': self.username}

        res = self.session.post(url, data=data).json()
        return res['data']

    def _encrypt_pwd(self, token):
        with open('encrypt.js', 'rb') as f:
            js = f.read().decode()

        ctx = execjs.compile(js)
        return ctx.call('encrypt_pwd', self.password, token)

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        api = 'http://www.lrts.me/user/login.do'

        token = self._get_token()
        pwd = self._encrypt_pwd(token)
        data = {
            'accountName': self.username,
            'hashPass': pwd,
            'autoLogin': '******',
            'validateCode': ''
        }
        res = self.session.post(api, data=data)
        cookies = res.cookies.get_dict()
        if self.check_islogin(cookies):
            self.logger.info('Cookies 有效期: {} 天'.format(
                int(res.json()['data']['expires'] / 86400)))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return cookies
        elif res.json()['errMsg'] == '帐号或密码错误':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败: ', res.json()['errMsg'])

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login()
예제 #15
0
class TaobaoLogin:

    def __init__(self, username: str = None, password: str = None):
        self.site = 'taobao'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)

    async def check_islogin(self, page):
        """
        检查登录状态: 访问首页, 出现用户名则登录成功
        :param page:
        :return:
        """

        await page.goto('https://www.taobao.com/')

        time.sleep(3)

        html = await page.content()

        bsobj = BeautifulSoup(html, 'lxml')

        if bsobj.find('a', {'class': 'site-nav-login-info-nick'}):
            self.logger.info('Cookies 有效! ')
            nickname = bsobj.find('a', {'class': 'site-nav-login-info-nick'}).get_text()
            self.logger.info('Hello, {}! '.format(nickname))
            cookies = await page.cookies()
            # cookies = {item['name']: item['value'] for item in cookies}
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        return False

    @staticmethod
    def input_time_random():
        return random.randint(150, 201)

    def retry_if_result_none(self, result):
        self.logger.warning('滑块判定失败, 重试!')
        return result is None

    @check_user()
    async def login(self):
        # 以下使用await 可以针对耗时的操作进行挂起
        # 记:一定要给pyppeteer权限删除用户数据, 即设置userDataDir: 文件夹名称, 否则会报错无法移除用户数据
        browser = await launch(
            {
                'headless': True,
                'args': ['--no-sandbox', '--disable-infobars'],
            },
            # userDataDir=r'D:\login\userdata',
            args=['--window-size=1366, 768']
        )
        page = await browser.newPage()  # 启动个新的浏览器页面
        await page.setJavaScriptEnabled(enabled=True)  # 启用js
        await page.setUserAgent(
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299'
        )  # 设置模拟浏览器

        self.logger.info('尝试登录...')

        await page.goto(
            'https://login.taobao.com/member/login.jhtml?spm=a21bo.2017.754894437.1.5af911d9qqVAb1&f=top&redirectURL=https%3A%2F%2Fwww.taobao.com%2F'
        )
        await self.page_evaluate(page)  # 修改window.navigator.webdriver = False, 这是绕过淘宝自动化工具检测的关键

        # 使用type选定页面元素,并修改其数值,用于输入账号密码,修改的速度仿人类操作,因为有个输入速度的检测机制
        # 因为 pyppeteer 框架需要转换为js操作,而js和python的类型定义不同,所以写法与参数要用字典,类型导入

        try:
            await page.click('#J_Quick2Static')   # 点击选择密码登录, 看你进入登录页面是否已经是密码登录, 若不是则需要点击选择密码登录
        except:
            pass

        time.sleep(1)

        # 清空用户名输入框, 确保正确输入: 用户名不为空时页面才会有清空节点 nickx
        try:
            await page.click('.nickx')
        except:
            pass

        # await page.evaluate('''() => { document.getElementById(TPL_username_1).value="" }''')
        time.sleep(1)
        await page.type('#TPL_username_1', self.username, {'delay': self.input_time_random() - 50})
        time.sleep(1)
        await page.type('#TPL_password_1', self.password, {'delay': self.input_time_random()})

        # await page.screenshot({'path': './headless-test-result.png'})   # 截图测试
        time.sleep(2)

        slider = await page.Jeval('#nocaptcha', 'node => node.style')  # 是否有滑块

        self.logger.info('账号密码输入完成, 判断滑块是否出现')
        if slider:
            self.logger.info('出现滑块情况判定')
            # await page.screenshot({'path': './headless-login-slide.png'})   # 截图测试
            flag = await self.mouse_slide(page=page)  # js拉动滑块
            if flag:
                # await page.keyboard.press('Enter')  # 模拟按键Enter确定 或鼠标点击登录
                await page.click('#J_SubmitStatic')
                time.sleep(1)
                cookies = await page.cookies()
                # cookies = {item['name']: item['value'] for item in cookies}
                self.redis_client.save_cookies(self.site, self.username, cookies)
        else:
            # await page.keyboard.press('Enter')
            self.logger.info('滑块未出现, 点击登录按钮')
            await page.click('#J_SubmitStatic')
            await page.waitFor(20)
            await page.waitForNavigation()  # 等待跳转
            try:
                global error
                error = await page.Jeval('.error', 'node => node.textContent')  # 检测是否是账号密码错误
            except Exception as e:
                error = None
                self.logger.info("登录成功! ")
            finally:
                if error:
                    # self.logger.info('确保账户安全重新输入')
                    error = await (await (await page.xpath('//div[@class="dialog-con"]'))[0].getProperty(
                        'textContent')).jsonValue()
                    self.logger.info(error)
                else:
                    await asyncio.sleep(3)
                    cookies = await page.cookies()
                    # print({item['name']: item['value'] for item in cookies})
                    self.redis_client.save_cookies(self.site, self.username, cookies)
                    return cookies
        await self.page_close(browser)

    async def page_evaluate(self, page):
        # 替换淘宝在检测浏览时采集的一些参数。
        # 就是在浏览器运行的时候,始终让window.navigator.webdriver=false
        # navigator是windiw对象的一个属性,同时修改plugins,languages,navigator
        await page.evaluate(
            '''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => undefined } }) }''')  # 以下为插入中间js,将淘宝会为了检测浏览器而调用的js修改其结果。
        await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')
        await page.evaluate(
            '''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')
        await page.evaluate(
            '''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')

    async def page_close(self, browser):
        """
        关闭浏览器驱动
        :param browser:
        :return:
        """
        for _page in await browser.pages():
            await _page.close()
        await browser.close()

    @retry(retry_on_result=retry_if_result_none, )
    async def mouse_slide(self, page=None):
        await asyncio.sleep(2)
        try:
            # 鼠标移动到滑块,按下,滑动到头(然后延时处理),松开按键
            await page.hover('#nc_1_n1z')  # 不同场景的验证码模块可能名字不同。
            await page.mouse.down()  # 模拟按下鼠标
            await page.mouse.move(2000, 0, {'delay': random.randint(1000, 2000)})  # js模拟拖动
            await page.mouse.up()  # 模拟松开鼠标
        except Exception as e:
            self.logger.error('验证失败: {}'.format(e.args))
            return None, page
        else:
            await asyncio.sleep(2)
            slider_again = await page.Jeval('.nc-lang-cnt', 'node => node.textContent')  # 判断是否通过
            if slider_again != '验证通过':
                return None, page
            else:
                # await page.screenshot({'path': './headless-slide-result.png'}) # 截图测试
                self.logger.info('验证通过! ')
                return 1, page

    async def run(self, load_cookies: bool = True):
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                browser = await launch(
                    {
                        'headless': True,
                        'args': ['--no-sandbox', '--disable-infobars'],
                    },
                    userDataDir=r'D:\login\userdata',
                    args=['--window-size=1366, 768']
                )
                page = await browser.newPage()
                self.logger.info('将 cookies 装载到浏览器中...')
                await page.deleteCookie()
                for cookie in cookies:
                    await page.setCookie(cookie)
                if await self.check_islogin(page):
                    await self.page_close(browser)
                    return cookies
                await self.page_close(browser)
                self.logger.warning('cookies 已过期! ')

        return await self.login()
예제 #16
0
class GithubLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'github'
        self.username = username
        self.password = password
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }
        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        res = requests.get('https://github.com/', cookies=cookies)

        if 'octolytics-actor-login' in res.text:
            self.logger.info('Cookies 有效! ')
            bsobj = BeautifulSoup(res.text, 'lxml')
            nickname = bsobj.find(
                'meta', {'name': 'octolytics-actor-login'})['content']
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        return False

    def _get_authenticity_token(self):
        """
        请求登录页获取 authenticity_token
        :return:
        """
        res = self.session.get('https://github.com/login')
        bsobj = BeautifulSoup(res.text, 'lxml')
        authenticity_token = bsobj.find(
            'input', {'name': 'authenticity_token'})['value']
        return authenticity_token

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        模拟登录
        :return:
        """
        login_api = 'https://github.com/session'

        authenticity_token = self._get_authenticity_token()
        data = {
            'commit': 'Sign in',
            'utf8': '✓',
            'authenticity_token': authenticity_token,
            'login': self.username,
            'password': self.password,
            'webauthn-support': 'supported'
        }

        res = self.session.post(login_api, data=data, allow_redirects=False)

        if res.status_code == 302:
            self.logger.info('登录成功! ')
            self.redis_client.save_cookies(self.site, self.username,
                                           res.cookies.get_dict())
            return True
        elif 'Incorrect username or password' in res.text:
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败! ')

    @check_user()
    def run(self, load_cookies: bool = True):
        """
        主函数运行
        :return:
        """
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.warning('Cookies 已过期! ')

        self.login()
예제 #17
0
class ZhilianLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'zhilian'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.browser = None
        self.wait = None

    def check_islogin(self, cookies):
        """
        检查登录状态, 跳转至个人主页则 cookies 有效
        :param cookies:
        :return:
        """
        url = 'https://fe-api.zhaopin.com/c/i/user/detail'
        headers = {
            'user-agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }
        res = requests.get(url, headers=headers, cookies=cookies).json()
        if res['code'] == 200:
            self.logger.info('Cookies 有效!')
            nickname = res['data']['Name']
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        return False

    def get_geetest_button(self):
        button = self.wait.until(
            EC.element_to_be_clickable(
                (By.CLASS_NAME, 'geetest_slider_button')))
        return button

    def get_geetest_image(self, name, full):
        top, bottom, left, right, size = self.get_position(full)
        # print("验证码位置", top, bottom, left, right)
        screenshot = self.get_screenshot()
        captcha = screenshot.crop((left, top, right, bottom))
        size = size["width"] - 1, size["height"] - 1
        captcha.thumbnail(size)
        # captcha.show()
        # captcha.save(name)
        return captcha

    def get_position(self, full):
        img = self.wait.until(
            EC.presence_of_element_located(
                (By.CSS_SELECTOR, "canvas.geetest_canvas_slice")))
        fullbg = self.wait.until(
            EC.presence_of_element_located(
                (By.CSS_SELECTOR, "canvas.geetest_canvas_fullbg")))
        time.sleep(2)

        # 两种执行js写法
        if full:
            self.browser.execute_script(
                'document.getElementsByClassName("geetest_canvas_fullbg")[0].setAttribute("style", "")'
            )
        else:
            self.browser.execute_script(
                "arguments[0].setAttribute(arguments[1], arguments[2])",
                fullbg, "style", "display: none")

        location = img.location
        size = img.size
        top, bottom, left, right = location["y"], location["y"] + \
                                   size["height"], location["x"], location["x"] + size["width"]
        return (top, bottom, left, right, size)

    def get_screenshot(self):
        screenshot = self.browser.get_screenshot_as_png()
        return Image.open(BytesIO(screenshot))

    def get_gap(self, image1, image2):
        for i in range(LEFT, image1.size[0]):
            for j in range(image1.size[1]):
                if not self.is_pixel_equal(image1, image2, i, j):
                    return i
        return LEFT

    def is_pixel_equal(self, image1, image2, x, y):
        pixel1 = image1.load()[x, y]
        pixel2 = image2.load()[x, y]
        if abs(pixel1[0] - pixel2[0]) < THRESHOLD and abs(
                pixel1[1] - pixel2[1]) < THRESHOLD and abs(
                    pixel1[2] - pixel2[2]) < THRESHOLD:
            return True
        else:
            return False

    def get_track(self, distance):
        """
        获取滑块移动轨迹的列表
        :param distance: 第二个缺块的左侧的x坐标
        :return: 滑块移动轨迹列表
        """
        # 移动轨迹
        track = []
        # 当前位移
        current = 0
        # 减速阈值
        mid = distance * 2 / 3
        # 计算间隔
        t = 0.4
        # 初速度
        v = 0
        distance += 10  # 使滑块划过目标地点, 然后回退

        while current < distance:
            # 加速度
            if current < mid:
                a = 2
            else:
                a = -3
            # 初速度 v0
            v0 = v
            # 当前速度
            v = v0 + a * t
            # 移动距离
            move = v0 * t + 0.5 * a * t * t
            # 当前位移
            current += move
            track.append(move)

        return track

    def get_slider(self):
        return self.wait.until(
            EC.element_to_be_clickable(
                (By.CLASS_NAME, "geetest_slider_button")))

    def move_to_gap(self, button, track):
        ActionChains(self.browser).click_and_hold(button).perform()
        for x in track:
            ActionChains(self.browser).move_by_offset(xoffset=x,
                                                      yoffset=0).perform()
            # time.sleep(0.5)
        # time.sleep(0.5)
        ActionChains(self.browser).release().perform()

    @seleniumLoopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        打开浏览器,并且输入账号密码
        :return: None
        """
        self.logger.info('尝试登录...')
        self.browser.get(
            "https://passport.zhaopin.com/login?bkUrl=%2F%2Fi.zhaopin.com%2Fblank%3Fhttps%3A%2F%2Fwww.zhaopin.com%2F"
        )
        time.sleep(1)
        self.browser.find_element_by_xpath(
            '//li[@class="zppp-panel-tab"]').click()
        time.sleep(1)
        username = self.wait.until(
            EC.element_to_be_clickable(
                (By.CSS_SELECTOR, 'input[type="text"]')))
        password = self.wait.until(
            EC.element_to_be_clickable(
                (By.CSS_SELECTOR, 'input[type="password"]')))
        submit = self.wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, '.zppp-submit')))
        time.sleep(1)
        username.clear()
        username.send_keys(self.username)
        time.sleep(1)
        password.clear()
        password.send_keys(self.password)
        time.sleep(1)
        self.logger.info('账号密码输入完成, 点击登录按钮')
        submit.click()

        self.logger.info('等待验证码加载...')
        image1 = self.get_geetest_image("captcha1.png", True)
        image2 = self.get_geetest_image("captcha2.png", False)
        gap = self.get_gap(image1, image2)
        track = self.get_track(gap - BORDER)
        slider = self.get_slider()
        self.logger.info('移动滑块至缺口...')
        self.move_to_gap(slider, track)
        time.sleep(3)

        # 跳转至首页则登录成功
        self.logger.info('校验滑动验证是否成功...')
        if self.browser.current_url == 'https://www.zhaopin.com/':
            self.logger.info('校验完成, 登录成功! ')
            nickname = self.browser.find_element_by_css_selector(
                '.zp-userinfo').text
            self.logger.info('Hello, {}! '.format(nickname))
            cookies = self.browser.get_cookies()
            cookies = {item['name']: item['value'] for item in cookies}
            self.redis_client.save_cookies(self.site, self.username, cookies)
            self.browser.close()
            return cookies
        elif self.wait.until(
                EC.presence_of_element_located(
                    (By.CSS_SELECTOR, "canvas.geetest_canvas_slice"))):
            raise Exception('滑动验证失败! ')
        elif self.browser.find_element_by_xpath('//p[@class="tips"]'):
            self.logger.error('校验完成, 登录失败: {}! '.format(
                self.browser.find_element_by_xpath('//p[@class="tips"]').text))
            return None
        raise Exception('登录失败! ')

    @check_user()
    def run(self, load_cookies: bool = True):
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        options = webdriver.ChromeOptions()
        # 设置为开发者模式,避免被识别
        options.add_experimental_option('excludeSwitches',
                                        ['enable-automation'])
        options.add_argument('--headless')
        self.browser = webdriver.Chrome(options=options)
        self.wait = WebDriverWait(self.browser, 20)
        cookies = self.login()
        self.logger.info('程序结束!')
        return cookies
예제 #18
0
class QixinbaoLogin:

    def __init__(self, username: str = None, password: str = None):
        self.site = 'qixinbao'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Content-Type': 'application/json;charset=UTF-8',  # payload提交表单参数, 请求头中必须含有 Content-Type, 并且提交方法为 json.dumps(data)
            'Referer': 'https://www.qixin.com/auth/login?return_url=%2F',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36',
            'X-Requested-With': 'XMLHttpRequest'
        }

        # 密码错误重置
        self.reset_flag = False

        with open('encrypt.js', 'rb') as f:
            js = f.read().decode()
        self.ctx = execjs.compile(js)
        self.codes = self.get_codes()

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def check_islogin(self, cookies):
        url = 'https://www.qixin.com/user/home/center'
        res = self.session.get(url, cookies=cookies)
        if '会员中心' in res.text:
            bsobj = BeautifulSoup(res.text, 'lxml')
            nickname = bsobj.find('div', {'class': 'body'}).find('h5').get_text()
            self.logger.info('登录成功!')
            self.logger.info('Hello, {}! '.format(nickname))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        return False

    def _encrypt_pwd(self):
        """
        加密密码
        :return:
        """
        return self.ctx.call('encrypt', self.password)

    @staticmethod
    def get_codes():
        """
        获取 js 加密 codes
        :return:
        """
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36',
        }
        url = 'https://cache.qixin.com/pcweb/common.a89140e8.js'
        resp = requests.get(url, headers=headers)
        codes = {}
        for i in range(20):
            text = r'e\.default={' + str(i) + ':"(.*?)"}'
            x = re.search(text, resp.text).group(1)
            codes.setdefault(i, x)
        return codes

    def _get_header_js(self, url, data):
        """
        获取请求头中的加密参数, 加密对象为提交的表单
        :return:
        """
        return {self.ctx.call('header_key', self.codes, url): self.ctx.call('header_value', self.codes, url, data)}

    def _init_cookies(self):
        self.session.get('https://www.qixin.com/')

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        模拟登录
        :return:
        """
        self._init_cookies()
        login_api = 'https://www.qixin.com/api/user/login'
        pwd = self._encrypt_pwd()
        data = {
            'acc': self.username,
            'captcha': {
                'isTrusted': 'true'
            },
            'keepLogin': '******',
            'pass': pwd
        }
        header_js = self._get_header_js(login_api, data)
        self.session.headers.update(header_js)
        res = self.session.post(login_api, data=json.dumps(data))
        cookies = self.session.cookies.get_dict()
        if self.check_islogin(cookies):
            return cookies
        elif '用户名或密码错误' in res.text:
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败: ', res.json()['message'])

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login()
예제 #19
0
class City58Login:
    def __init__(self, username: str = None, password: str = None):
        self.site = '58city'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'user-agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }
        # 密码错误重置初始化
        self.reset_flag = False

    def _get_token(self):
        """
        获取登录的token参数
        :return:
        """
        base_url = 'https://passport.58.com/sec/58/feature/pc/ui?'
        res = self.session.get(base_url)
        doc = pq(res.text)
        path = doc('#path').attr('value')
        timestamp = int(time.time() * 1000)
        url = f'https://passport.58.com/58/login/init?callback=jQuery112401218021763208601_{timestamp}&source=58-default-pc&path={path}&psdk-d=jsdk&psdk-v=1.0.0&_={int(time.time()*1000)}'
        r = self.session.get(url)
        result = json.loads(
            r.text.replace(f'jQuery112401218021763208601_{timestamp}(',
                           '').replace(')', ''))
        token = result['data']['token']
        return path, token

    def _encrypt_pwd(self):
        """
        RSA加密密码
        :return:
        """
        with open('encrypt.js', 'rb') as f:
            js = f.read().decode()
        ctx = execjs.compile(js)
        encrypt_pwd = ctx.call('encryptString', self.password)
        return encrypt_pwd

    def check_islogin(self, cookies):
        """
        检查是否成功登录
        :return:
        """
        url = 'http://my.58.com/webpart/userbasicinfo?'
        res = self.session.get(url, cookies=cookies)
        if 'username' in res.text:
            self.logger.info('Cookies 有效!')
            nickname = unquote(cookies['58uname'])
            self.logger.info('Hello, {}! '.format(nickname))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        return False

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        登录
        :return:
        """
        login_api = 'https://passport.58.com/58/login/pc/dologin'

        encrypt_pwd = self._encrypt_pwd()
        path, token = self._get_token()
        # 浏览器指纹可固定
        data = {
            'fingerprint': 'cFJ17E_h2J-JDePNDcjQipipJf-ulq8O',
            'callback': 'successFun',
            'username': self.username,
            'password': encrypt_pwd,
            'token': token,
            'source': '58-default-pc',
            'path': path,
            'domain': '58.com',
            'finger2':
            'zh-CN|24|1|4|1366_768|1366_728|-480|1|1|1|undefined|1|unknown|Win32|unknown|3|false|false|false|false|false|0_false_false|d41d8cd98f00b204e9800998ecf8427e|ab307cc3fc702e5ba66265525bf235e9',
            'psdk-d': 'jsdk',
            'psdk-v': '1.0.0'
        }
        self.session.headers.update({
            'accept':
            'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
            'accept-encoding': 'gzip, deflate, br',
            'accept-language': 'zh-CN,zh;q=0.9',
            'cache-control': 'max-age=0',
            'content-length': '918',
            'content-type': 'application/x-www-form-urlencoded',
            'cookie':
            'id58=c5/njVzb4POxn3A0A5HAAg==; 58tj_uuid=d9c75b22-75df-45a5-9753-7d50573ecf07; als=0; xxzl_deviceid=q7tLhmL5%2BD1rBg1ATI6k4pOMk5JPQohVW%2F2gGSVpM6FQmGsn62qCn5qWyuyKi9WD; wmda_uuid=241b006d58daf7ba9c3bb7e99a44dc04; wmda_new_uuid=1; wmda_visited_projects=%3B2385390625025; ppStore_fingerprint=2435661B36DB2AADF42830177DB0924E0018B24F3003A472%EF%BC%BF1557913861099; 58home=hf; city=hf; mcity=hf; finger_session=cFJ17E_h2J-JDePNDcjQipipJf-ulq8O; new_session=1; new_uv=6; utm_source=sem-sales-360-pc; spm=18470355416.%7Bcreative%7D; init_refer=https%253A%252F%252Fwww.so.com%252Fs%253Fie%253Dutf-8%2526src%253Ddlm%2526shb%253D1%2526hsid%253D048b900bc5158a43%2526ls%253Dn5eecf99698%2526q%253D58%2525E5%252590%25258C%2525E5%25259F%25258E',
            'origin': 'https://passport.58.com',
            'referer':
            'https://passport.58.com/login/?path=https%3A//hf.58.com/chuzu/%3Futm_source%3Dsem-sales-360-pc%26spm%3D18470355416.%7Bcreative%7D%26utm_campaign%3Dsell%26utm_medium%3Dcpc%26showpjs%3Dpc_fg&PGTID=0d3090a7-0034-5e39-c90b-41d899bb8a55&ClickID=2',
            'upgrade-insecure-requests': '1',
        })
        resp = self.session.post(login_api, data=data)
        doc = pq(resp.text)
        result = json.loads(
            re.search(r'parent.successFun\((.*?)\)',
                      doc('script').text()).group(1))
        if result['code'] == 0:
            self.logger.info('登录成功! ')
            cookies = resp.cookies.get_dict()
            nickname = unquote(cookies['58uname'])
            self.logger.info('Hello, {}! '.format(nickname))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return cookies
        elif result['msg'] == '该用户名与密码不符' or result['msg'] == '密码格式错误,请重置':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        # 手机号验证...
        raise Exception('登录失败: {} '.format(result['msg']))

    @check_user()
    def run(self, load_cookies: bool = True):
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login()
예제 #20
0
class Email163Login:
    def __init__(self, username: str = None, password: str = None):
        self.site = '163email'
        self.username = username
        self.password = password
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Content-Type':
            'application/json',
            'Origin':
            'https://dl.reg.163.com',
            'Referer':
            'https://mail.163.com/',
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36',
        }
        with open('encryptEnvinfo.js', 'r') as f:
            self.js = f.read()
        self.ctx = execjs.compile(self.js)
        self.rtid = self.ctx.call('getRtid')

        # 密码错误重试初始化
        self.reset_flag = False

    def check_islogin(self, cookies):

        sid = cookies['sid']

        params = {'sid': sid}
        cookie = cookies['cookies']

        resp = self.session.get('http://mail.163.com/js6/main.jsp?',
                                params=params,
                                cookies=cookie)

        if '收件箱' in resp.text:
            self.logger.info('Cookies 有效! ')
            try:
                nickname = re.search("'true_name':'(.*?)'", resp.text).group(1)
                self.logger.info('Hello, {}! '.format(nickname))
            except:
                self.logger.info('你还没有设置昵称, 快去设置吧! ')
            return True
        return False

    def _set_data(self, func):
        """
        配置收件箱接口表单参数
        :return:
        """
        with open('data.html', 'r') as f:
            html = f.read()
        data_list = html.split('<?xml version="1.0"?>')
        if func == 'global:sequential':
            return data_list[1]
        elif func == 'mbox:listMessages':
            return data_list[2]
        elif func == 'mbox:readMessage':
            return data_list[3]
        else:
            self.logger.warning('不支持的接口类型, 有需要请自行添加! ')

    @staticmethod
    def _format_date(text):
        """
        格式化日期
        :param date:
        :return:
        """
        date = re.search(r"new Date\((.*?)\)", text, re.S)
        send_time = '-'.join([
            x for x in date.group(1).split(',')[:3]
        ]) + ' ' + ':'.join([x for x in date.group(1).split(',')[3:]])
        return text.replace(date.group(0), send_time)

    def _read_email(self, cookies):
        """
        查看收件箱: 接口返回的数据是字典样式的原生字符串, demjson 格式化后都无法转为 json 格式... 懒得用正则提取了, 将就看
        :return:
        """
        cookie = cookies['cookies']
        sid = cookies['sid']
        self.session.headers.update({
            'Accept':
            'text/javascript',  # 请求头携带这个参数接口返回的是格式化数据, 没有这个参数返回的html源码
            'Content-type':
            'application/x-www-form-urlencoded'
        })
        url = 'https://mail.163.com/js6/s?'
        func_map = {
            '1': 'global:sequential',
            '2': 'mbox:listMessages',
            '3': 'mbox:readMessage'
        }
        sign_list = []
        all_flag = input('是否查看邮箱整体信息? (yes/任意键跳过) >> \n')
        if all_flag == 'yes':
            all_flag = 1
        else:
            all_flag = 0
        if all_flag:
            sign_list.append('1')
        mailbox_flag = input('是否查看收件箱邮件列表? (yes/任意键跳过) >> \n')
        if mailbox_flag == 'yes':
            mailbox_flag = 1
        else:
            mailbox_flag = 0
        if mailbox_flag:
            sign_list.append('2')
        for sign in sign_list:
            params = {
                'sid': sid,
                'func': func_map[sign],
            }
            data = {'var': self._set_data(func_map[sign])}
            res = self.session.post(url,
                                    params=params,
                                    data=data,
                                    cookies=cookie)
            if sign == '1':
                self.logger.info('邮箱整体信息如下:')
                pprint(res.text)
            elif sign == '2':
                self.logger.info('收件箱邮件列表: ')
                ids = re.findall("'id':'(.*?)'", res.text)
                subjects = re.findall("'subject':'(.*?)'", res.text)
                id_dict = {str(index): id_ for index, id_ in enumerate(ids)}
                subject_dict = {
                    str(index): subject
                    for index, subject in enumerate(subjects)
                }
                if id_dict:
                    pprint(subject_dict)
                    view_flag = input('是否需要查看具体邮件信息? (yes/任意键退出) >> \n')
                    if view_flag == 'yes':
                        view_flag = 1
                    else:
                        view_flag = 0
                    while view_flag:
                        email_num = input('请输入邮件编号(左边数字)>> ')
                        params = {
                            'sid': sid,
                            'func': func_map['3'],
                        }
                        origin_id = re.search('"id">(.*?)<',
                                              self._set_data(
                                                  func_map['3'])).group(1)
                        data = {
                            'var':
                            self._set_data(func_map['3']).replace(
                                origin_id, id_dict[email_num])
                        }
                        resp = self.session.post(url,
                                                 params=params,
                                                 data=data,
                                                 cookies=cookie)
                        result = self._format_date(resp.text)
                        pprint(result)
                        view_flag = int(input('继续查看请按 1 , 退出程序请按 0 >> \n'))
                else:
                    self.logger.info('收件箱列表空空如也~ ')

    def _init_cookies(self):
        """
        初始化 Cookies, 关键 Cookie: l_s_mail163CvViHzl, 有这个 Cookie 拿到 tk
        :return:
        """
        url = 'https://dl.reg.163.com/dl/ini?'
        params = {
            "pd": "mail163",
            "pkid": "CvViHzl",
            "pkht": "mail.163.com",
            "channel": "0",
            "topURL": "https://mail.163.com/",
            "rtid": self.rtid,
            "nocache": int(time.time() * 1000)
        }
        self.session.get(url, params=params)

    def _get_token(self):
        """
        获取页面 token
        :return:
        """
        url = 'https://dl.reg.163.com/gt?'

        params = {
            'un': self.username,
            'pkid': 'CvViHzl',
            'pd': 'mail163',
            'channel': 0,
            'topURL': 'https://mail.163.com/',
            'rtid': self.rtid,
            'nocache': int(time.time() * 1000)
        }

        result = self.session.get(url, params=params).json()
        token = result['tk']
        return token

    def _encrypt_pwd(self):
        """
        加密密码
        :return:
        """
        return self.ctx.call('encrypt2', self.password)

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        self._init_cookies()
        tk = self._get_token()

        login_api = 'https://dl.reg.163.com/dl/l'

        data = {
            "un": self.username,
            "pw": self._encrypt_pwd(),
            "pd": "mail163",
            "l": 0,
            "channel": 0,
            "d": 10,
            "t": int(time.time() * 1000),
            "pkid": "CvViHzl",
            "domains": "",
            "tk": tk,
            "pwdKeyUp": 1,
            "topURL": "https://mail.163.com/",
            "rtid": self.rtid
        }

        self.session.headers.update({
            'Cookie':
            'JSESSIONID-WYTXZDL=g1JHfvz6wsLNeHAdyUtE0FRiruebrGhpnsGt%5CTZs%5CPAAfGmXG5hGzE3eEu0QDmcqGQKf87EVpesHEvrEGPWeWs4u%2FAgfTWKfoTE3GpnbrQtrto1LU0B2f9tlUNun7en3J7p1PFX6ddMsK%2Bh0LlsLVf5MAN6qTzfWGo5jB6tm5KnpbBdo%3A1569055359975; l_s_mail163CvViHzl=2BDA1093FDDA9283AD02B57FFFEC7E0EF7CE8F4A6E2DA32BBA32CC50C8A54E5BB98676C37C29B6F138D45F2B1D5510896F1359E92D0A78847C03BEBD800E91DCC6880B78017150B4FBBD720B8AE3FE99EE370B654693348BE2A23B1B22020FC24086B6B03057ED5D1AD40CEA84949569'
        })
        res = self.session.post(login_api, data=json.dumps(data)).json()
        if res['ret'] == '201':
            form_data = {
                "style": "-1",
                "df": "mail163_letter",
                "allssl": "true",
                "net": "",
                "language": "-1",
                "from": "web",
                "race": "",
                "iframe": "1",
                "url2": "https://mail.163.com/errorpage/error163.htm",
                "product": "mail163"
            }

            cookies = 'df=mail163_letter; NTES_SESS=' + self.session.cookies.get_dict(
            )['NTES_SESS']
            # cookies = '; '.join([key + '=' + value for key, value in self.session.cookies.get_dict().items()])
            self.session.headers.update({'Cookie': cookies})
            resp = self.session.post(
                'https://mail.163.com/entry/cgi/ntesdoor?',
                data=form_data,
                allow_redirects=False)
            redirect_url = resp.headers['location'].replace(
                'unknow', 'mail163_letter')

            if 'sid' in redirect_url:
                self.logger.info('登录成功! ')
                response = self.session.get(redirect_url)

                # 网易邮箱的关键是这个sid, 是 session id 的意思, 有了它就可以爬邮箱了, 当然还要有配套的 Cookie
                cookies_item = {
                    'cookies': resp.cookies.get_dict(),
                    'sid':
                    redirect_url.split('?')[1].split('&')[0].split('=')[1]
                }
                self.redis_client.save_cookies(self.site, self.username,
                                               cookies_item)
                try:
                    nickname = re.search("'true_name':'(.*?)'",
                                         response.text).group(1)
                    self.logger.info('Hello, {}! '.format(nickname))
                except:
                    self.logger.info('你还没有设置昵称, 快去设置...')
                return cookies_item
            raise Exception('登录失败! ')
        elif res['ret'] == '413':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        elif res['ret'] == '445':
            self.logger.warning('验证码校验...')
            return None
        elif res['ret'] == '409':
            self.logger.warning('登录过于频繁, 请稍后再试! ')
            return None
        elif res['ret'] == '423':
            self.logger.warning('风控账号! ')
            return None
        raise Exception('登录失败! ')

    @check_user()
    def run(self, load_cookies: bool = True):
        if '163.com' not in self.username:
            self.username += '@163.com'
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)

            if cookies:
                if self.check_islogin(cookies):
                    read_flag = input('是否需要查看邮箱? (yes/任意键退出) >> \n')
                    if read_flag == 'yes':
                        self._read_email(cookies)
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login()
예제 #21
0
class ToutiaoLogin:
    def __init__(self,
                 username: str = None,
                 password: str = None,
                 headless=False):
        self.site = 'toutiao'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.browser = None
        self.wait = None
        self.headless = headless

        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        """
        检查登录状态, 请求网站首页出现用户名则 cookies 有效
        :param cookies:
        :return:
        """
        url = 'https://www.toutiao.com/'
        headers = {
            'user-agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }
        resp = requests.get(url, headers=headers, cookies=cookies)
        nickname = re.search("userName: '******',", resp.text).group(1)
        if nickname != '':
            self.logger.info('Cookies 有效! ')
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        return False

    def set_browser(self):
        """
        配置 selenium
        :return:
        """
        options = webdriver.ChromeOptions()
        # 设置为开发者模式,避免被识别, 开发者模式下 webdriver 属性为 undefined
        options.add_experimental_option('excludeSwitches',
                                        ['enable-automation'])
        if self.headless:
            options.add_argument('--headless')
        self.browser = webdriver.Chrome(options=options)
        self.wait = WebDriverWait(self.browser, 20)

    @staticmethod
    def pic_download(url, type):
        """
        下载验证码图片
        :param url:
        :param type:
        :return:
        """
        img_data = requests.get(url).content
        with open('./{}.jpg'.format(type), 'wb') as f:
            f.write(img_data)

    @staticmethod
    def process_img(img1, img2):
        """
        图片处理
        :param img1: 处理后图片
        :param img2: 待处理图片
        :return:
        """
        cv2.imwrite(img1, img2)
        target = cv2.imread(img1)
        target = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
        target = abs(255 - target)
        cv2.imwrite(img1, target)

    def get_distance(self, slider_url, captcha_url):
        """
        获取缺口距离
        :param slider_url: 滑块图片 url
        :param captcha_url: 验证码图片 url
        :return:
        """

        # 引用上面的图片下载
        self.pic_download(slider_url, 'slider')

        time.sleep(2)

        # 引用上面的图片下载
        self.pic_download(captcha_url, 'captcha')

        # 计算拼图还原距离
        target = cv2.imread('slider.jpg', 0)
        template = cv2.imread('captcha.jpg', 0)
        w, h = target.shape[::-1]
        temp = 'temp.jpg'
        targ = 'targ.jpg'
        self.process_img(temp, template)
        self.process_img(targ, target)
        target = cv2.imread(targ)
        template = cv2.imread(temp)
        result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)
        x, y = np.unravel_index(result.argmax(), result.shape)
        # 缺口位置
        # print((y, x, y + w, x + h))

        # 调用PIL Image 做测试
        image = Image.open('captcha.jpg')

        xy = (y, x, y + w, x + h)
        # 切割
        imagecrop = image.crop(xy)
        # 保存切割的缺口
        imagecrop.save("new_image.jpg")
        # imagecrop.show()
        return y

    def get_slider(self):
        """
        获取滑块
        :return:
        """
        return self.wait.until(
            EC.element_to_be_clickable(
                (By.XPATH, '//img[@class="drag-button"]')))

    def move_to_gap(self, distance, slider):
        """
        移动滑块至缺口
        :param distance: 缺口距离
        :param slider: 滑块对象
        :return:
        """
        has_gone_dist = 0
        remaining_dist = distance
        # distance += randint(-10, 10)
        # 按下鼠标左键
        ActionChains(self.browser).click_and_hold(slider).perform()
        time.sleep(0.5)
        while remaining_dist > 0:
            ratio = remaining_dist / distance
            if ratio < 0.1:
                # 开始阶段移动较慢
                span = random.randint(3, 5)
            elif ratio > 0.9:
                # 结束阶段移动较慢
                span = random.randint(5, 8)
            else:
                # 中间部分移动快
                span = random.randint(15, 20)
            ActionChains(self.browser).move_by_offset(span,
                                                      random.randint(
                                                          -5, 5)).perform()
            remaining_dist -= span
            has_gone_dist += span
            time.sleep(random.randint(5, 20) / 100)

        ActionChains(self.browser).move_by_offset(remaining_dist,
                                                  random.randint(-5,
                                                                 5)).perform()
        ActionChains(self.browser).release(on_element=slider).perform()

    def is_element_exists(self, element):
        """
        判断页面元素是否存在: Xpath
        :param element:
        :return:
        """
        try:
            self.browser.find_element_by_xpath(element)
            return True
        except:
            return False

    @seleniumLoopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        打开浏览器,并且输入账号密码
        :return:
        """
        self.logger.info('尝试登录...')
        self.browser.get('https://sso.toutiao.com/')

        self.logger.info('点击选择账号密码登录...')
        acount_login = self.wait.until(
            EC.presence_of_element_located(
                (By.XPATH, '//div[@id="login-type-account"]')))
        acount_login.click()

        self.logger.info('输入账号...')
        input_username = self.wait.until(
            EC.presence_of_element_located((By.XPATH, '//*[@id="user-name"]')))
        input_username.send_keys(self.username)
        time.sleep(1)

        self.logger.info('输入密码...')
        input_password = self.wait.until(
            EC.presence_of_element_located((By.XPATH, '//*[@id="password"]')))
        input_password.send_keys(self.password)
        time.sleep(1)

        self.logger.info('点击登录...')
        button = self.wait.until(
            EC.presence_of_element_located(
                (By.XPATH, '//*[@id="bytedance-login-submit"]')))
        button.click()
        time.sleep(3)

        # 判断是否出现滑块验证
        slider_flag = self.is_element_exists('//*[@id="verify-bar-box"]')
        if not slider_flag:
            self.logger.info('未出现滑块验证! ')
            time.sleep(3)
            error_flag = self.is_element_exists('//div[@class="login-msg"]')
            if error_flag:
                msg_error = self.browser.find_element_by_xpath(
                    '//div[@class="login-msg"]').text
                if '帐号或密码错误' in msg_error:
                    self.reset_flag = True
                    raise Exception('账号或密码错误! ')
                else:
                    self.logger.error(msg_error)
                    return None
            elif self.browser.current_url != "https://www.toutiao.com/":
                self.logger.error('登录失败! ')
                return None
            else:
                self.logger.info('登录成功! ')
                cookies = self.browser.get_cookies()
                cookies = {
                    cookie['name']: cookie['value']
                    for cookie in cookies
                }
                self.redis_client.save_cookies(self.site, self.username,
                                               cookies)
                return cookies
        self.logger.info('出现滑块验证! ')
        while True:
            captcha_url = self.wait.until(
                EC.presence_of_element_located(
                    (By.XPATH,
                     '//*[@id="validate-big"]'))).get_attribute('src')
            slider_url = self.wait.until(
                EC.presence_of_element_located(
                    (By.XPATH,
                     '//img[@class="validate-block"]'))).get_attribute('src')
            distance = self.get_distance(slider_url, captcha_url)
            slider = self.get_slider()
            self.move_to_gap(distance, slider)
            time.sleep(3)
            error_flag = self.is_element_exists('//div[@class="login-msg"]')
            if error_flag:
                self.logger.info('验证通过! ')
                msg_error = self.browser.find_element_by_xpath(
                    '//div[@class="login-msg"]').text
                if '帐号或密码错误' in msg_error:
                    self.reset_flag = True
                    raise Exception('账号或密码错误! ')
                else:
                    self.logger.error(msg_error)
                    return msg_error
            elif self.is_element_exists('//*[@id="verify-bar-box"]'):
                self.logger.warning('验证失败, 重试! ')
                time.sleep(0.5)
            else:
                self.logger.info('验证通过, 登录成功! ')
                cookies = self.browser.get_cookies()
                cookies = {
                    cookie['name']: cookie['value']
                    for cookie in cookies
                }
                self.redis_client.save_cookies(self.site, self.username,
                                               cookies)
                return cookies
            time.sleep(random.randint(1, 3))

    @check_user()
    def run(self, load_cookies: bool = True):
        """
        运行
        :param load_cookies: 是否加载数据库中的 cookies
        :return: cookies
        """
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        self.set_browser()
        cookies = self.login()
        self.logger.info('程序结束! ')
        return cookies
예제 #22
0
class SteamLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'steam'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }

        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        """
        检查是否登录成功
        :return:
        """
        res = self.session.get('https://store.steampowered.com/',
                               cookies=cookies)
        if 'account_pulldown' in res.text:
            bsobj = BeautifulSoup(res.text, 'lxml')
            nickname = bsobj.select('#account_pulldown')[0].get_text()
            self.logger.info('Cookies 有效! ')
            self.logger.info(f'Hello, {nickname}! ')
            return True
        return False

    def _init_cookies(self):
        self.session.get('https://store.steampowered.com/')

    def _get_rsakey(self):
        """
        获取 RSA 加密参数
        :return:
        """
        url = 'https://store.steampowered.com/login/getrsakey/'
        data = {
            'donotcache': int(time.time() * 1000),
            'username': self.username
        }
        res = self.session.post(url, data=data).json()
        rsa_mod = res['publickey_mod']
        rsa_exp = res['publickey_exp']
        rsa_timestamp = res['timestamp']
        return rsa_mod, rsa_exp, rsa_timestamp

    def _encrypt_pwd(self, rsa_mod, rsa_exp):
        with open('encryptPwd.js', 'rb') as f:
            js = f.read().decode()

        ctx = execjs.compile(js)
        return ctx.call('encrypt', self.password, rsa_mod, rsa_exp)

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        login_api = 'https://store.steampowered.com/login/dologin/'

        self._init_cookies()
        rsa_mod, rsa_exp, rsa_timestamp = self._get_rsakey()
        pwd = self._encrypt_pwd(rsa_mod, rsa_exp)

        data = {
            'donotcache': int(time.time() * 1000),
            'password': pwd,
            'username': self.username,
            'twofactorcode': '',
            'emailauth': '',
            'loginfriendlyname': '',
            'captchagid': '-1',
            'captcha_text': '',
            'emailsteamid': '',
            'rsatimestamp': rsa_timestamp,
            'remember_login': '******'
        }

        res = self.session.post(login_api, data=data).json()
        if res['success']:
            transfer_urls = res['transfer_urls']
            transfer_parameters = res['transfer_parameters']
            resp = self.session.post(transfer_urls[1],
                                     data=transfer_parameters)
            if 'transfer_success' in resp.text:
                self.logger.info('登录成功! ')
                cookies = self.session.cookies.get_dict()
                self.redis_client.save_cookies(self.site, self.username,
                                               cookies)
                return cookies
            raise Exception('登录失败! ')
        else:
            if res['captcha_needed']:
                self.logger.info('此次登录需要验证码! ')
                return None
            elif res['message'] == '您输入的帐户名称或密码错误。' or \
                    res['message'] == 'The account name or password that you have entered is incorrect.':
                self.reset_flag = True
                raise Exception('账号或密码错误! ')
            raise Exception('登录失败! ')

    @check_user()
    def run(self, load_cookies: bool = True):
        """
        主函数运行
        :return:
        """
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)

            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期! ')

        return self.login()
예제 #23
0
class HuyaLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'huya'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'content-type':
            'application/json;charset=UTF-8',
            'lcid':
            '2052',
            'uri':
            '30001',
            'Origin':
            'https://udblgn.huya.com',
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }
        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        """
        检查登录, 请求用户主页若出现用户名则登录成功
        :return:
        """
        res = self.session.get('https://i.huya.com/', cookies=cookies)
        bsobj = BeautifulSoup(res.text, 'lxml')
        if bsobj.find('h2', {'class': 'uesr_n'}):
            nickname = bsobj.find('h2', {'class': 'uesr_n'}).get_text()
            self.logger.info('登录成功! ')
            self.logger.info('Hello, {}! '.format(nickname))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        return False

    def _get_sdid(self):
        url = 'https://udblgn.huya.com/web/middle/2.3/37893475/https/787b6ffa5e4c42a99091ab91d071ed2a'
        resp = self.session.get(url)
        sdid = re.search(r'HyUDBWebSDK_Exchange.init\((.*?)\);',
                         resp.text).group(1)
        return sdid

    def encrypt(self):
        with open('encrypt.js', 'rb') as f:
            js = f.read().decode()

        ctx = execjs.compile(js)

        password = ctx.call('encryptPwd', self.password)
        request_id = ctx.call('getRequestId', 1)
        page = ctx.call('getPage', 'https://www.huya.com/l')
        # 页面cookie, 没有测试过期时间
        context = ctx.call(
            'getContext',
            '__yamid_tt1=0.1232795775887836; __yamid_new=C875D5606C80000176AD12EEAE0014D2; SoundValue=0.50; alphaValue=0.80; guid=3ad7b83861a9ea5c33512be62ce6b2fa; Hm_lvt_51700b6c722f5bb4cf39906a596ea41f=1558882650,1559909095,1559998946; __yasmid=0.1232795775887836; udb_passdata=3; isInLiveRoom=true; udb_guiddata=787b6ffa5e4c42a99091ab91d071ed2a; web_qrlogin_confirm_id=bf407b38-0a04-453a-8899-c93acf12f406; h_unt=1560003929; Hm_lpvt_51700b6c722f5bb4cf39906a596ea41f=1560003939; __yaoldyyuid=; _yasids=__rootsid%3DC87A02DEAC400001CC501DC016A81329; PHPSESSID=qdd0udkruqk8mi2u0unr4p53r5'
        )
        return password, request_id, page, context

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        sdid = self._get_sdid()
        password, request_id, page, context = self.encrypt()
        self.session.headers.update({
            'context':
            context,
            'reqid':
            str(request_id),
            'Referer':
            'https://udblgn.huya.com/web/middle/2.3/854732/https/{}'.format(
                context.split('-')[1])
        })
        payload = {
            'appId': "5002",
            'byPass': "******",
            'context': context,
            'data': {
                'userName': "******",
                'password': password,
                'domainList': "",
                'behavior':
                "%5B%7B%22page.login%22%3A%220.073%22%7D%2C%7B%22input.l.account%22%3A%222.856%22%7D%2C%7B%22input.l.passwd%22%3A%225.37%22%7D%2C%7B%22button.UDBSdkLogin%22%3A%228.387%2C138%2C254%22%7D%5D",
                'page': page,
                'randomStr': "",
                'remember': "1"
            },
            'lcid': "2052",
            'requestId': str(request_id),
            'sdid': str(sdid),
            'smid': "",
            'uri': "30001",
            'version': "2.4"
        }
        url = 'https://udblgn.huya.com/web/v2/passwordLogin'
        res = self.session.post(url, data=json.dumps(payload))
        cookies = res.cookies.get_dict()
        if self.check_islogin(cookies):
            return cookies
        elif res.json()['description'] == '账号或密码错误':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败: {}'.format(res.json()['description']))

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login()
예제 #24
0
class WangyiyunLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'wangyiyun'
        self.username = username
        self.password = password
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)

        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        res = requests.get('https://music.163.com/#/user/home?',
                           cookies=cookies)
        # 注: 正则拿到的 json 字符串中 key 没有被括起来(json 默认字典里的字符串为双引号括起来), 转 json 会报错, demjson 库可以修改 json 格式错误
        json_str = re.search('var GUser=(.*?);', res.text, re.S).group(1)
        user_info = demjson.decode(json_str)
        if user_info:
            self.logger.info('登录成功! ')
            self.logger.info('Hello, {}! '.format(user_info['nickname']))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        return False

    def get_wm_did(self):
        """
        获取 WM_DID, js生成认证 checkToken 所需的一个参数, 未找到 js 生成函数, 所以直接用浏览器获取了...
        有效期是一天左右, 过期重新获取, 并保存到本地 txt 文件中, 避免每次登录都要重新调用浏览器获取
        :return:
        """
        options = webdriver.ChromeOptions()
        # 设置为开发者模式,避免被识别, 开发者模式下 webdriver 属性为 undefined
        options.add_experimental_option('excludeSwitches',
                                        ['enable-automation'])
        options.add_argument('--headless')
        browser = webdriver.Chrome(options=options)

        browser.get("https://music.163.com/#/login")
        time.sleep(1)
        WM_DID = browser.execute_script('return window.localStorage["WM_DID"]')
        param = WM_DID.split('__')[0]
        stime = WM_DID.split('__')[2][:10]
        etime = WM_DID.split('__')[1][:10]
        start_time = time.strftime(
            '%Y-%m-%d %H:%M:%S',
            time.localtime(int(WM_DID.split('__')[2][:10])))
        end_time = time.strftime(
            '%Y-%m-%d %H:%M:%S',
            time.localtime(int(WM_DID.split('__')[1][:10])))
        self.logger.info('{} 有效时间: {} - {}'.format(param, start_time,
                                                   end_time))
        browser.close()

        with open('param.txt', 'w') as f:
            f.write(param + '\n')
            f.write(stime + '\n')
            f.write(etime)

        return param

    def get_checktoken(self):
        """
        获取 token 认证
        :return:
        """
        with open('param.txt', 'r') as f:
            lines = f.readlines()
        param = lines[0].replace('\n', '')
        stime = int(lines[1].replace('\n', ''))
        etime = int(lines[2])
        current_time = int(time.time())
        if stime < current_time < etime:
            self.logger.info('{} 有效! '.format(param))
        else:
            self.logger.warning('{} 已过期, 等待访问首页重新获取! '.format(param))
            param = self.get_wm_did()
        with open('get_checktoken.js', 'rb') as f:
            js = f.read().decode()
        ctx = execjs.compile(js)
        return ctx.call('getCheckToken', param)

    def md5_encrypt(self):
        """
        md5加密密码
        :return:
        """
        md5 = hashlib.md5()
        md5.update(self.password.encode())
        encrypt_pwd = md5.hexdigest()
        return encrypt_pwd

    @staticmethod
    def get_random_str():
        """
        获取一个随机16位字符串
        :return: 随机16位字符串
        """
        str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
        res = ''
        for x in range(16):
            index = math.floor(random.random() * len(str))
            res += str[index]
        return res

    @staticmethod
    def aes_encrypt(text, key):
        """
        AES加密
        :param text: 待加密密文
        :param key: 密钥
        :return:
        """
        # iv: 偏移量
        iv = '0102030405060708'
        # 注:AES只能加密数字和字母,无法加密中文。
        # 解决方法:在CBC加密模式下,字符串必须补齐长度为16的倍数,且长度指标不能为中文,需转化为unicode编码长度
        pad = 16 - len(text.encode()) % 16
        text = text + pad * chr(pad)
        encryptor = AES.new(key, AES.MODE_CBC, iv)
        # 最后还需要进行base64加密
        msg = base64.b64encode(encryptor.encrypt(text))
        return msg

    @staticmethod
    def rsa_encrypt(value, text, modulus):
        """
        RSA加密
        :param value: 加密指数
        :param text: 待加密密文
        :param modulus: 加密系数
        :return:
        """
        text = text[::-1]
        rs = int(codecs.encode(text.encode('utf-8'), 'hex_codec'), 16)**int(
            value, 16) % int(modulus, 16)
        return format(rs, 'x').zfill(256)

    def get_data(self):
        """
        params:进行了两次AES加密
        encSecKey:进行了一次RSA加密
        :return:
        """
        encrypt_pwd = self.md5_encrypt()
        checkToken = self.get_checktoken()
        data = {
            "phone": self.username,
            "password": encrypt_pwd,
            "rememberLogin": "******",
            "checkToken": checkToken,
            "csrf_token": ""
        }
        text = json.dumps(data)
        random_text = self.get_random_str()

        # params: 两次AES加密
        params = self.aes_encrypt(text, '0CoJUm6Qyw8W8jud')
        params = self.aes_encrypt(params.decode('utf-8'),
                                  random_text).decode('utf-8')

        # RSA加密系数, 固定值
        module = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5a" \
                 "a76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46be" \
                 "e255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
        # encSeckey: 一次 RSA 加密, '010001' 为加密指数, 固定值
        encSecKey = self.rsa_encrypt('010001', random_text, module)
        return {'params': params, 'encSecKey': encSecKey}

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        login_api = 'https://music.163.com/weapi/login/cellphone?csrf_token='
        data = self.get_data()
        headers = {
            'referer':
            'https://music.163.com/',
            'user-agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }
        res = requests.post(login_api, data=data, headers=headers)
        cookies = res.cookies.get_dict()

        if res.json()['code'] == 200:
            self.logger.info('登录成功! ')
            self.logger.info('Hello, {}!'.format(
                res.json()['profile']['nickname']))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        elif res.json()['message'] == '密码错误':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败: {} '.format(res.json()['message']))

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.warning('Cookies 已过期')

        self.login()
예제 #25
0
class BaiduLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'baidu'
        self.username = username
        self.password = password
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'User-Agent':
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.7 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.7',
            'Referer': 'https://pan.baidu.com/',
        }

        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        """
        ...
        :param cookies:
        :return:
        """
        pass

    def _init_cookies(self):
        """
        访问百度网盘首页初始化 cookies
        :return:
        """
        self.session.get('https://pan.baidu.com/')

    @staticmethod
    def _get_gid():
        return str(uuid4()).upper()

    def _get_token(self, gid):
        """
        获取登录 token 认证
        :return:
        """
        url = 'https://passport.baidu.com/v2/api/?getapi'
        params = {
            'getapi': '',
            'tpl': 'mn',
            'apiver': 'v3',
            'tt': str(int(time.time() * 1000)),
            'class': 'login',
            'gid': gid,
            'loginversion': 'v4',
            'logintype': 'dialogLogin',
            'traceid': '',
            'callback': 'bd__cbs__pivyke',
        }
        resp = self.session.get(url=url, params=params)
        js = parse_json(resp.text.replace("\'", "\""))
        return js['data']['token']

    def _get_public_key(self, gid, token):
        """
        获取 RSA 加密公钥
        :return:
        """
        url = 'https://passport.baidu.com/v2/getpublickey'
        params = {
            'token': token,
            'tpl': 'mn',
            'apiver': 'v3',
            'tt': str(int(time.time() * 1000)),
            'gid': gid,
            'loginversion': 'v4',
            'traceid': '',
            'callback': 'bd__cbs__h02h0j'
        }
        resp = self.session.get(url=url, params=params)
        js = parse_json(resp.text.replace("\'", "\""))
        key, public_key = js.get('key'), js.get('pubkey')
        return key, public_key

    def _encrypt_pwd(self, public_key):
        rsa_key = RSA.importKey(public_key)
        encryptor = Cipher_pkcs1_v1_5.new(rsa_key)
        cipher = b64encode(encryptor.encrypt(self.password.encode('utf-8')))
        return cipher.decode('utf-8')

    def _get_verifycode(self, code_string):
        """
        使用超级鹰识别验证码
        :param pcid:
        :return:
        """
        captcha_url = f'https://passport.baidu.com/cgi-bin/genimage?{code_string}'
        img_data = self.session.get(captcha_url).content
        self.logger.info('使用超级鹰识别验证码...')
        ok, result = image_to_text(img_data)
        if ok:
            self.logger.info('成功识别验证码!')
            return result
        raise Exception('验证码识别失败: ', result)

    def _verify_phone(self, authtoken, lstr, ltoken, loginproxy):
        """
        手机验证
        :return:
        """
        url = 'https://passport.baidu.com/v2/sapi/authwidgetverify?'
        params = {
            "authtoken": authtoken,
            "type": "mobile",
            "jsonp": "1",
            "apiver": "v3",
            "verifychannel": "",
            "action": "getapi",
            "vcode": "",
            "questionAndAnswer": "",
            "needsid": "",
            "rsakey": "",
            "countrycode": "",
            "subpro": "",
            "u": "https://www.baidu.com/",
            "lstr": lstr,
            "ltoken": ltoken,
            "tpl": "mn",
            "winsdk": "",
            "authAction": "",
            "traceid": "00BC1501",
            "callback": "bd__cbs__h3w9ui"
        }

        res = self.session.get(url, params=params)
        encode_str = res.text.replace(
            'bd__cbs__h3w9ui(', '').replace(')', '').replace('{', '').replace(
                '}', '').replace('"', '').replace("'", '').replace(' ', '')
        result = {
            item.split(':')[0]: item.split(':')[1]
            for item in encode_str.split(',')
        }
        if result['errno'] == '110000':
            self.logger.info('成功请求验证码接口! ')
            params.update({
                "action": "send",
            })
            resp = self.session.get(url, params=params)
            encode_str = resp.text.replace('bd__cbs__h3w9ui(', '').replace(
                ')', '').replace('{',
                                 '').replace('}', '').replace('"', '').replace(
                                     "'", '').replace(' ', '')
            result = {
                item.split(':')[0]: item.split(':')[1]
                for item in encode_str.split(',')
            }
            if result['errno'] == '110000':
                self.logger.info('验证码发生中, 请注意接收...')
                time.sleep(1)
                verify_code = input('请输入验证码 >> \n')
                params.update({
                    "action": "check",
                    "vcode": verify_code,
                })
                respo = self.session.get(url, params=params)
                encode_str = respo.text.replace(
                    'bd__cbs__h3w9ui(',
                    '').replace(')',
                                '').replace('{', '').replace('}', '').replace(
                                    '"', '').replace("'", '').replace(' ', '')
                result = {
                    item.split(':')[0]: item.split(':')[1]
                    for item in encode_str.split(',')
                }
                if result['errno'] == '110000':
                    self.logger.info('手机验证成功! ')
                    response = self.session.get(loginproxy)
                    print(response.text)
                    return True
        elif result['errno'] == '110002':
            self.logger.error(result['msg'])
            return False

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):

        self._init_cookies()
        gid = self._get_gid()
        token = self._get_token(gid)
        key, public_key = self._get_public_key(gid, token)
        pwd = self._encrypt_pwd(public_key)

        login_api = 'https://passport.baidu.com/v2/api/?login'
        data = {
            'staticpage': 'https://www.baidu.com/cache/user/html/v3Jump.html',
            'charset': 'UTF-8',
            'token': token,
            'tpl': 'netdisk',
            'subpro': 'netdisk_web',
            'apiver': 'v3',
            'tt': str(int(time.time() * 1000)),
            'codestring': '',
            'safeflg': '0',
            'u': 'https://www.baidu.com/',
            'isPhone': 'false',
            'detect': '1',
            'gid': gid,
            'quick_user': '******',
            'logintype': 'dialogLogin',
            'logLoginType': 'pc_loginDialog',
            'idc': '',
            'loginmerge': 'true',
            'splogin': '******',
            'username': self.username,
            'password': pwd,
            'rsakey': key,
            'crypttype': '12',
            'ppui_logintime': 389548,
            'countrycode': '',
            'loginversion': 'v4',
            'traceid': '',
            'callback': 'parent.bd__pcbs__oxzeyj'
        }
        for _ in range(10):
            resp = self.session.post(login_api, data=data)

            result_str = re.search(r'.*href \+= "(.*)"\+accounts',
                                   resp.text).group(1)
            result = {
                x.split('=')[0]: x.split('=')[1]
                for x in result_str.split('&')
            }

            if result['err_no'] == '0':
                self.logger.info('登录成功! ')
                cookies = resp.cookies.get_dict()
                self.redis_client.save_cookies(self.site, self.username,
                                               cookies)
                return True
            elif result['err_no'] in {'6', '257'}:
                code_str = result.get('codeString')
                self.logger.warning('请输入验证码! ')
                verify_code = self._get_verifycode(code_str)
                data.update({
                    'codestring': code_str,
                    'verifycode': verify_code
                })
            elif result['err_no'] == '120021':
                self.logger.warning('账号存在风险, 请进行手机验证! ')
                authtoken = result['authtoken']
                lstr = result['lstr']
                ltoken = result['ltoken']
                loginproxy = result['loginproxy']
                flag = self._verify_phone(authtoken, lstr, ltoken, loginproxy)
                if not flag:
                    return
            elif result['err_no'] in {'4', '7'}:
                self.reset_flag = True
                raise Exception('账号或密码错误! ')

    @check_user()
    def run(self, load_cookies: bool = True):
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.warning('Cookies 已过期')

        self.login()
예제 #26
0
class ShixiSengLogin:
    def __init__(self, username: str = None, password: str = None):
        # 网站
        self.site = 'shixiseng'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'Referer':
            'https://www.shixiseng.com/',
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }
        # 密码错误重置
        self.reset_flag = False

    def check_islogin(self, cookies):
        res = self.session.get('https://www.shixiseng.com/', cookies=cookies)
        html = res.content.decode(chardet.detect(res.content)['encoding'])
        bsobj = BeautifulSoup(html, 'lxml')
        if bsobj.find('span', {'class': 'nickname'}):
            nickname = bsobj.find('span', {
                'class': 'nickname'
            }).get_text().strip()
            self.logger.info('登录成功!')
            self.logger.info('Hello, {}! '.format(nickname))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        return False

    def _encrypt_pwd(self):
        with open('encrypt.js', 'r') as f:
            js = f.read()
        ctx = execjs.compile(js)
        return ctx.call('myencode', self.password)

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        pwd = self._encrypt_pwd()
        url = 'https://www.shixiseng.com/user/login'

        data = {
            'username': self.username,
            'password': pwd,
            'remember_login': '******'
        }

        res = self.session.post(url, data=data)
        result = json.loads(res.text)
        cookies = res.cookies.get_dict()
        if self.check_islogin(cookies):
            return cookies
        elif result['msg'] == '密码不对' or '密码不正确':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败: ', result['msg'])

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login()
예제 #27
0
class RenrenLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'renren'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }
        with open('encryptPwd.js', 'rb') as f:
            js = f.read().decode()

        self.ctx = execjs.compile(js)

        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        """
        检查是否登录成功
        :return:
        """
        res = self.session.get('http://www.renren.com/home', cookies=cookies)
        if 'hd-name' in res.text:
            bsobj = BeautifulSoup(res.text, 'lxml')
            nickname = bsobj.select('.hd-name')[0].get_text()
            self.logger.info('Cookies 有效! ')
            self.logger.info(f'Hello, {nickname}! ')
            return True
        return False

    def _init_cookies(self):
        """
        访问首页初始化 Cookie
        :return:
        """
        self.session.get('http://www.renren.com/')

    def _get_rkey(self):
        """
        获取加密所需密钥和 rkey 参数
        :return:
        """
        url = 'http://login.renren.com/ajax/getEncryptKey'
        res = self.session.get(url).json()

        if res['isEncrypt']:
            iv = res['e']
            encryptKey = res['n']
            rkey = res['rkey']
            return iv, encryptKey, rkey
        raise Exception('获取密钥出错! ')

    def _encrypt_pwd(self, iv, encryptKey):
        return self.ctx.call('encrypt', self.password, iv, encryptKey)

    def _get_uniquetimestamp(self):
        return self.ctx.call('getUniqueTimestamp')

    def _show_captcha(self):
        """
        访问接口判断是否需要验证码
        :return:
        """
        url = 'http://www.renren.com/ajax/ShowCaptcha'
        data = {'email': self.username, '_rtk': 'a0cdef52'}
        res = self.session.post(url, data=data)
        if '0' in res.text:
            self.logger.info('此次登录无需验证码! ')
            return False
        return True

    def _get_verifycode(self):
        captcha_url = 'http://icode.renren.com/getcode.do?t=web_login&rnd=0.28838133194471105'
        img_data = self.session.get(captcha_url).content
        self.logger.info('使用超级鹰识别验证码...')
        ok, result = image_to_text(img_data)
        if ok:
            self.logger.info('成功识别验证码!')
            return result
        raise Exception('验证码识别失败: ', result)

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):

        params = {'1': 1, 'uniqueTimestamp': self._get_uniquetimestamp()}

        login_api = 'http://www.renren.com/ajaxLogin/login?' + urlencode(
            params)

        self._init_cookies()
        iv, encryptKey, rkey = self._get_rkey()
        pwd = self._encrypt_pwd(iv, encryptKey)

        flag = self._show_captcha()
        if flag:
            icode = self._get_verifycode()
        else:
            icode = ''
        data = {
            'email': self.username,
            'icode': icode,
            'origURL': 'http://www.renren.com/home',
            'domain': 'renren.com',
            'key_id': '1',
            'captcha_type': 'web_login',
            'password': pwd,
            'rkey': rkey,
            'f': 'http%3A%2F%2Fwww.renren.com%2F971788971'
        }
        self.session.headers['Referer'] = 'http://www.renren.com/SysHome.do'
        res = self.session.post(login_api, data=data)

        if 'failCode' not in res.text:
            self.logger.info('登录成功! ')

            resp = self.session.get('http://www.renren.com/home',
                                    allow_redirects=False)
            redirect_url = resp.headers['location']

            cookies = self.session.cookies.get_dict()

            # 巨坑... 这里返回的 cookies 中的 t 的值需要替换为 societyguester 的值
            # 真正起作用的 cookie 就是 t这个键 和 societyguester 的值, 其他 cookie 可以不要。
            cookies['t'] = cookies['societyguester']
            self.redis_client.save_cookies(self.site, self.username, cookies)

            response = self.session.get(redirect_url)
            bsobj = BeautifulSoup(response.text, 'lxml')
            nickname = bsobj.select('.hd-name')[0].get_text()
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        elif res.json()['failCode'] == 128:
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        elif res.json()['failCode'] == 512:
            raise Exception(res.json()['failDescription'])
        raise Exception('登录失败! ')

    @check_user()
    def run(self, load_cookies: bool = True):
        """
        主函数运行
        :return:
        """
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)

            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.warning('Cookies 已过期! ')

        self.login()
예제 #28
0
class MeituanLogin:

    def __init__(self, username: str = None, password: str = None):
        self.site = 'meituan'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)

        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        url = 'https://www.meituan.com/ptapi/getLoginedUserInfo?timestamp={}'.format(int(time.time() * 1000))
        headers = {
            'Referer': 'http://hf.meituan.com/',
            'Upgrade-Insecure-Requests': '1',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }
        cookies = {item['name']: item['value'] for item in cookies}
        resp = requests.get(url, headers=headers, cookies=cookies).json()
        if resp['nickName']:
            self.logger.info('Cookies 有效! ')
            nickname = resp['nickName']
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        return False

    @staticmethod
    def input_time_random():
        return random.randint(150, 201)

    def retry_if_exception(self, result):
        if isinstance(result, Exception):
            self.logger.error('Something Wring: {}'.format(result))
            return result is Exception
        return result is None

    async def page_evaluate(self, page):

        await page.evaluate(
            '''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => undefined } }) }''')  # 以下为插入中间js,将淘宝会为了检测浏览器而调用的js修改其结果。
        await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')
        await page.evaluate(
            '''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')
        await page.evaluate(
            '''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')

    async def mouse_slide(self, page=None):
        await asyncio.sleep(2)
        try:
            # 鼠标移动到滑块,按下,滑动到头(然后延时处理),松开按键
            await page.hover('#yodaBox')  # 不同场景的验证码模块可能名字不同。
            await page.mouse.down()  # 模拟按下鼠标
            await page.mouse.move(2000, 0, {'delay': random.randint(1000, 2000)})  # js模拟拖动
            await page.mouse.up()  # 模拟松开鼠标
        except Exception as e:
            return None, page
        else:
            await asyncio.sleep(2)
            slider_again = await page.Jeval('#yodaTip', 'node => node.textContent')  # 判断是否通过
            if slider_again != '验证码已发送,请稍后':
                return None, page
            else:
                # await page.screenshot({'path': './headless-slide-result.png'}) # 截图测试
                return 1, page

    @staticmethod
    async def page_close(browser):
        """
        关闭浏览器驱动
        :param browser:
        :return:
        """
        for _page in await browser.pages():
            await _page.close()
        await browser.close()

    async def login(self):
        # 以下使用await 可以针对耗时的操作进行挂起
        # 记:一定要给pyppeteer权限删除用户数据, 即设置userDataDir: 文件夹名称, 否则会报错无法移除用户数据
        browser = await launch(
            {
                'headless': False,
                'args': ['--no-sandbox', '--disable-infobars'],
            },
            userDataDir=r'D:\login\userdata',
            args=['--window-size=1366, 768']
        )
        page = await browser.newPage()  # 启动个新的浏览器页面
        await page.setJavaScriptEnabled(enabled=True)  # 启用js
        await page.setUserAgent(
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299'
        )  # 设置模拟浏览器

        self.logger.info('尝试登录...')

        await page.goto('https://passport.meituan.com/account/unitivelogin?service=www&continue=https%3A%2F%2Fwww.meituan.com%2Faccount%2Fsettoken%3Fcontinue%3Dhttp%253A%252F%252Fhf.meituan.com%252F')

        await self.page_evaluate(page)

        self.logger.info('输入账号密码...')
        await page.type('#login-email', self.username, {'delay': self.input_time_random() - 50})
        time.sleep(1)
        await page.type('#login-password', self.password, {'delay': self.input_time_random()})
        time.sleep(1)

        self.logger.info('点击提交...')
        await page.click('input.btn')
        time.sleep(2)

        await self.verify(page)

    @staticmethod
    async def get_position(captcha):
        """
        获取验证码位置元组
        :return:
        """
        location = captcha.location
        size = captcha.size
        top, bottom, left, right = location["y"], location["y"] + \
                                   size["height"], location["x"], location["x"] + size["width"]
        return top, bottom, left, right, size

    async def verify(self, page):
        """
        风控认证
        :param page:
        :return:
        """
        self.logger.info('判断是否需要进行风控认证')
        await asyncio.sleep(3)
        if await page.xpath('//img[@id="yodaImgCode"]'):
            self.logger.info('账号存在风险, 需要进行风控认证! ')
            await page.screenshot({'path': './captcha_screenshot.png'})
            # captcha = (await page.xpath('//img[@id="yodaImgCode"]'))[0]
            # top, bottom, left, right, size = await self.get_position(captcha)
            with open('captcha_screenshot.png', 'rb') as f:
                img_data = f.read()
            # img_data = screenshot.crop((left, top, right, bottom))
            self.logger.info('使用超级鹰识别验证码...')
            ok, verify_code = image_to_text(img_data)
            if ok:
                self.logger.info('成功识别验证码! ')
                self.logger.info('输入验证码...')
                await page.type('#yodaImgCodeInput', verify_code, {'delay': self.input_time_random() - 50})
                await asyncio.sleep(1)
                self.logger.info('点击提交...')
                await page.click('#yodaImgCodeSure')
                await asyncio.sleep(3)
        else:
            self.logger.info('账号正常, 未出现验证码! ')
            await asyncio.sleep(3)
            if page.url == 'http://hf.meituan.com/':
                self.logger.info('登录成功! ')
                cookies = await page.cookies()
                self.redis_client.save_cookies(self.site, self.username, cookies)
                return True
            elif 'verify.meituan.com' in page.url:
                self.logger.warning('为了您的账户安全,请先验证手机! ')
                await page.click('#yodaSmsCodeBtn')
                await asyncio.sleep(3)
                slider = page.Jeval('#yodaBox', 'node => node.style')
                if slider:
                    self.logger.info('出现滑块情况判定')
                    flag = await self.mouse_slide(page=page)
                    if flag:
                        self.logger.info('验证通过! ')
                    else:
                        self.logger.error('滑块验证失败! ')
                        return False
                await asyncio.sleep(3)
                phone_vcode = input('请输入手机验证码 >> \n')
                await page.type('#yodaVerification', phone_vcode, {'delay': self.input_time_random() - 50})
                await asyncio.sleep(1)
                self.logger.info('点击提交...')
                await page.click('#yodaSubmit')
                await asyncio.sleep(2)
        if await page.xpath('//div[@class="validate-info"]'):
            validate_info = await (await (await page.xpath('//div[@class="validate-info"]'))[0].getProperty('textContent')).jsonValue()
            self.logger.error(validate_info)
            return False
        elif page.url == 'http://hf.meituan.com/':
            self.logger.info('登录成功! ')
            cookies = await page.cookies()
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return True
        elif await page.xpath('//img[@id="yodaImgCode"]'):
            self.logger.error('验证失败! ')
            return False

    @check_user()
    async def run(self, load_cookies: bool = True):
        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return True
                self.logger.info('cookies 已过期! ')

        await self.login()
예제 #29
0
class OpenlawLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'openlaw'
        self.username = username
        self.password = password
        self.logger = get_logger()
        self.redis_client = RedisClient(self.logger)
        self.session = Session()
        self.session.headers = {
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }
        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        url = 'http://openlaw.cn/user/profile.jsp'
        res = self.session.get(url, cookies=cookies)
        if 'bbp-breadcrumb-root' in res.text:
            self.logger.info('Cookies 有效! ')
            bsobj = BeautifulSoup(res.text, 'lxml')
            nickname = bsobj.select('.bbp-breadcrumb-root')[0].get_text()
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        return False

    def _get_csrf(self):
        while True:
            base_url = 'http://openlaw.cn/login.jsp'
            res = self.session.get(base_url)
            cookies = res.cookies.get_dict()
            if cookies:
                soup = BeautifulSoup(res.text, 'lxml')
                _csrf = soup.find('input', {'name': '_csrf'})['value']
                return _csrf, cookies
            time.sleep(1)

    def _encrypt_pwd(self):
        with open('encryptPwd.js', 'rb') as f:
            js = f.read().decode()

        ctx = execjs.compile(js)
        encrypt_pwd = ctx.call('encrypt_pwd', self.password)
        return encrypt_pwd

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        login_api = 'http://openlaw.cn/login'
        _csrf, cookies = self._get_csrf()
        _encrypt_pwd = self._encrypt_pwd()
        data = {
            'username': self.username,
            '_csrf': _csrf,
            'password': _encrypt_pwd,
            '_spring_security_remember_me': 'true'
        }

        res = self.session.post(login_api, data=data)
        bsobj = BeautifulSoup(res.text, 'lxml')
        if bsobj.select('.bbp-breadcrumb-root'):
            self.logger.info('登录成功!')
            nickname = bsobj.select('.bbp-breadcrumb-root')[0].get_text()
            self.logger.info('Hello, {}! '.format(nickname))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return cookies
        elif '用户名或密码错误' in res.text:
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败! ')

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('Cookies 已过期')

        return self.login()
예제 #30
0
class KankanLogin:
    def __init__(self, username: str = None, password: str = None):
        self.site = 'kankan'
        self.logger = get_logger()
        self.username = username
        self.password = password
        self.redis_client = RedisClient(self.logger)
        self.session = requests.session()
        self.session.headers = {
            'user-agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
        }

        # 密码错误重置初始化
        self.reset_flag = False

    def check_islogin(self, cookies):
        """
        检查登录状态
        :return:
        """
        url = 'http://api.t.kankan.com/kknotify.json?'
        params = {
            'jsobj': 'G_SSUser',
            'userid': cookies['luserid'],
            'r': int(time.time() * 1000)
        }
        resp = self.session.get(url, params=params, cookies=cookies)
        result = json.loads(
            re.search('G_SSUser = (.*?) ;', resp.text, re.S).group(1))
        if result['status'] == 200:
            self.logger.info('Cookies 有效! ')
            nickname = result['data']['user']['nickname']
            self.logger.info('Hello, {}! '.format(nickname))
            return True
        return False

    def _encrypt_password(self, check_n, check_e, vcode):
        """
        RSA加密
        :return: 密码加密字符串
        """
        with open('encrypt.js', 'rb') as f:
            js = f.read().decode()

        ctx = execjs.compile(js)
        encrypt_pwd = ctx.call('encrypt_pwd', check_n, check_e, self.password,
                               vcode.upper())
        return encrypt_pwd

    def _check_account(self):
        url = 'https://ilogin.kankan.com/check/?u={}&v=100'.format(
            self.username)
        resp = self.session.get(url)
        cookies = resp.cookies.get_dict()
        check_n = unquote(cookies['check_n'])
        check_e = cookies['check_e']
        vcode = cookies['check_result'].replace('0:', '')
        return check_n, check_e, vcode

    @loopUnlessSeccessOrMaxTry(3, sleep_time=3)
    def login(self):
        """
        模拟登录
        :return:
        """
        login_api = 'https://ilogin.kankan.com/sec2login/'

        check_n, check_e, vcode = self._check_account()
        pwd = self._encrypt_password(check_n, check_e, vcode)
        data = {
            'p': pwd,
            'u': self.username,
            'n': check_n,
            'e': check_e,
            'v': '100',
            'verifycode': vcode,
            'login_enable': '0',
            'business_type': '107'
        }

        resp = self.session.post(login_api, data=data)
        cookies = resp.cookies.get_dict()
        if cookies['blogresult'] == '0':
            self.logger.info('登录成功! ')
            nickname = cookies['usernick']
            self.logger.info('Hello, {}! '.format(nickname))
            self.redis_client.save_cookies(self.site, self.username, cookies)
            return cookies
        elif cookies['blogresult'] == '4':
            self.reset_flag = True
            raise Exception('账号或密码错误! ')
        raise Exception('登录失败: ', cookies['logindetail'])

    @check_user()
    def run(self, load_cookies: bool = True):

        if load_cookies:
            cookies = self.redis_client.load_cookies(self.site, self.username)
            if cookies:
                if self.check_islogin(cookies):
                    return cookies
                self.logger.warning('cookies已过期')

        return self.login()