Full Code of lyyyuna/wechat_robot for AI

master ba0d0901fda3 cached
12 files
39.9 KB
11.5k tokens
55 symbols
1 requests
Download .txt
Repository: lyyyuna/wechat_robot
Branch: master
Commit: ba0d0901fda3
Files: 12
Total size: 39.9 KB

Directory structure:
gitextract_yz03lpkv/

├── .gitignore
├── README.md
├── wechat-asyncio/
│   ├── HttpClient.py
│   ├── Monitor.py
│   ├── MsgHandler.py
│   ├── RobotEngine.py
│   ├── RobotPredefinedAnswer.py
│   ├── Wechat.py
│   ├── config.py
│   ├── logger.conf
│   └── main.py
└── wechat-draft/
    └── wechat-robot.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.pyc
*.json
*.jpg
auth.py
__pycache__
*.log
.idea

================================================
FILE: README.md
================================================
# 微信聊天机器人 - 个人账号版

这是一个基于微信网页版接口的,个人账号聊天机器人。

不同于微信公众号和订阅号,个人账号腾讯并没有提供 API 接口,所以只能模拟微信网页版的协议来做。由于使用未公开通信协议,故不能保证向后兼容性。

* wechat-asyncio 是异步实现的。需要 Python 3.5。
* wechat-draft 是很早的第一个可用的版本。只有两个线程。只需要 > Python 3。

## 简单说明

### 依赖

申请一枚图灵机器人 API,新建 auth.py,并写入 

    apikey = 'xxxxxxxxxxx'

* pip3 install aiohttp

### 快速开始

目前使用起来还不友好,且登陆有一定失败率。

    (terminal 1) python3 main.py 

运行后会在当前文件夹内下载二维码,根据终端提示做即可。

1. 若 10s 内二维码下载失败则重来。
2. 若 wx.log 提示 sync 失败则重来。

### 参数调整

在 config.py 中可以对各个时间间隔做调整。

## Changelog

### 2016.2.4

改成了基于 asyncio/aiohttp 的异步框架。现在只有 5 个任务:sync, sendmsg, updategroupinfo, msgloop, monitor。

### 2016.1.23

wechat-robot.py 改用 Python3。原来的 urllib2/urllib 全部改为了 requests。


## 参考

