示例#1
0
 def waitForAuth(self, conf):
     qrcodeManager = QrcodeManager(conf)
     try:
         qrcodeManager.Show(self.getQrcode())
         while True:
             time.sleep(3)
             authStatus = self.getAuthStatus()
             if '二维码未失效' in authStatus:
                 INFO('登录 Step2 - 等待二维码扫描及授权')
             elif '二维码认证中' in authStatus:
                 INFO('二维码已扫描,等待授权')
             elif '二维码已失效' in authStatus:
                 WARN('二维码已失效, 重新获取二维码')
                 qrcodeManager.Show(self.getQrcode())
             elif '登录成功' in authStatus:
                 INFO('已获授权')
                 items = authStatus.split(',')
                 self.nick = str(items[-1].split("'")[1])
                 self.qq = str(int(self.session.cookies['superuin'][1:]))
                 self.urlPtwebqq = items[2].strip().strip("'")
                 break
             else:
                 CRITICAL('获取二维码扫描状态时出错, html="%s"', authStatus)
                 sys.exit(1)
     finally:
         qrcodeManager.Destroy()
示例#2
0
    def smartRequest(self,
                     url,
                     data=None,
                     repeatOnDeny=2,
                     sessionObj=None,
                     **kw):
        session = sessionObj or self.session
        i, j = 0, 0
        while True:
            html, timeOut = '', False
            session.headers.update(**kw)
            try:
                if data is None:
                    resp = session.get(url)
                else:
                    resp = session.post(url, data=data)

                if url == 'https://d1.web2.qq.com/channel/poll2':
                    # DEBUG('POLL RESULT: status_code=%s, html=%s',
                    #        resp.status_code, resp.content)

                    if resp.status_code in (502, 504):
                        timeOut = True
                    else:
                        html = resp.content
                        try:
                            result = JsonLoads(html)
                        except ValueError:
                            timeOut = True

                    if timeOut:
                        session.get(
                            ('http://pinghot.qq.com/pingd?dm=w.qq.com.hot&'
                             'url=/&hottag=smartqq.im.polltimeout&hotx=9999&'
                             'hoty=9999&rand=%s') %
                            random.randint(10000, 99999))
                        continue
                else:
                    html = resp.content
                    result = JsonLoads(html)

            except (requests.ConnectionError, ValueError):
                i += 1
                errorInfo = '网络错误或url地址错误'
            else:
                retcode = result.get('retcode', result.get('errCode', -1))
                if retcode in (0, 1202, 100003):
                    return result.get('result', result)
                else:
                    j += 1
                    errorInfo = '请求被拒绝错误'

            # 出现网络错误可以多试几次 (i <= 4);
            # 若 retcode 有误,一般连续 3 次都出错就没必要再试了 (j <= 2)
            if i <= 4 and j <= repeatOnDeny:
                DEBUG('第%d次请求“%s”时出现“%s”, html:\n%s', i + j, url, errorInfo,
                      html)
            else:
                CRITICAL('第%d次请求“%s”时出现“%s”,终止 QQBot', i + j, url, errorInfo)
                raise RequestError
