Skip to content
This repository has been archived by the owner on Aug 23, 2020. It is now read-only.

Commit

Permalink
细化文档,增加“获取好友备注名失败表”时的处理。
Browse files Browse the repository at this point in the history
  • Loading branch information
pandolia committed Mar 22, 2017
1 parent b15f46b commit 4b9d2ad
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 102 deletions.
31 changes: 19 additions & 12 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ list 命令提供强大的联系人查询功能,用法示例如下:

将列出所有名为 “机器人测试” 的群。

send 命令中第三个参数和 list 命令中的第三、四个参数格式一致。要注意,如果有重名现象,会给所有重名的联系人发信息。 另外要注意,第二个参数只能是 buddy/group/discuss ,不可以为 group-member/discuss-member 。
send 命令中第三个参数和 list 命令中的第三、四个参数格式一致。要注意,如果有重名现象,会给所有重名的联系人发信息。 另外要注意,第二个参数只能是 buddy/group/discuss ,不能是 group-member/discuss-member 。

另外,QQBot 启动后,用另外一个 QQ 向本 QQ 发送 “--version” ,则 QQBot 会自动回复: “QQBot-v2.x.x” 。

Expand Down Expand Up @@ -101,11 +101,11 @@ send 命令中第三个参数和 list 命令中的第三、四个参数格式一
QQBot 开始运行后,每收到一条 QQ 消息,会将消息来源、消息内容以及一个 QQBot 对象传递给上面注册的消息响应函数。其中:

bot : QQBot 对象,提供 List/SendTo/Stop/Restart 四个接口,详见本文档第五节
contact : QContact 对象,消息的发送者,具有 ctype/qq/uin/name/nick/mark/card 属性,这些属性都是 str 对象
contact : QContact 对象,消息的发送者,具有 ctype/qq/uin/nick/mark/card/name 属性,这些属性都是 str 对象
member : QContact 对象,仅当本消息为 群或讨论组 消息时有效,代表实际发消息的成员
content : str 对象,消息内容