前期参考了 [查看被删的微信好友](https://github.com/0x5e/wechat-deleted-friends)。

也参考了 [Nodejs 版的微信聊天机器人](https://github.com/HalfdogStudio/wechat-user-bot)。


================================================
FILE: wechat-asyncio/HttpClient.py
================================================
# coding=utf-8

import logging
import asyncio
import aiohttp
import json

logger = logging.getLogger('wx')


class HttpClient:
    def __init__(self, client):
        if not isinstance(client, aiohttp.ClientSession):
            raise TypeError('Please init with a aiohttp.ClientSession instance')
        self.__client = client
        self.__cookies = None

    async def get(self, url, params=None):
        try:
            self.__cookies = self.__client.cookies
            async with await self.__client.get(url, params=params) as r:
                #assert r.status == 200
                return await r.text()

        except Exception:
            logger.exception("Network Exception, url: %s, params: %s" % (url, params))
            return None

    async def get_json(self, url, params=None):
        try:
            self.__cookies = self.__client.cookies
            async with await self.__client.get(url, params=params) as r:
                text = await r.text(encoding='utf-8')
                return json.loads(text)

        except Exception:
            logger.exception("Network Exception, url: %s, params: %s" % (url, params))
            return None

    async def get_json_timeout(self, url, params=None):
        try:
            self.__cookies = self.__client.cookies
            with aiohttp.Timeout(2):
                async with await self.__client.get(url, params=params) as r:
                    text = await r.text(encoding='utf-8')
                    return json.loads(text)

        except Exception:
            logger.exception("Network Exception, url: %s, params: %s" % (url, params))
            return None

    async def post(self, url, data, params=None):
        try:
            async with await self.__client.post(url, params=params, data=data) as r:
                #assert r.status == 200
                return await r.text()

        except Exception:
            logger.exception("Network Exception, url: %s, params: %s" % (url, params))
            return None

    async def post_json(self, url, data, params=None):
        try:

            async with await self.__client.post(url, params=params, data=data) as r:
                #assert r.status == 200
                text = await r.text(encoding='utf-8')
                return json.loads(text)

        except Exception:
            logger.exception("Network Exception, url: %s, params: %s" % (url, params))
            return None

    async def post_json_timeout(self, url, data, params=None):
        try:

            with aiohttp.Timeout(2):
                async with await self.__client.post(url, params=params, data=data) as r:
                    #assert r.status == 200
                    text = await r.text(encoding='utf-8')
                    return json.loads(text)

        except Exception:
            logger.exception("Network Exception, url: %s, params: %s" % (url, params))
            return None

    async def downloadfile(self, url, data, filename):
        try:
            async with await self.__client.post(url, data=data) as r:
                #assert r.status == 200
                with open(filename, 'wb') as fd:
                    while True:
                        chunk = await r.content.read(512)
                        if not chunk:
                            break
                        fd.write(chunk)
                return True
        except aiohttp.errors.DisconnectedError:
            return False


================================================
FILE: wechat-asyncio/Monitor.py
================================================
# coding=utf-8

import logging
import asyncio
from time import ctime
import config

logger = logging.getLogger('monitor')

class Monitor():
    def __init__(self, wx):
        self.wx = wx

    async def monitor(self):
        while True:
            logger.info('Monitoring.......... ' + ctime())
            logger.info('retcode %s,  selector %s' % (self.wx.retcode, self.wx.selector))
            logger.info('recvqueue size: %s' % self.wx.recvqueue.qsize())
            logger.info('sendqueue size: %s' % self.wx.sendqueue.qsize())
            logger.info('updatequeue size: %s' % self.wx.updatequeue.qsize())
            logger.info('Monitor end.......... ')

            if self.wx.recvqueue.qsize() > 3:
                while self.wx.recvqueue.qsize() > 1:
                    try:
                        self.wx.recvqueue.get_nowait()
                    except:
                        pass

            if self.wx.sendqueue.qsize() > 3:
                while self.wx.sendqueue.qsize() > 1:
                    try:
                        self.wx.sendqueue.get_nowait()
                    except:
                        pass

            if self.wx.updatequeue.qsize() > 3:
                while self.wx.updatequeue.qsize() > 1:
                    try:
                        self.wx.updatequeue.get_nowait()
                    except:
                        pass

            await asyncio.sleep(config.monitor_interval)


================================================
FILE: wechat-asyncio/MsgHandler.py
================================================
# coding=utf-8

import asyncio
import re

import config
import logging
logger = logging.getLogger('monitor')

class MsgHandler:
    def __init__(self, wx, robot):
        self.wx = wx
        self.robot = robot

    async def __parsemsg(self):
        msg = await self.wx.recvqueue.get()
        # 自己从别的平台发的消息忽略
        if msg['FromUserName'] == self.wx.My['UserName']:
            return None
        # 排除不是发给自己的消息
        if msg['ToUserName'] != self.wx.My['UserName']:
            return None
        # 在黑名单里面
        if msg['FromUserName'] in self.wx.blacklist:
            return None

        msginfo = {}
        # 文字消息
        if msg['MsgType'] == 1:
            content = msg['Content']
            fromsomeone_NickName = ''
            ## 来自群消息
            if msg['FromUserName'].find('@@') != -1:
                fromsomeone = content[:content.find(':<br/>')]
                groupname = msg['FromUserName']
                if groupname not in self.wx.grouplist:
                    await self.wx.updatequeue.put(groupname)
                elif fromsomeone in self.wx.grouplist[groupname]:
                    fromsomeone_NickName = self.wx.grouplist[groupname][fromsomeone]
                    fromsomeone_NickName = '@' + fromsomeone_NickName + ' '
                else:
                    await self.wx.updatequeue.put(groupname)
                # 去掉消息头部的来源信息
                content = content[content.find('>')+1:]
            # 普通消息
            else:
                fromsomeone_NickName = ''

            # print (content)
            if len(content)>1:
                regx = re.compile(r'@.+?\u2005')
                content = regx.sub(' ', content)

            msginfo['Content'] = content
            msginfo['fromsomeone'] = fromsomeone_NickName
            msginfo['FromUserName'] = msg['FromUserName']

            return msginfo
        else:
            return None

    async def msgloop(self):
        while True:
            msginfo = await self.__parsemsg()
            if msginfo != None:
                response = {}
                answser = await self.robot.answser(msginfo)
                response['Content'] = msginfo['fromsomeone'] + answser
                response['user'] = msginfo['FromUserName']
                await self.wx.sendqueue.put(response)

                logger.info(msginfo['fromsomeone'] + ' say: ' + msginfo['Content'])
                logger.info('Harry Potter say: ' + response['Content'])

            await asyncio.sleep(config.msgloop_interval)


================================================
FILE: wechat-asyncio/RobotEngine.py
================================================
# coding=utf-8

import asyncio
import re
from HttpClient import *
import RobotPredefinedAnswer
import random

class RobotEngine():
    def __init__(self, client, apikey):
        self.rbclient = HttpClient(client)
        self.apikey = apikey
        self.acc = 0
        self.lasttext = ''
        self.lastuser = ''

    async def answser(self, msginfo):
        content = msginfo['Content']
        # 去掉英文,因为图灵机器人不支持
        content = re.sub(r'[a-zA-Z]', '', content)
        # 去掉两端空格,不然图灵api那边有问题
        content = content.strip()
        # 做一下字数限制
        content = content[:50]
        # 做完处理发现没有字符了
        if content == '':
            content = self.__randomanswer()

        tuling_data = dict(
            key=self.apikey,
            info=content,
            userid=msginfo['FromUserName'][2:32],  # 把userName的一部分截取,作为userid,这样对话有上下文功能.
        )
        tuling_url = 'http://www.tuling123.com/openapi/api'
        # 使用post方法访问图灵,以免出现content没有经过urlencoded得不到正确结果.
        dic = await self.rbclient.post_json_timeout(tuling_url, data=tuling_data)
        if dic is not None:
            text = dic['text']
        else:
            text = '网络异常。。。。。。。。。。。。'

        # 做一下字数回复的限制
        if len(text)>100:
            text = text[:100]
            text = text + '......'

        # 对于不能回答的问题直接回复数数
        if text.find('不明白你是什么意思,麻烦换一种说法') != -1:
            text = str(self.acc)
            self.acc = self.acc + 1
        if text.find('不明白你说的什么意思') != -1:
            text = str(self.acc)
            self.acc = self.acc + 1
        if text == self.lasttext and msginfo['FromUserName'] == self.lastuser:
            text = self.__randomanswer()

        self.lasttext = text
        self.lastuser = msginfo['FromUserName']
        return text

    def __randomanswer(self):
        diaglen = len(RobotPredefinedAnswer.dialoglist)
        index = random.randint(0, diaglen-1)
        return RobotPredefinedAnswer.dialoglist[index]


================================================
FILE: wechat-asyncio/RobotPredefinedAnswer.py
================================================
dialoglist = [
    '公司下属出错了,没什么大事,我小心提醒一句,就说下次要注意啊,不然艾姆安格瑞',
    '我妈给我介绍对象,看了照片,很美,我脱口而出,excited!' ,
    '财务处通知我薪水涨了,我说,哎呀,你们给我搞的这个涨薪,excited!' ,
    '吃到好吃的东西,不说delicious, 说excited',
    '新同事长的美艳无比,自我介绍时候我忍不住连声赞叹excited' ,
    '看完大圣归来,观后感就是excited' ,
    '遇到任何高兴的事情,都用一棵塞体的表达心情' ,
    '有了点积蓄开始买手表,先后买了三块,不打算再买了,遇到重大场合把三块都戴着以示严肃' ,
    '以前在公交车被人踩了,都是叫哎呀!现在被踩脱口而出 艾姆安格瑞!' ,
    '遇到工科生必问你们学不学engineer drawing,用不用鸭嘴笔' ,
    '身为淮安人说普通话不自觉带扬州口音' ,
    '把格利高里派克演的葛底斯堡演讲视频截下来,对着反复练习,每一次都觉得自己受到了灵魂洗礼,熟练背诵全文没一点问题' ,
    '曾经花了一年的闲余时间听完了莎士比亚的戏剧全集音频,顺着翻完了世图出版的那本全集书,看书的动机就是因为他说中国人要熟悉莎士比亚和贝多芬' ,
    '欢迎客人亲戚时候,都是套路:今天天气预报说有雨,二舅你来了立刻万里无云阳光灿烂' ,
    '跟人提起未来,规划,梦想的时候,必然要提到,人的命运啊,就什么都不知道。个人奋斗当然很重要,但和历史行程也是分不开的' ,
    '被人表扬时候表示谦虚,都是说我很惭愧,就做了这么点微小工作,谢谢大家' ,
    '为了表示志向高洁理想远大,必然要念林则徐的两句诗' ,
    '朋友问我下班去吃日料不,以前回好,现在回吼啊!' ,
    '就会一句粤语,识得唔识得噶' ,
    '形容和某人的深厚友谊一般用谈笑风生这个词' ,
    '对唱歌好有文艺范的妹子充满好感' ,
    '以前很反感说话中夹英,现在能夹就夹,不然体现不出膜法师的风度' ,
    '这些就是比较少见的一些词语运用,类似图样什么的出现的场合太多了,就不一一列举了' ,
    '它,就是化肥,“金坷垃”。' ,
    '你家麦地2米以下藏着丰富的氮磷钾。' ,
    '肥料掺了金坷垃,一袋能顶两袋撒' ,
    '肥料掺了金坷垃,小麦亩产一千八。' ,
    '美国英国法国都在用金坷垃......日本不给用......'
]


================================================
FILE: wechat-asyncio/Wechat.py
================================================
# coding=utf-8


from HttpClient import HttpClient
import aiohttp
import asyncio
import time
import re
import xml.dom.minidom
import json
import html

import config
import logging

logger = logging.getLogger('wx')

class Wechat():
    def __init__(self, client):
        self.__wxclient = HttpClient(client)
        self.tip = 0
        self.deviceId = 'e000701000000000'

        self.recvqueue = asyncio.Queue()
        self.sendqueue = asyncio.Queue()
        self.blacklist = []
        self.updatequeue = asyncio.Queue() # 更新群组信息的请求
        self.grouplist = {} # 存储群组的联系人信息
        # 给 monitor 用
        self.retcode = '0'
        self.selector = '0'

    async def __getuuid(self):
        logger.debug('Entering getuuid.')
        url = 'https://login.weixin.qq.com/jslogin'
        payload = {
            'appid': 'wx782c26e4c19acffb',
            'fun': 'new',
            'lang': 'zh_CN',
            '_': int(time.time()),
        }

        text = await self.__wxclient.post(url=url, data=payload)
        if text == None:
            return False
        logger.info(text)

        regx = r'window.QRLogin.code = (\d+); window.QRLogin.uuid = "(\S+?)"'
        pm = re.search(regx, text)

        code = pm.group(1)
        uuid = pm.group(2)

        self.uuid = uuid
        if code == '200':
            return True
        else:
            return False

    async def __downloadQR(self):
        logger.debug('Entering downloadQR.')
        url = 'https://login.weixin.qq.com/qrcode/' + self.uuid
        payload = {
            't': 'webwx',
            '_': int(time.time()),
        }

        su = await self.__wxclient.downloadfile(url, data=payload, filename='qrimage.jpg')
        logger.info ('请扫描二维码')
        print ('请扫描二维码')
        return su

    async def __waitforlogin(self):
        logger.debug('Waiting for login.......')
        url = 'https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?tip=%s&uuid=%s&_=%s' % (self.tip, self.uuid, int(time.time()))
        text = await self.__wxclient.get(url)

        regx = r'window.code=(\d+);'
        pm = re.search(regx, text)
        code = pm.group(1)

        if code == '201':
            logger.info ('成功扫描,请在手机上点击确认以登录')
            print ('成功扫描,请在手机上点击确认以登录')
            self.tip = 0
        elif code == '200':
            logger.info ('正在登录。。。')
            print ('正在登录。。。')
            regx = r'window.redirect_uri="(\S+?)";'
            pm = re.search(regx, text)
            redirect_uri = pm.group(1) + '&fun=new'
            self.redirect_uri  = redirect_uri
            base_uri = redirect_uri[:redirect_uri.rfind('/')]
            self.base_uri = base_uri

            services = [
                ('wx2.qq.com', 'webpush2.weixin.qq.com'),
                ('qq.com', 'webpush.weixin.qq.com'),
                ('web1.wechat.com', 'webpush1.wechat.com'),
                ('web2.wechat.com', 'webpush2.wechat.com'),
                ('wechat.com', 'webpush.wechat.com'),
                ('web1.wechatapp.com', 'webpush1.wechatapp.com'),
            ]

            push_uri = base_uri
            for (searchUrl, pushUrl) in services:
                if base_uri.find(searchUrl) >= 0:
                    push_uri = 'https://%s/cgi-bin/mmwebwx-bin' % pushUrl
                    break
            self.push_uri = push_uri
        elif code == '408':
            pass

        return code


    async def __checklogin(self):
        logger.debug('Entering checklogin.')
        text = await self.__wxclient.get(self.redirect_uri)

        doc = xml.dom.minidom.parseString(text)
        root = doc.documentElement

        for node in root.childNodes:
            if node.nodeName == 'skey':
                skey = node.childNodes[0].data
            elif node.nodeName == 'wxsid':
                wxsid = node.childNodes[0].data
            elif node.nodeName == 'wxuin':
                wxuin = node.childNodes[0].data
            elif node.nodeName == 'pass_ticket':
                pass_ticket = node.childNodes[0].data

        if not all((skey, wxsid, wxuin, pass_ticket)):
            return False

        BaseRequest = {
            'Uin': int(wxuin),
            'Sid': wxsid,
            'Skey': skey,
            'DeviceID': self.deviceId,
        }
        logger.debug('%s, %s, %s, %s', skey, wxsid, wxuin, pass_ticket)
        self.skey = skey
        self.wxsid = wxsid
        self.wxuin = wxuin
        self.pass_ticket = pass_ticket
        self.BaseRequest = BaseRequest

        return True


    async def __responseState(self, func, BaseResponse):
        ErrMsg = BaseResponse['ErrMsg']
        Ret = BaseResponse['Ret']
        logger.info('func: %s, Ret: %d, ErrMsg: %s' % (func, Ret, ErrMsg))
        if Ret != 0:
            return False
        return True


    async def __webwxinit(self):
        logger.debug('Entering webwxinit.')
        url = self.base_uri + \
            '/webwxinit?pass_ticket=%s&skey=%s&r=%s' % (
                self.pass_ticket, self.skey, int(time.time()))
        payload = {
            'BaseRequest' : self.BaseRequest
        }

        dic = await self.__wxclient.post_json(url=url, data=json.dumps(payload))

        self.My = dic['User']
        self.SyncKey = dic['SyncKey']
        logger.debug('The new SyncKey is: %s' % self.SyncKey)

        return await self.__responseState('webwxinit', dic['BaseResponse'])

    async def __webwxgetcontact(self):
        url = self.base_uri + \
        '/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s' % (
            self.pass_ticket, self.skey, int(time.time()))

        dic = await self.__wxclient.get_json(url)

        SpecialUsers = ["newsapp", "fmessage", "filehelper", "weibo", "qqmail", "tmessage", "qmessage", "qqsync", "floatbottle", "lbsapp", "shakeapp", "medianote", "qqfriend", "readerapp", "blogapp", "facebookapp", "masssendapp",
                    "meishiapp", "feedsapp", "voip", "blogappweixin", "weixin", "brandsessionholder", "weixinreminder", "wxid_novlwrv3lqwv11", "gh_22b87fa7cb3c", "officialaccounts", "notification_messages", "wxitil", "userexperience_alarm"]
        self.blacklist += SpecialUsers

        MemberList = {}
        for member in dic['MemberList']:
            if member['VerifyFlag'] & 8 != 0: # 公众号
                continue
            elif member['UserName'] in SpecialUsers:
                continue
            MemberList[member['UserName']] = {
                'NickName' : member['NickName'] ,
                'DisplayName' : member['DisplayName']
            }

        self.memberlist = MemberList
        logger.info('You have %s friends.' % len(MemberList))



    async def __login(self):
        success = await self.__getuuid()
        if not success:
            logger.info ('获取 uuid 失败')
            print ('获取 uuid 失败')
        success = await self.__downloadQR()
        if not success:
            logger.info ('获取二维码失败')
            print ('获取二维码失败')

        while await self.__waitforlogin() != '200':
            pass

        success = await self.__checklogin()
        if not success:
            logger.info ('登陆失败')
            print ('登陆失败')
        logger.info ('登陆成功')
        print ('登陆成功')
        success = await self.__webwxinit()
        if not success:
            logger.info ('初始化失败')
            print ('初始化失败')
        logger.info ('初始化成功')
        print ('初始化成功')

        await self.__webwxgetcontact()

    def __syncKey(self):
        SyncKey = self.SyncKey
        SyncKeyItems = ['%s_%s' % (item['Key'], item['Val'])
                        for item in SyncKey['List']]
        SyncKeyStr = '|'.join(SyncKeyItems)
        return SyncKeyStr

    async def __synccheck(self):
        url = self.push_uri + '/synccheck?'
        BaseRequest = self.BaseRequest
        params = {
            'skey': BaseRequest['Skey'] ,
            'sid': BaseRequest['Sid'] ,
            'uin': BaseRequest['Uin'] ,
            'deviceId': BaseRequest['DeviceID'] ,
            'synckey': self.__syncKey() ,
            'r': int(time.time()*1000)
        }
        text = await self.__wxclient.get(url, params = params)
        if text == None:
            return ('1111', '1111')

        regx = r'window.synccheck={retcode:"(\d+)",selector:"(\d+)"}'
        pm = re.search(regx, text)

        retcode = pm.group(1)
        selector = pm.group(2)
        logger.info('retcode: %s, selector: %s' % (retcode, selector))
        return (retcode, selector)

    async def __webwxsync(self):
        url = self.base_uri + '/webwxsync?'
        payload = {
            'BaseRequest' : self.BaseRequest ,
            'SyncKey' : self.SyncKey ,
            'rr' : ~int(time.time())
        }
        params = {
            'skey' : self.BaseRequest['Skey'] ,
            'pass_ticket' : self.pass_ticket ,
            'sid' : self.BaseRequest['Sid']
        }

        dic = await self.__wxclient.post_json(url, params=params, data=json.dumps(payload))
        if dic == None:
            return
        # 更新 synckey
        self.SyncKey = dic['SyncKey']

        await self.__responseState('webwxsync', dic['BaseResponse'])

        msglist = dic['AddMsgList']
        for msg in msglist:
            await self.recvqueue.put(msg)


    async def __webwxsendmsg(self, content, user):
        url = self.base_uri + \
            '/webwxsendmsg?pass_ticket=%s' % (self.pass_ticket)

        msgid = int(time.time()*10000000)
        msg = {
            'ClientMsgId' : msgid ,
            'Content' : content,
            'FromUserName' : self.My['UserName'] ,
            'LocalID' : msgid ,
            'ToUserName' : user,
            'Type' : 1
        }
        payload = {
            'BaseRequest' : self.BaseRequest ,
            'Msg' : msg
        }
        data = json.dumps(payload, ensure_ascii=False)
        data = data.encode('utf-8')

        text = await self.__wxclient.post(url, data=data)


    async def __webwxbatchgetcontact(self, groupname):
        url = self.base_uri + '/webwxbatchgetcontact?'
        List = [{
            'ChatRoomId' : '',
            'UserName' : groupname
        }]
        payload = {
            'BaseRequest': self.BaseRequest ,
            'Count' : 1 ,
            'List' : List
        }
        params = {
            'lang' : 'zh_CN' ,
            'type' : 'ex' ,
            'pass_ticket' : self.pass_ticket ,
            'r' : int(time.time())
        }

        dic = await self.__wxclient.post_json(url, params=params, data=json.dumps(payload))
        if dic == None:
            return
        GroupMapUsers = {}
        ContactList = dic['ContactList']
        for contact in ContactList:
            memberlist = contact['MemberList']
            for member in memberlist:
                # 默认 @群名片,没有群名片就 @昵称
                nickname = member['NickName']
                displayname = member['DisplayName']
                AT = ''
                if displayname == '':
                    # 有些人的昵称会有表情 <span> 会表示成 &lt;span&gt;
                    # 需要 html.unescape() 转义一下
                    AT = html.unescape(nickname)
                else:
                    AT = html.unescape(displayname)
                GroupMapUsers[member['UserName']] = AT

        self.grouplist[groupname] = GroupMapUsers

    async def sync(self):
        await self.__login()
        logger.info ('开始心跳噗通噗咚 咚咚咚!!!!')
        print ('开始心跳噗通噗咚 咚咚咚!!!!')
        logger.info('Begin to sync with wx server.....')
        while True:
            retcode, selector = await self.__synccheck()
            if retcode != '0':
                logger.info ('sync 失败')
                print ('sync 失败')
            if selector != '0':
                await self.__webwxsync()

            await asyncio.sleep(config.sync_interval)
            self.retcode = retcode
            self.selector = selector


    async def sendmsg(self):
        while True:
            response = await self.sendqueue.get()
            # 不要发的太频繁,在拿到 response 之后歇一秒
            await asyncio.sleep(config.send_interval)
            await self.__webwxsendmsg(response['Content'], response['user'])

    async def updategroupinfo(self):
        while True:
            groupname = await self.updatequeue.get()

            logger.info('更新群信息开始')
            await self.__webwxbatchgetcontact(groupname)
            await asyncio.sleep(config.updategroupinfo_interval)
            logger.info('更新群信息结束')


================================================
FILE: wechat-asyncio/config.py
================================================
send_interval = 0.5
sync_interval = 1
updategroupinfo_interval = 1
monitor_interval = 10
msgloop_interval = 1


================================================
FILE: wechat-asyncio/logger.conf
================================================
#logger.conf


###############################################

[loggers]
keys=root,wx,monitor

[logger_root]
level=DEBUG
handlers=hand01

[logger_wx]
handlers=hand01
qualname=wx
propagate=0

[logger_monitor]
handlers=hand02
qualname=monitor
propagate=0

###############################################

[handlers]
keys=hand01,hand02

[handler_hand01]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=form01
args=('wx.log', 'a', 10*1024*1024, 5)

[handler_hand02]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=form01
args=('monitor.log', 'a', 10*1024*1024, 5)

###############################################

[formatters]
keys=form01

[formatter_form01]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
datefmt=%a, %d %b %Y %H:%M:%S


================================================
FILE: wechat-asyncio/main.py
================================================
# coding=utf-8

import aiohttp
import asyncio

from Wechat import Wechat
from MsgHandler import MsgHandler
from RobotEngine import RobotEngine
from Monitor import Monitor
import auth

import logging
import logging.config

logging.config.fileConfig("logger.conf")

with aiohttp.ClientSession() as client, aiohttp.ClientSession() as rclient:
    wx = Wechat(client)
    robot = RobotEngine(rclient, auth.apikey)
    msg = MsgHandler(wx, robot)
    god = Monitor(wx)
    tasks = [
            wx.sync() ,
            wx.sendmsg() ,
            wx.updategroupinfo() ,
            msg.msgloop() ,
            god.monitor()
            ]
    asyncio.get_event_loop().run_until_complete(asyncio.wait(tasks))


================================================
FILE: wechat-draft/wechat-robot.py
================================================
# coding=utf-8

import os
import requests
import simplejson as json
import time
import re
import xml.dom.minidom
# from collections import deque
import queue
import html

import threading
# lock = threading.Lock()

DEBUG = False
LOG = True

deviceId = 'e000000000000000' 
g_info = {}
g_info['tip'] = 0
g_queue = queue.Queue()# []

import config
apikey = config.apikey

def getUUID():
    global g_info

    url = 'https://login.weixin.qq.com/jslogin'
    params = {
        'appid': 'wx782c26e4c19acffb',
        'fun': 'new',
        'lang': 'zh_CN',
        '_': int(time.time()),   
    }

    r = requests.post(url, params)
    if DEBUG:
        print (r.text)
    text = r.text
    regx = r'window.QRLogin.code = (\d+); window.QRLogin.uuid = "(\S+?)"'
    pm = re.search(regx, text)

    code = pm.group(1)
    uuid = pm.group(2)

    g_info['uuid'] = uuid
    if code == '200':
        return True 

    return False

def showQRImage():
    global g_info

    uuid = g_info['uuid']
    url = 'https://login.weixin.qq.com/qrcode/' + uuid
    params = {
        't': 'webwx',
        '_': int(time.time()),
    }

    r = requests.post(url, params)
    g_info['tip'] = 1

    with open('qrcode.jpg', 'wb') as fd:
        for chunk in r.iter_content(512):
            fd.write(chunk)

    print ('请扫描二维码。。。')

def waitForLogin():
    global g_info

    tip = g_info['tip']
    uuid = g_info['uuid']
    url = 'https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?tip=%s&uuid=%s&_=%s' % (
        tip, uuid, int(time.time()))  

    r = requests.get(url)
    text = r.text
    regx = r'window.code=(\d+);'
    pm = re.search(regx, text)
    
    code = pm.group(1)
    if code == '201':
        print ('成功扫描,请在手机上点击确认以登录')
        g_info['tip'] = 0
    elif code == '200':
        print ('正在登录。。。')
        regx = r'window.redirect_uri="(\S+?)";'
        pm = re.search(regx, text)
        redirect_uri = pm.group(1) + '&fun=new'
        g_info['redirect_uri']  = redirect_uri
        base_uri = redirect_uri[:redirect_uri.rfind('/')]
        g_info['base_uri'] = base_uri

        services = [
            ('wx2.qq.com', 'webpush2.weixin.qq.com'),
            ('qq.com', 'webpush.weixin.qq.com'),
            ('web1.wechat.com', 'webpush1.wechat.com'),
            ('web2.wechat.com', 'webpush2.wechat.com'),
            ('wechat.com', 'webpush.wechat.com'),
            ('web1.wechatapp.com', 'webpush1.wechatapp.com'),
        ]

        push_uri = base_uri
        for (searchUrl, pushUrl) in services:
            if base_uri.find(searchUrl) >= 0:
                push_uri = 'https://%s/cgi-bin/mmwebwx-bin' % pushUrl
                break  
        g_info['push_uri'] = push_uri

    elif code == '408':
        pass

    return code

def login():
    global g_info

    redirect_uri = g_info['redirect_uri']
    r = requests.get(redirect_uri)


    g_info['cookies'] = r.cookies

    doc = xml.dom.minidom.parseString(r.text)
    root = doc.documentElement

    for node in root.childNodes:
        if node.nodeName == 'skey':
            skey = node.childNodes[0].data
        elif node.nodeName == 'wxsid':
            wxsid = node.childNodes[0].data
        elif node.nodeName == 'wxuin':
            wxuin = node.childNodes[0].data
        elif node.nodeName == 'pass_ticket':
            pass_ticket = node.childNodes[0].data   

    if not all((skey, wxsid, wxuin, pass_ticket)):
        return False

    BaseRequest = {
        'Uin': int(wxuin),
        'Sid': wxsid,
        'Skey': skey,
        'DeviceID': deviceId,
    }

    g_info['skey'] = skey
    g_info['wxsid'] = wxsid
    g_info['wxuin'] = wxuin
    g_info['pass_ticket'] = pass_ticket
    g_info['BaseRequest'] = BaseRequest

    if DEBUG:
        print (skey, wxsid, wxuin)

    return True



def responseState(func, BaseResponse):
    ErrMsg = BaseResponse['ErrMsg']
    Ret = BaseResponse['Ret']
    if DEBUG:
        print('func: %s, Ret: %d, ErrMsg: %s' % (func, Ret, ErrMsg))

    if Ret != 0:
        return False

    return True

def webwxinit():
    global g_info

    base_uri = g_info['base_uri']
    pass_ticket = g_info['pass_ticket']
    skey = g_info['skey']
    BaseRequest = g_info['BaseRequest']

    url = base_uri + \
        '/webwxinit?pass_ticket=%s&skey=%s&r=%s' % (
            pass_ticket, skey, int(time.time()))
    params = {
        'BaseRequest': BaseRequest
    }

    r = requests.post(url, json.dumps(params))
    text = r.text

    if DEBUG:
        with open('webwxinit.json', 'wb') as fd:
            for chunk in r.iter_content(512):
                fd.write(chunk)

    dic = json.loads(text)
    ContactList = dic['ContactList']
    My = dic['User']
    SyncKey = dic['SyncKey']

    g_info['ContactList'] = ContactList
    g_info['My'] = My 
    g_info['SyncKey'] = SyncKey

    state = responseState('webwxinit', dic['BaseResponse'])
    return state

def webwxgetcontact():
    global g_info

    base_uri = g_info['base_uri']
    pass_ticket = g_info['pass_ticket']
    skey = g_info['skey']

    url = base_uri + \
        '/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s' % (
            pass_ticket, skey, int(time.time()))
    headers = {'Content-Type':'application/json; charset=UTF-8'}
    r = requests.get(url,headers=headers,cookies=g_info['cookies'])
    text = r.text

    if DEBUG:
        with open('webwxgetcontact.json', 'wb') as fd:
            for chunk in r.iter_content(512):
                fd.write(chunk)

    
    dic = json.loads(text, 'utf-8')
    MemberList = dic['MemberList']
    SpecialUsers = ["newsapp", "fmessage", "filehelper", "weibo", "qqmail", "tmessage", "qmessage", "qqsync", "floatbottle", "lbsapp", "shakeapp", "medianote", "qqfriend", "readerapp", "blogapp", "facebookapp", "masssendapp",
                    "meishiapp", "feedsapp", "voip", "blogappweixin", "weixin", "brandsessionholder", "weixinreminder", "wxid_novlwrv3lqwv11", "gh_22b87fa7cb3c", "officialaccounts", "notification_messages", "wxitil", "userexperience_alarm"]
    for i in range(len(MemberList) - 1, -1, -1):
        Member = MemberList[i]
        if Member['VerifyFlag'] & 8 != 0:  # 公众号/服务号
            MemberList.remove(Member)
        elif Member['UserName'] in SpecialUsers:  # 特殊账号
            MemberList.remove(Member)   
    
    _MemberList = {}
    for user in MemberList:
        _MemberList[user['UserName']] = user['NickName']

    g_info['MemberList'] = _MemberList


def syncKey():
    global g_info

    SyncKey = g_info['SyncKey']
    SyncKeyItems = ['%s_%s' % (item['Key'], item['Val'])
                    for item in SyncKey['List']]
    SyncKeyStr = '|'.join(SyncKeyItems)
    return SyncKeyStr

def syncCheck():
    global g_info

    push_uri = g_info['push_uri']
    BaseRequest = g_info['BaseRequest']
    url = push_uri + '/synccheck?'
    params = {
        'skey': BaseRequest['Skey'],
        'sid': BaseRequest['Sid'],
        'uin': BaseRequest['Uin'],
        'deviceId': BaseRequest['DeviceID'],
        'synckey': syncKey(),
        'r': int(time.time()),
    }

    r = requests.get(url, params=params, cookies=g_info['cookies'], timeout=300)
    text = r.text
    regx = r'window.synccheck={retcode:"(\d+)",selector:"(\d+)"}'
    pm = re.search(regx, text)    

    retcode = pm.group(1)
    selector = pm.group(2)

    if DEBUG or LOG:
        print (text)

    return (retcode, selector)


def webwxsync():
    global g_info

    base_uri = g_info['base_uri']
    BaseRequest = g_info['BaseRequest']
    SyncKey = g_info['SyncKey']
    pass_ticket = g_info['pass_ticket']
    # url = base_uri + '/webwxsync?lang=zh_CN&skey=%s&sid=%s&pass_ticket=%s' % (
    #     BaseRequest['Skey'], BaseRequest['Sid'], quote_plus(pass_ticket))
    url = base_uri + '/webwxsync?'
    params = {
        'BaseRequest': BaseRequest,
        'SyncKey': SyncKey,
        'rr': ~int(time.time()),
    } 
    url_params = {
        # 'lang' : 'zh_CN' ,
        'skey' : BaseRequest['Skey'] ,
        'pass_ticket' : pass_ticket ,
        'sid' : BaseRequest['Sid']
    }
    headers = {
        'ContentType': 'application/json; charset=UTF-8'
    }
    r = requests.post(url, params=url_params, data=json.dumps(params), headers = headers, cookies=g_info['cookies'])

    # if DEBUG:
    #     global i 
    #     i = i + 1
    #     with open('sync' +  str(i) + '.json', 'wb') as fd:
    #         for chunk in r.iter_content(512):
    #             fd.write(chunk)
    r.encoding = 'utf-8'
    dic = json.loads(r.text)
    # print (dic)
    # 更新 synckey
    g_info['SyncKey'] = dic['SyncKey']
    state = responseState('webwxsync', dic['BaseResponse'])

    msg_list = dic['AddMsgList']
    if DEBUG:
        print (msg_list)

    return (state, msg_list)


def getMsg(msg_list):
    global g_info, g_queue

    My = g_info['My']

    for msg in msg_list:
        if msg['MsgType'] != 1:
            continue
        if msg['FromUserName'] == My['UserName']:
            continue
        if msg['ToUserName'] == My['UserName']:
            response = {}
            content = msg['Content']

            # 群消息中 :<br/> 之前是 UserName
            if content.find(':<br/>') != -1:
                fromsomeone = content[:content.find(':<br/>')]
            else:
                fromsomeone = ''

            fromsomeone_NickName = ''
            if msg['FromUserName'].find('@@') != -1:
                # 如果是来自群,那就试着去 g_info[] 对应的群中找群成员列表
                groupName = msg['FromUserName']
                # 群还没有记录
                if groupName not in g_info:
                    g_info['Group_UserName_Req'] = msg['FromUserName']
                # 在群列表中有了,因为可能群成员会变化,所以要再次找一遍
                elif fromsomeone in g_info[groupName]:
                    fromsomeone_NickName = g_info[groupName][fromsomeone]
                    fromsomeone_NickName = '@' + fromsomeone_NickName + ' '
                # 找不到,所以置标志位,会在另一个群中触发寻找行为
                else:
                    g_info['Group_UserName_Req'] = msg['FromUserName']
            else:
                fromsomeone_NickName = ''

            response['fromsomeone'] = fromsomeone_NickName
            response['Content'] = content[content.find('>')+1:]
            response['FromUserName'] = msg['FromUserName']

            # g_info['Group_UserName_Req'] = response['FromUserName']

            # 不停地塞新消息
            # lock.acquire()
            # try:
            #     g_queue.append(response)
            # finally:
            #     lock.release()
            # print (response['Content'])

            # test
            if g_queue.qsize() > 5:
                g_queue.get()
                g_queue.get()
            g_queue.put(response)

    if LOG:
        print ('getmsg queue: %s' % g_queue.qsize())


def webwxsendmsg(content, user):
    global g_info

    base_uri = g_info['base_uri']
    pass_ticket = g_info['pass_ticket']
    BaseRequest = g_info['BaseRequest']
    My = g_info['My']

    wxuin = BaseRequest['Uin']
    wxsid = BaseRequest['Sid']
    skey = BaseRequest['Skey']
    deviceId = BaseRequest['DeviceID']

    url = base_uri + \
    '/webwxsendmsg?pass_ticket=%s' % (pass_ticket)

    msgid = int(time.time()*10000000)
    msg = {
        'ClientMsgId' : msgid ,
        'Content' : content,
        'FromUserName' : My['UserName'] ,
        'LocalID' : msgid ,
        'ToUserName' : user,
        'Type' : 1
    }
    params = {
        'BaseRequest' : BaseRequest,
        'Msg' : msg
    }
    data = json.dumps(params, ensure_ascii=False)
    # print (data)
    data = data.encode('utf-8')
    r = requests.post(url, data=data, cookies=g_info['cookies'])


def sendMsg():
    global g_info, g_queue

    MemberList = g_info['MemberList']
    tuling_url = 'http://www.tuling123.com/openapi/api?key=' + apikey + '&info='

    time.sleep(1)
    if LOG:
        print ('sendmsg queue: %s' % g_queue.qsize())
    while g_queue.empty() is False:
        # lock.acquire()
        # try:
        #     response = g_queue.popleft()
        # finally:
        #     lock.release()
        response = g_queue.get()

        content = response['Content']
        from_user = response['FromUserName']
        AT = response['fromsomeone']
        tuling_url = tuling_url + content
        try:
            data = requests.get(tuling_url)
            data = json.loads(data.text)
            text = data['text']
        except:
            text = '网络异常。。。。。'          
        webwxsendmsg(AT + text, from_user)
        time.sleep(1)

        if LOG:
            print
            print ('机器人收到回复:%s' % content)
            print ('机器人的回复: %s' % text)
            print




def webwxbatchgetcontact(UserName):
    global g_info

    base_uri = g_info['base_uri']
    pass_ticket = g_info['pass_ticket']
    BaseRequest = g_info['BaseRequest']

    url = base_uri + '/webwxbatchgetcontact?'


    List = [{
        'ChatRoomId' : '',
        'UserName' : UserName
    }]
    
    post_params = {
        'BaseRequest': BaseRequest ,
        'Count' : 1 ,
        'List' : List
    } 
    url_params = {
        'lang' : 'zh_CN' ,
        'type' : 'ex' ,
        'pass_ticket' : pass_ticket ,
        'r' : int(time.time())
    }

    headers = {
        'ContentType': 'application/json; charset=UTF-8'
    }
    r = requests.post(url, params=url_params, data=json.dumps(post_params), headers = headers, cookies=g_info['cookies'])

    r.encoding = 'utf-8'
    dic = json.loads(r.text)    


    GroupMapUsers = {}
    ContactList = dic['ContactList']
    for contact in ContactList:
        memberlist = contact['MemberList']
        for member in memberlist:
            # 默认 @群名片,没有群名片就 @昵称
            nickname = member['NickName']
            displayname = member['DisplayName']
            AT = ''
            if displayname == '':
                # 有些人的昵称会有表情 <span> 会表示成 &lt;span&gt;
                # 需要 html.unescape() 转义一下
                AT = html.unescape(nickname)
            else:
                AT = html.unescape(displayname)
            GroupMapUsers[member['UserName']] = AT

            if DEBUG:
                print (member['NickName'])

    # 整群的成员列表消息记录
    g_info[UserName] = GroupMapUsers




def getgroupinfo():
    global g_info

    if 'Group_UserName_Req' not in g_info:
        return
    if g_info['Group_UserName_Req'] == '0':
        return

    Group_UserName = g_info['Group_UserName_Req']
    webwxbatchgetcontact(Group_UserName)

    # 这个变量表示一次 获取群成员列表 请求。请求完毕置空
    g_info['Group_UserName_Req'] = '0'

    time.sleep(0.5)


    
def heartBeatLoop():
    while True:
        retcode, selector = syncCheck()
        if retcode != '0':
            print ('sync 失败。。。')
        if selector == '2':
            state, msg_list = webwxsync()
            getMsg(msg_list)
            getgroupinfo()

        time.sleep(1)



def main():
    global g_info

    if not getUUID():
        print ('获取 uuid 失败')
        return
    print ('获取二维码图片中。。。')
    showQRImage()
    time.sleep(1)

    while waitForLogin() != '200':
        pass

    if not login():
        print ('登陆失败')
        return

    if not webwxinit():
        print ('初始化失败')
        return

    print ('登陆')

    print ('获取好友。。。。')
    webwxgetcontact()

    print ('开始心跳 噗咚噗通')
    t1 = threading.Thread(target=heartBeatLoop)
    t1.start()

    MemberCount = len(g_info['MemberList'])
    print ('这位同志啊,你有 %s 个好友' % MemberCount)

    try:
        while True:
            sendMsg()
            time.sleep(1.5)
    except KeyboardInterrupt:
        print ('bye bye ~')

if __name__ == '__main__':
    main()
Download .txt
gitextract_yz03lpkv/

├── .gitignore
├── README.md
├── wechat-asyncio/
│   ├── HttpClient.py
│   ├── Monitor.py
│   ├── MsgHandler.py
│   ├── RobotEngine.py
│   ├── RobotPredefinedAnswer.py
│   ├── Wechat.py
│   ├── config.py
│   ├── logger.conf
│   └── main.py
└── wechat-draft/
    └── wechat-robot.py
Download .txt
SYMBOL INDEX (55 symbols across 6 files)

FILE: wechat-asyncio/HttpClient.py
  class HttpClient (line 11) | class HttpClient:
    method __init__ (line 12) | def __init__(self, client):
    method get (line 18) | async def get(self, url, params=None):
    method get_json (line 29) | async def get_json(self, url, params=None):
    method get_json_timeout (line 40) | async def get_json_timeout(self, url, params=None):
    method post (line 52) | async def post(self, url, data, params=None):
    method post_json (line 62) | async def post_json(self, url, data, params=None):
    method post_json_timeout (line 74) | async def post_json_timeout(self, url, data, params=None):
    method downloadfile (line 87) | async def downloadfile(self, url, data, filename):

FILE: wechat-asyncio/Monitor.py
  class Monitor (line 10) | class Monitor():
    method __init__ (line 11) | def __init__(self, wx):
    method monitor (line 14) | async def monitor(self):

FILE: wechat-asyncio/MsgHandler.py
  class MsgHandler (line 10) | class MsgHandler:
    method __init__ (line 11) | def __init__(self, wx, robot):
    method __parsemsg (line 15) | async def __parsemsg(self):
    method msgloop (line 62) | async def msgloop(self):

FILE: wechat-asyncio/RobotEngine.py
  class RobotEngine (line 9) | class RobotEngine():
    method __init__ (line 10) | def __init__(self, client, apikey):
    method answser (line 17) | async def answser(self, msginfo):
    method __randomanswer (line 61) | def __randomanswer(self):

FILE: wechat-asyncio/Wechat.py
  class Wechat (line 18) | class Wechat():
    method __init__ (line 19) | def __init__(self, client):
    method __getuuid (line 33) | async def __getuuid(self):
    method __downloadQR (line 60) | async def __downloadQR(self):
    method __waitforlogin (line 73) | async def __waitforlogin(self):
    method __checklogin (line 117) | async def __checklogin(self):
    method __responseState (line 153) | async def __responseState(self, func, BaseResponse):
    method __webwxinit (line 162) | async def __webwxinit(self):
    method __webwxgetcontact (line 179) | async def __webwxgetcontact(self):
    method __login (line 206) | async def __login(self):
    method __syncKey (line 234) | def __syncKey(self):
    method __synccheck (line 241) | async def __synccheck(self):
    method __webwxsync (line 264) | async def __webwxsync(self):
    method __webwxsendmsg (line 290) | async def __webwxsendmsg(self, content, user):
    method __webwxbatchgetcontact (line 313) | async def __webwxbatchgetcontact(self, groupname):
    method sync (line 353) | async def sync(self):
    method sendmsg (line 371) | async def sendmsg(self):
    method updategroupinfo (line 378) | async def updategroupinfo(self):

FILE: wechat-draft/wechat-robot.py
  function getUUID (line 27) | def getUUID():
  function showQRImage (line 54) | def showQRImage():
  function waitForLogin (line 73) | def waitForLogin():
  function login (line 120) | def login():
  function responseState (line 165) | def responseState(func, BaseResponse):
  function webwxinit (line 176) | def webwxinit():
  function webwxgetcontact (line 211) | def webwxgetcontact():
  function syncKey (line 249) | def syncKey():
  function syncCheck (line 258) | def syncCheck():
  function webwxsync (line 287) | def webwxsync():
  function getMsg (line 333) | def getMsg(msg_list):
  function webwxsendmsg (line 394) | def webwxsendmsg(content, user):
  function sendMsg (line 429) | def sendMsg():
  function webwxbatchgetcontact (line 468) | def webwxbatchgetcontact(UserName):
  function getgroupinfo (line 530) | def getgroupinfo():
  function heartBeatLoop (line 548) | def heartBeatLoop():
  function main (line 562) | def main():
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (47K chars).
[
  {
    "path": ".gitignore",
    "chars": 50,
    "preview": "*.pyc\n*.json\n*.jpg\nauth.py\n__pycache__\n*.log\n.idea"
  },
  {
    "path": "README.md",
    "chars": 843,
    "preview": "# 微信聊天机器人 - 个人账号版\n\n这是一个基于微信网页版接口的,个人账号聊天机器人。\n\n不同于微信公众号和订阅号,个人账号腾讯并没有提供 API 接口,所以只能模拟微信网页版的协议来做。由于使用未公开通信协议,故不能保证向后兼容性。\n\n"
  },
  {
    "path": "wechat-asyncio/HttpClient.py",
    "chars": 3461,
    "preview": "# coding=utf-8\n\nimport logging\nimport asyncio\nimport aiohttp\nimport json\n\nlogger = logging.getLogger('wx')\n\n\nclass HttpC"
  },
  {
    "path": "wechat-asyncio/Monitor.py",
    "chars": 1439,
    "preview": "# coding=utf-8\n\nimport logging\nimport asyncio\nfrom time import ctime\nimport config\n\nlogger = logging.getLogger('monitor'"
  },
  {
    "path": "wechat-asyncio/MsgHandler.py",
    "chars": 2511,
    "preview": "# coding=utf-8\n\nimport asyncio\nimport re\n\nimport config\nimport logging\nlogger = logging.getLogger('monitor')\n\nclass MsgH"
  },
  {
    "path": "wechat-asyncio/RobotEngine.py",
    "chars": 1944,
    "preview": "# coding=utf-8\n\nimport asyncio\nimport re\nfrom HttpClient import *\nimport RobotPredefinedAnswer\nimport random\n\nclass Robo"
  },
  {
    "path": "wechat-asyncio/RobotPredefinedAnswer.py",
    "chars": 1102,
    "preview": "dialoglist = [\n    '公司下属出错了,没什么大事,我小心提醒一句,就说下次要注意啊,不然艾姆安格瑞',\n    '我妈给我介绍对象,看了照片,很美,我脱口而出,excited!' ,\n    '财务处通知我薪水涨了,我说,"
  },
  {
    "path": "wechat-asyncio/Wechat.py",
    "chars": 12385,
    "preview": "# coding=utf-8\n\n\nfrom HttpClient import HttpClient\nimport aiohttp\nimport asyncio\nimport time\nimport re\nimport xml.dom.mi"
  },
  {
    "path": "wechat-asyncio/config.py",
    "chars": 110,
    "preview": "send_interval = 0.5\nsync_interval = 1\nupdategroupinfo_interval = 1\nmonitor_interval = 10\nmsgloop_interval = 1\n"
  },
  {
    "path": "wechat-asyncio/logger.conf",
    "chars": 779,
    "preview": "#logger.conf\n\n\n###############################################\n\n[loggers]\nkeys=root,wx,monitor\n\n[logger_root]\nlevel=DEBU"
  },
  {
    "path": "wechat-asyncio/main.py",
    "chars": 701,
    "preview": "# coding=utf-8\n\nimport aiohttp\nimport asyncio\n\nfrom Wechat import Wechat\nfrom MsgHandler import MsgHandler\nfrom RobotEng"
  },
  {
    "path": "wechat-draft/wechat-robot.py",
    "chars": 15520,
    "preview": "# coding=utf-8\n\nimport os\nimport requests\nimport simplejson as json\nimport time\nimport re\nimport xml.dom.minidom\n# from "
  }
]

About this extraction

This page contains the full source code of the lyyyuna/wechat_robot GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (39.9 KB), approximately 11.5k tokens, and a symbol index with 55 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!