诗词君每天会向参与的饭友随机推送一句诗词。这里有两个问题要考虑的,1、如何记录参与的饭友;2、如何随机选取一句诗词。
永久记录数据一般有两种方式,保存到磁盘或数据库上,前者比较简单,所以我们采取文件的形式。
我们来看看在 Python 中如何读写文件,为了方便,请先在 cmd 切换到 d 盘后,输入 python 进入交互环境:
>>> f = open('test.txt')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'
>>>
当你尝试打开一个不存在的文件的时候,会得到错误信息。
我们先来创建文件:
>>> f = open('test.txt', 'w')
>>> f.write('hello, fanfou')
>>> f.close()
>>>
现在打开文件浏览器,看是否有一个 test.txt 的文件,可以打开查看它的内容。
内置函数 open() 可以打开一个文件,上面两次的函数调用的区别在于,第二次多传递了一个参数 'w', 这个字符代表着打开文件的模式,可用模式如下表:
字符 含义 'r' 读取(默认),如果文件不存在则失败 'w' 写入,如果文件已存在则先清空原文件 'x' 创建新文件并写入,如果文件已存在则失败 'a' 写入,如果文件已存在则追加到文件的末端 'b' 二进制模式,需和 r/w/x/a 中的一个共同使用 't' 文本模式(默认),需和 r/w/x/a 中的一个共使用 '+' 读取和写入,和 r/w/x/a 中的一个共同使用 'U' 通用换行模式(已弃用)
默认的模式是 'rt'(读取文本文件)。得到一个文件对象后,将有一些方法可使用,如上面的 write(),不同的模式打开文件可用的方法不完全相同。
请下载 poems.txt 到你的 d 盘,我们接着看代码:
>>> f = open('poems.txt', encoding='utf8')
>>> poems = f.readlines()
>>> len(poems)
952
>>> type(poems)
<class 'list'>
>>> poems[0]
'曲则全,枉则直。(《老子》)\n'
>>> poems[1]
'言必信,行必果。(《论语》)\n'
>>>
我把收集到的诗词一行一句保存在 poems.txt,在上面我们以读取文本模式打开了它,并把 f.readlines() 返回的结果赋值给 poems。 这是一个列表,每个元素都是一句诗词,这离我们解决问题近了一步,接下来只要想办法每次随机选取一句即可。
我们来看看怎样随机选取元素:
>>> import random
>>> arr = [1, 2, 3, 4, 5, 6]
>>> random.chioce(arr)
3
>>> random.chioce(arr)
6
>>> random.chioce(arr)
2
>>>
你会发现你得到的结果和我不同,因为 random.choice() 的作用是在列表中随机选取一个元素。那么我们把 random.choice() 应用在 poems 上即可随机选取诗词。
接下来我们看看怎样记录参与的饭友,这需要用到另一个标准库 shelve:
>>> import shelve
>>> db = shelve.open('poems.dbm')
>>> db['test'] = 'hello, fanfou'
>>>
请退出交互环境并查看 d 盘是否有 poems.dbm 等文件,现在我们再次进入交互环境:
>>> import shelve
>>> db = shelve.open('poems.dbm')
>>> db['test']
'hello, fanfou'
>>> list(db.keys())
['test']
>>>
你看,它把我们刚才的赋值保存起来了,你可以像一个字典一样来使用 shelve 返回的对象 db,我们对它的修改会自动保存到磁盘上。
我们已经解决了最初需要考虑的两个问题,现在来看看怎样让诗词君工作起来。
我们需要访问 mentions 的消息,看是否有想要加入或退出的饭友,然后更新到我们的 db 上:
import fanfou
# 请修改为你的 Consumer
consumer = {'key': 'consumer key', 'secret': 'consumer secret'}
# 请修改为你的 ID 和密码
client = fanfou.XAuth(consumer, 'username', 'password')
fanfou.bound(client)
resp = client.statuses.mentions()
for item in resp.json():
user_id = item['user']['unique_id']
if '-join' in item['text']:
db[user_id] = item['user']['name']
elif '-quit' in item['text']:
try:
del db[user_id]
except:
pass
参与推送的饭友有时候可能会改名,而改名了我们就 at 不到,所以需要定时更新名字:
import time
for user_id in db.keys():
try:
resp = client.users.show({'id': user_id})
db[user_id] = resp.json()['name']
except:
pass
time.sleep(0.5)
终于到推送这一步啦:
for user_id, name in db.items():
try:
poem = random.choice(poems).strip()
body = {
'status': '@%s %s' % (name, poem),
'in_reply_to_user_id': user_id,
}
client.statuses.update(body)
except:
pass
time.sleep(0.5)
定时执行的方法我们在上一个 Demo 已经学习了,把上面这些东西放在一起,我们的诗词君就完成了。完整的代码可点击 poems.py 查看 。