示例#3
0
    def smartRequest(self, url, data=None,
                     timeoutRetVal=None, repeateOnDeny=2, **kw):
        nCE, nTO, nUE, nDE = 0, 0, 0, 0
        while True:
            url = url.format(rand=repr(random.random()))
            html = ''
            errorInfo = ''
            self.session.headers.update(**kw)
            try:
                if data is None:
                    resp = self.session.get(url, verify=self.httpsVerify)
                else:
                    resp = self.session.post(url, data=data,
                                             verify=self.httpsVerify)
            except requests.ConnectionError as e:
                nCE += 1
                errorInfo = '网络错误 %s' % e
            else:
                html = resp.content
                if resp.status_code in (502, 504, 404):
                    self.session.get(
                        ('http://pinghot.qq.com/pingd?dm=w.qq.com.hot&'
                         'url=/&hottag=smartqq.im.polltimeout&hotx=9999&'
                         'hoty=9999&rand=%s') % random.randint(10000, 99999)
                    )
                    if url == 'https://d1.web2.qq.com/channel/poll2':
                        return {'errmsg': ''}
                    nTO += 1
                    errorInfo = '超时'
                else:
                    try:
                        result = JsonLoads(html)
                    except ValueError:
                        nUE += 1
                        errorInfo = ' URL 地址错误'
                    else:
                        retcode = result.get('retcode', 
                                             result.get('errCode',
                                                        result.get('ec', -1)))
                        if retcode in (0, 1202, 100003, 100100):
                            return result.get('result', result)
                        else:
                            nDE += 1
                            errorInfo = '请求被拒绝错误'

            # 出现网络错误、超时、 URL 地址错误可以多试几次 
            # 若网络没有问题但 retcode 有误,一般连续 3 次都出错就没必要再试了
            if nCE < 5 and nTO < 20 and nUE < 5 and nDE <= repeateOnDeny:
                DEBUG('第%d次请求“%s”时出现“%s”, html=%s',
                      nCE+nTO+nUE+nDE, url, errorInfo, repr(html))
                time.sleep(0.5)
            elif nTO == 20 and timeoutRetVal: # by @killerhack
                return timeoutRetVal
            else:
                CRITICAL('第%d次请求“%s”时出现“%s”',
                         nCE+nTO+nUE+nDE, url, errorInfo)
                raise QSession.Error
示例#4
0
文件: qqbotconf.py 项目: yupk/qqbot
    def readConf(cls):
        conf = ast.literal_eval(defaultConfStr)
        cls.userDefInfo = conf['userInfo']['DEFAULT']
        confPath = cls.ConfPath()
        if os.path.exists(confPath):
            try:
                with open(confPath) as f:
                    cusConf = ast.literal_eval(f.read())

                if type(cusConf) is not dict:
                    raise ValueError('Must be a dict')

                for k, v in conf.items():
                    if k in cusConf:
                        if type(v) is not type(cusConf[k]):
                            raise ValueError('key: %s' % k)
                        conf[k] = cusConf[k]

                if type(conf['userInfo']) is not dict:
                    raise ValueError('key: userInfo')

                for k, v in conf['userInfo'].items():
                    if type(k) is not str or type(v) is not dict:
                        raise ValueError('key: userInfo.%s' % k)

            except IOError:
                CRITICAL('读取配置文件出现 IOError')
                sys.exit(1)

            except (SyntaxError, ValueError) as e:
                CRITICAL('配置文件语法或格式错误,%s', e)
                sys.exit(1)

        else:
            try:
                with open(confPath, 'w') as f:
                    f.write(defaultConfStr)
            except IOError:
                pass

        cls.__dict__.update(conf)
示例#5
0
 def manualLogin(self):
     try:
         self.prepareSession()
         self.waitForAuth()
         self.getPtwebqq()
         self.getVfwebqq()
         self.getUinAndPsessionid()
         self.testLogin()
         self.fetchBuddies()
         self.fetchGroups()
         self.fetchDiscusses()
         self.dumpSessionInfo()
     except RequestError:
         CRITICAL('手动登录失败!')
         sys.exit(1)
示例#6
0
 def __init__(self, name, port, tmpDir, runInBackgroud=True):
     assert type(port) is int or (type(port) is str and port.isdigit())
     assert os.path.isdir(tmpDir)
     self.name, self.port, self.tmpDir = name, int(port), tmpDir
     self._indexHTML = '<html><body>QQBOT-HTTP-SERVER</body></html>'
     self._indexURL = 'http://localhost:%s/qqbot' % port
     if not self.isRunning():
         if runInBackgroud:
             args = 'python', __file__, str(port), tmpDir
             if CallInNewConsole(args):
                 CRITICAL('无法运行命令"%s",二维码 HTTP 服务器启动失败' % 
                          ' '.join(args))
                 sys.exit(0)
             else:
                 time.sleep(1.0)
                 INFO('已在后台开启二维码 HTTP 服务器')
         else:
             print >>sys.stderr, ' * QQBot\'s QRCODE HTTP server'
             self.run()
     else:
         INFO('二维码 HTTP 服务器正在后台运行')        