QContact 对象的 ctype 属性可以为 'buddy'/'group'/'discuss'/'group-member'/'discuss-member' ,代表 好友/群/讨论组/群成员/讨论组成员。
一个 QContact 对象都代表一个联系人,它的 ctype 属性可以为 'buddy'/'group'/'discuss'/'group-member'/'discuss-member' ,代表 好友/群/讨论组/群成员/讨论组成员 。注意所有 QContact 对象都是 **只读对象** ,只能读取它的属性,不能设置它的属性,也不能向它添加额外的属性。 不同类型的 QContact 对象的 nick/mark/card/name 属性所代表的含义有所不同,参见 [这里](https://github.com/pandolia/qqbot/blob/master/contact-attr-meannings.png)

可以调用 QQBot 对象的 SendTo 接口向 QContact 对象发送消息,但要注意:**不可以向 群成员/讨论组成员 发送消息**

Expand All @@ -130,11 +130,11 @@ QContact 对象的 ctype 属性可以为 'buddy'/'group'/'discuss'/'group-member

QQBot 对象提供 List/SendTo/Stop/Restart 四个公开接口,一般情况下,请勿 调用/存取 此对象的其他 方法/属性 。以下介绍 List/SendTo 接口。

#### (1) bot.List(tinfo, [cinfo]) --> [contact0, contact1, ..., ]
#### (1) bot.List(tinfo, [cinfo]) --> [contact0, contact1, ..., ]/[]/None

对应上面的 list 命令。返回一个联系人对象( QContact 对象)列表
对应上面的 list 命令。返回联系人对象( QContact 对象)列表或者 None

List 接口第一个参数 tinfo 可以为 'buddy'/'group'/'discuss' ,第二个参数是可选的(和 list 命令的第三个参数格式一致)。示例:
List 接口的第一个参数 tinfo 可以为 'buddy'/'group'/'discuss' ,第二个参数是可选的(和 list 命令的第三个参数格式一致)。示例:

# 返回所有好友的列表:
>>> bot.List('buddy')
Expand All @@ -150,10 +150,17 @@ List 接口的第一个参数 tinfo 也可以是一个 ctype 等于 'group'/'dis

注意上面第三句不允许是 bot.List(g, card='jack') 的格式。

**List 接口的内部执行顺序:** 首先在 QQBot 的联系人数据库内查找 tinfo 所代表的联系人列表;若数据库内已有此列表,则在此列表内进行搜索,并返回一个包含 “此列表中所有和 cinfo 匹配的联系人” 的列表;若数据库内没有此列表,则向 QQ 服务器请求数据获取联系人列表,获取成功后将联系人列表保存到数据库内,然后再进行搜索并返回一个包含 “此列表中所有和 cinfo 匹配的联系人” 的列表;如果在向 QQ 服务器请求数据的过程中出错了,则打印相关的失败信息,并返回 None 。

**List 接口返回值的含义:** 返回一个非空列表表示 tinfo 所指定的联系人列表内所有和 cinfo 匹配的联系人;返回一个空列表表示该联系人列表内没有和 cinfo 匹配的联系人;返回 None 表示向 QQ 服务器请求联系人列表和资料失败,不知道是否有相匹配的联系人。

调用 List 接口后, **务必** 先根据以上三种情况对返回值进行判断,然后再执行后续代码。

#### (2) bot.SendTo(contact, content) --> '向 xx 发消息成功'/'错误:...'

向联系人发送消息。第一个参数为 QContact 对象,第二个参数为消息内容。再次提醒: **不允许给 群成员/讨论组成员 发消息**

若发送成功,返回字符串('向 xx 发消息成功')。否则,返回含错误原因的字符串('错误:...')。

六、 可注册的响应函数
-----------------------------------
Expand Down Expand Up @@ -201,7 +208,7 @@ List 接口的第一个参数 tinfo 也可以是一个 ctype 等于 'group'/'dis
@qqbotslot
def onQQMessage(bot, contact, member, content):
if '@ME' in content:
bot.SendTo(contact, '%s, 又在想我了吧?' % member.name)
bot.SendTo(contact, member.name+',又在想我了吧')

七、二维码管理器、QQBot 配置、掉线后自动重启、命令行参数
------------------------------------------------
Expand All @@ -212,7 +219,7 @@ SmartQQ 登录时需要用手机 QQ 扫描二维码图片,在 QQBot 中,二
* 邮箱模式: 将二维码图片发送到指定的邮箱
* 服务器模式: 在一个 HTTP 服务器中显示二维码图片

GUI 模式是默认的模式,只适用于个人电脑。邮箱模式可以适用于个人电脑和远程服务器。服务器模式一般只在有公网ip的系统中使用。最方便的是使用 QQ 邮箱的邮箱模式,当发送二维码图片后,手机 QQ 客户端一般会立即收到通知,在手机 QQ 客户端上打开邮件,再长按二维码就可以扫描了。
GUI 模式是默认的模式,只适用于个人电脑。邮箱模式可以适用于个人电脑和远程服务器。服务器模式一般只在有公网ip的系统中使用。如果使用 QQ 邮箱来接收二维码,则当发送二维码图片后,手机 QQ 客户端会立即收到通知,在手机 QQ 客户端上打开邮件,再长按二维码就可以扫描了。

注意:当开启了邮箱模式或服务器模式时, GUI 模式是关闭的,登陆时不会自动弹出二维码图片。

Expand Down Expand Up @@ -274,7 +281,7 @@ GUI 模式是默认的模式,只适用于个人电脑。邮箱模式可以适

如果需要使用服务器模式,可以配置 httpServerIP 和 httpServerPort 项,一般来说应该设置为公网 ip 。服务器模式开启后,可以通过 http://httpServerIP:httpServerPort/qqbot/qrcode 来访问二维码图片。

当邮箱模式和服务器模式同时开启时,发邮件时不会发送真正的图片,只会将图片地址发到邮箱中去,而且只发送一次,二维码过期时刷新一下邮件就可以了。如果只开启邮箱模式,则发邮件时会发送真正的图片,当二维码过期时,需要手动将邮件删除,删除之后才会发送最新的二维码图片
当邮箱模式和服务器模式同时开启时,发邮件时不会发送真正的图片,只会将图片地址发到邮箱中去,而且只发送一次,二维码过期时刷新一下邮件就可以了。如果只开启邮箱模式,则发邮件时会发送真正的图片,当二维码过期时,需要将邮件设置为已读(用手机 QQ 打开邮件后该邮件就是已读了),之后才会发送最新的二维码图片

配置文件中每个用户都有 qq 这一项,如果在某用户(如 somebody )下设置了此项,则在命令行中输入 qqbot -u somebody 启动后,会先使用此 QQ 号上次登录保存的登录信息来自动登录。

Expand All @@ -292,8 +299,8 @@ GUI 模式是默认的模式,只适用于个人电脑。邮箱模式可以适

#### smartqq 协议支持、本项目已实现的功能
+ 消息收/发
+ 联系人(包括 好友/群/讨论组/群成员/讨论组成员)资料获取和查询(包括 QQ号/昵称/名称/备注名/群名片
+ 联系人资料动态更新,新增和丢失 好友/群/讨论组/群成员/讨论组成员 事件的通知(滞后约3~5分钟
+ 联系人(包括 好友/群/讨论组/群成员/讨论组成员)资料获取和查询(包括 QQ号/昵称/名称/备注名/群成员名片
+ 联系人资料动态更新,新增和丢失 好友/群/讨论组/群成员/讨论组成员 事件的通知(滞后约 5~10 分钟
+ 被群内其他成员 @ 的通知

#### 其他功能
Expand All @@ -306,7 +313,7 @@ GUI 模式是默认的模式,只适用于个人电脑。邮箱模式可以适

+ 无法长时间保持在线状态,每次登录成功后的 cookie 会每在 1 ~ 2 天后失效,将被腾讯服务器强制下线,此时 **必须** 手工扫码重新登录。可以将二维码显示模式设置为邮箱模式并打开自动重启模式,在被下线时自动重启并将二维码发送到邮箱,实现远程扫码
+ 无法发送图片和 xml 卡片消息
+ 无法获取到自己通过其他客户端(手机 QQ 、PC QQ)发送的消息,只能接收到别人发过来的消息
+ 无法获取到自己通过其他客户端(手机 QQ 、PC-QQ)发送的消息
+ 无法在群内 @ 其他成员,即便用本程序在群里发送了 “@jack xxx” 这样的消息, jack 也只能收到这个纯文本,收不到“有人@我”的提醒。
+ 无法向 群/讨论组 内的其他非好友成员发消息,也无法收到非好友成员发过来的临时会话消息
+ 在非常少的情况下,发消息时会重复发送多次,也可能对方已收到消息但返回发送失败的结果
Expand Down
4 changes: 4 additions & 0 deletions changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
2017-03-22 qqbot v2.1.2
1) 细化文档,增加 List 接口返回值的含义说明;增加 QContact 对象的 nick/mark/card/name 的属性的含义说明。
2) 增加针对 “获取好友列表有时返回的json中没有备注名列表” 的情况的处理。

2017-03-20 qqbot v2.1.1
2.1 版在 2.0 版的基础上再次进行大量的重构,功能加强,运行更加稳定,修正了几个 bug ,但不再兼容 2.0 版的接口。主要修改如下:
1) 联系人资料获取和查询功能加强,可获取到联系人的 QQ号/昵称/名称/备注名/群名片 。群内非好友的 QQ 号也可以获取到。
Expand Down
Binary file added contact-attr-meannings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions main.py

This file was deleted.

6 changes: 6 additions & 0 deletions qqbot/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import sys, os
p = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if p not in sys.path:
sys.path.insert(0, p)

from qqbot import Main; Main()
54 changes: 29 additions & 25 deletions qqbot/basicqsession.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,10 @@ def SendTo(self, contact, content):

return result

def urlGet(self, url, data=None, **kw):
self.session.headers.update(kw)
def urlGet(self, url, data=None, Referer=None, Origin=None):
Referer and self.session.headers.update( {'Referer': Referer} )
Origin and self.session.headers.update( {'Origin': Origin} )

try:
if data is None:
return self.session.get(url)
Expand All @@ -286,19 +288,20 @@ def urlGet(self, url, data=None, **kw):
requests.packages.urllib3.exceptions.
InsecureRequestWarning
)
return self.urlGet(url, data, **kw)
return self.urlGet(url, data, Referer, Origin)
else:
raise

def smartRequest(self, url, data=None, timeoutRetVal=None,
resultExtractor=None, repeateOnDeny=2, **kw):
def smartRequest(self, url, data=None, Referer=None, Origin=None,
expectedCodes=(0,100003,100100), expectedKey=None,
timeoutRetVal=None, repeateOnDeny=2):
nCE, nTO, nUE, nDE = 0, 0, 0, 0
while True:
url = url.format(rand=repr(random.random()))
html = ''
errorInfo = ''
try:
resp = self.urlGet(url, data, **kw)
resp = self.urlGet(url, data, Referer, Origin)
except requests.ConnectionError as e:
nCE += 1
errorInfo = '网络错误 %s' % e
Expand All @@ -316,35 +319,36 @@ def smartRequest(self, url, data=None, timeoutRetVal=None,
errorInfo = '超时'
else:
try:
result = JsonLoads(html)
rst = JsonLoads(html)
except ValueError:
nUE += 1
errorInfo = ' URL 地址错误'
else:
if resultExtractor:
try:
result = resultExtractor(result)
except:
DEBUG('', exc_info=True)
result = None
if result:
return result
else:
if 'retcode' in result:
retcode = result['retcode']
elif 'errCode' in result:
retcode = result('errCode')
elif 'ec' in result:
retcode = result['ec']
result = rst.get('result', rst)

if expectedKey:
if expectedKey in result:
return result
else:
if 'retcode' in rst:
retcode = rst['retcode']
elif 'errCode' in rst:
retcode = rst('errCode')
elif 'ec' in rst:
retcode = rst['ec']
else:
retcode = -1
if retcode in (0, 100003, 100100):
return result.get('result', result)

if (retcode in expectedCodes):
return result

nDE += 1
errorInfo = '请求被拒绝错误'

n = nCE + nTO + nUE+ nDE

if len(html) > 40:
html = html[:20] + '...' + html[-20:]

# 出现网络错误、超时、 URL 地址错误可以多试几次
# 若网络没有问题但 retcode 有误,一般连续 3 次都出错就没必要再试了
Expand All @@ -355,7 +359,7 @@ def smartRequest(self, url, data=None, timeoutRetVal=None,
elif nTO == 20 and timeoutRetVal: # by @killerhack
return timeoutRetVal
else:
CRITICAL('第%d次请求“%s”时出现 %s,html=%s',
ERROR('第%d次请求“%s”时出现 %s,html=%s',
n, url.split('?', 1)[0], errorInfo, repr(html))
raise RequestError

Expand Down
2 changes: 1 addition & 1 deletion qqbot/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,4 @@ def AutoTest():
input()
else:
raw_input()
print()
sys.stdout.write('\n')
2 changes: 1 addition & 1 deletion qqbot/qconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
if p not in sys.path:
sys.path.insert(0, p)

version = 'v2.1.1'
version = 'v2.1.2'

sampleConfStr = '''{
Expand Down
4 changes: 2 additions & 2 deletions qqbot/qcontactdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from qqbot.mainloop import Put, PutTo

TAGS = ('qq=', 'name=', 'nick=', 'mark=', 'card=', 'uin=')
CHSTAGS = ('QQ', '名称', '昵称', '备注名', '群名片', 'UIN')
CHSTAGS = ('QQ', '名称', '网名', '备注名', '群名片', 'UIN')
CTYPES = {
'buddy': '好友', 'group': '群', 'discuss': '讨论组',
'group-member': '成员', 'discuss-member': '成员'
Expand Down Expand Up @@ -254,7 +254,7 @@ def autoUpdate(self, args):
needFetch = (tinfo not in ('end', 'member')) and \
(not self.getTable(tinfo).IsFresh())

PutTo('fetch', self.fetchUpdate, tinfo, needFetch, args)
PutTo('auto-fetch', self.fetchUpdate, tinfo, needFetch, args)

# in child thread 'fetch'
def fetchUpdate(self, tinfo, needFetch, args):
Expand Down
4 changes: 3 additions & 1 deletion qqbot/qqbotcls.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ def onPollComplete(self, ctype, fromUin, memberUin, content):
member = QContact(ctype=ctype+'-member',
uin=memberUin, name='##UNKOWN')
if ctype == 'group':
nameInGroup = self.List(contact, self.conf.qq)[0].name
cl = self.List(contact, self.conf.qq)
if cl:
nameInGroup = cl[0].name

if nameInGroup and ('@'+nameInGroup) in content:
INFO('有人 @ 我:%s[%s]' % (contact, member))
Expand Down
Loading

0 comments on commit 4b9d2ad

Please sign in to comment.