示例#7
0
def runBot(argv=None):
    if sys.argv[-1] == '--subprocessCall':
        sys.argv.pop()
        bot = QQBot._bot
        bot.init(argv)
        bot.Run()
    else:
        conf = QConf()

        if conf.daemon:
            conf.Daemonize()

        if sys.argv[0].endswith('py') or sys.argv[0].endswith('pyc'):
            args = [sys.executable] + sys.argv
        else:
            args = sys.argv

        if '--bench' not in args:
            args = args + ['--bench', os.getcwd()]
        args = args + ['--qq', str(conf.qq)]
        args = args + ['--subprocessCall']

        while True:
            p = subprocess.Popen(args)
            code = p.wait()
            if code == 0:
                INFO('QQBot 正常停止')
                sys.exit(code)
            elif code == RESTART:
                INFO('1 秒后重新启动 QQBot (自动登陆,qq=%s)', args[-2])
                time.sleep(1)
            else:
                CRITICAL('QQBOT 异常停止(code=%s)', code)
                if conf.restartOnOffline:
                    args[-2] = '0'
                    INFO('5秒后重新启动 QQBot (手动登录)')
                    time.sleep(5)
                else:
                    sys.exit(code)
示例#8
0
    def fetchGroups(self, contacts, silence=True):
        if not silence:
            INFO('登录 Step7 - 获取群列表')
            INFO('=' * 60)

        for i in range(5):
            result = self.smartRequest(
                url='http://s.web2.qq.com/api/get_group_name_list_mask2',
                data={
                    'r': JsonDumps({
                        'vfwebqq': self.vfwebqq,
                        'hash': self.hash
                    })
                },
                Referer=('http://d1.web2.qq.com/proxy.html?v=20151105001&'
                         'callback=1&id=2'))
            if 'gmarklist' in result:
                break
            else:
                ERROR('获取群列表出错,等待 3 秒后再次尝试一次')
                time.sleep(3)
        else:
            CRITICAL('无法获取到群列表')
            raise QSession.Error

        markDict = dict((d['uin'], d['markname']) for d in result['gmarklist'])

        qqResult = self.smartRequest(
            url='http://qun.qq.com/cgi-bin/qun_mgr/get_group_list',
            data={'bkn': self.bkn},
            Referer='http://qun.qq.com/member.html')

        qqDict = defaultdict(list)
        for k in ('create', 'manage', 'join'):
            for d in qqResult.get(k, []):
                name = d['gn'].replace('&nbsp;', ' ').replace('&amp;', '&')
                qqDict[name].append(d['gc'])

        for info in result['gnamelist']:
            uin = info['gid']
            name = info['name']
            mark = markDict.get(uin, '')

            qqlist = qqDict.get(name, [])
            if len(qqlist) == 1:
                qq = qqlist.pop()
            else:
                qq = self.fetchGroupQQ(uin)
                for x in qqlist:
                    if (qq - x) % 1000000 == 0:
                        qq = x
                        break
                try:
                    qqlist.remove(qq)
                except ValueError:
                    pass

            members = self.fetchGroupMember(info['code'])

            c = contacts.Add('group', str(uin), name, str(qq), '', mark,
                             members)

            if not silence:
                INFO(repr(c))
                for uin, name in members.items():
                    INFO('    成员: %s, uin%s', name, uin)
                INFO('=' * 60)

        if not silence:
            INFO('获取群列表成功,共 %d 个群' % len(result))
示例#9
0
    def smartRequest(self,
                     url,
                     data=None,
                     repeatOnDeny=2,
                     sessionObj=None,
                     **kw):
        session = sessionObj or self.session
        nCE, nTO, nUE, nDE = 0, 0, 0, 0

        while True:
            url = url.format(rand=repr(random.random()))
            html, errorInfo = '', ''
            session.headers.update(**kw)
            try:
                if data is None:
                    resp = session.get(url)
                else:
                    resp = session.post(url, data=data)
            except requests.ConnectionError as e:
                nCE += 1
                errorInfo = '网络错误 %s' % e
            else:
                html = resp.content
                if resp.status_code in (502, 504):
                    session.get(
                        ('http://pinghot.qq.com/pingd?dm=w.qq.com.hot&'
                         'url=/&hottag=smartqq.im.polltimeout&hotx=9999&'
                         'hoty=9999&rand=%s') % random.randint(10000, 99999))
                    if url == 'https://d1.web2.qq.com/channel/poll2':
                        return {'errmsg': ''}
                    nTO += 1
                    errorInfo = '超时'
                else:
                    try:
                        result = JsonLoads(html)
                    except ValueError:
                        nUE += 1
                        errorInfo = ' URL 地址错误'
                    else:
                        retcode = \
                            result.get('retcode', result.get('errCode', -1))
                        if retcode in (0, 1202, 100003):
                            return result.get('result', result)
                        else:
                            nDE += 1
                            errorInfo = '请求被拒绝错误'

            # 出现网络错误或超时可以多试几次 (nCE < 5, nTO < 20);
            # 根据腾讯服务器的改标,增加了尝试次数
            # 若出现 URL 地址错误或 retcode 有误,一般连续 3 次都出错就没必要再试了
            if nCE < 5 and nTO < 20 and nUE < 3 and nDE <= repeatOnDeny:
                DEBUG('第%d次请求“%s”时出现“%s”, html=%s', nCE + nTO + nUE + nDE, url,
                      errorInfo, repr(html))
            else:
                if nTO == 20 and url.startswith(
                        'http://s.web2.qq.com/api/get_friend_uin2'):
                    # 针对某个好友获取不到的情况,先返回一个空值,以确保成功登陆
                    # 防止因个别好友无法获得触发SystemExit,如果是因为其他原因则退出
                    return {'account': -1}

                CRITICAL('第%d次请求“%s”时出现“%s”,终止 QQBot', nCE + nTO + nUE + nDE,
                         url, errorInfo)

                raise RequestError  # (SystemExit)
示例#10
0
文件: qqbot.py 项目: duduscript/qqbot
    def smartRequest(self,
                     url,
                     data=None,
                     repeatOnDeny=2,
                     sessionObj=None,
                     **kw):
        session = sessionObj or self.session
        nCE, nUE, nDE = 0, 0, 0
        while True:
            html, errorInfo = '', ''
            session.headers.update(**kw)
            try:
                if data is None:
                    resp = session.get(url)
                else:
                    resp = session.post(url, data=data)

            except requests.ConnectionError:
                nCE += 1
                errorInfo = '网络错误'

            else:
                if url == 'https://d1.web2.qq.com/channel/poll2':
                    timeOut = False
                    if resp.status_code in (502, 504):
                        timeOut = True
                    else:
                        html = resp.content
                        try:
                            result = JsonLoads(html)
                        except ValueError:
                            timeOut = True

                    if timeOut:
                        session.get(
                            ('http://pinghot.qq.com/pingd?dm=w.qq.com.hot&'
                             'url=/&hottag=smartqq.im.polltimeout&hotx=9999&'
                             'hoty=9999&rand=%s') %
                            random.randint(10000, 99999))
                        return {'errmsg': ''}

                else:
                    html = resp.content
                    try:
                        result = JsonLoads(html)
                    except ValueError:
                        nUE += 1
                        errorInfo = 'URL地址错误'

                if not errorInfo:
                    retcode = result.get('retcode', result.get('errCode', -1))
                    if retcode in (0, 1202, 100003):
                        return result.get('result', result)
                    else:
                        nDE += 1
                        errorInfo = '请求被拒绝错误'

            # 出现网络错误或URL地址错误可以多试几次 (nCE<=4 and nUE<=3);
            # 若 retcode 有误,一般连续 3 次都出错就没必要再试了(nDE<=2)
            if nCE <= 4 and nUE <= 3 and nDE <= repeatOnDeny:
                DEBUG('第%d次请求“%s”时出现“%s”, html=%s', nCE + nUE + nDE, url,
                      errorInfo, repr(html))
            else:
                CRITICAL('第%d次请求“%s”时出现“%s”,终止 QQBot', nCE + nUE + nDE, url,
                         errorInfo)
                raise RequestError  # (SystemExit)