[Python代码]Discuz!论坛(X2.5)发帖及回复脚本
昨天,我介绍了Discuz!论坛登录的Python脚本实现(点击进入)。今天,我继续这一系列,介绍Discuz!论坛最常见的一类脚本操作——发帖及回复。这里,我只实现普通主题的发表以及回复的脚本。
首先,我们依然要来分析发主题帖和回复时传输的数据包所post的数据:
上面这张图是发帖时的post数据。
formhash
是昨天登录脚本中在登录后页面中获得的formhash。如果没有正确的formhash,发帖时就会显示“您的来路请求不正确”的错误提示,请大家一定要注意!
subject
和message
分别是发表的新主题帖的题目和帖子内容。
上面三项是必须要post的数据。下面再对剩下的几组键值对进行简要的介绍,这些键值对不是必需出现的,在程序中就不对其进行实现了。
posttime
是发帖时间,会由程序自动生成,不需要我们关心。
wysiwyg
全称为“What You See Is What You Get”,翻译成中文就是“所见即所得”。在Discuz!论坛发贴的高级界面我们会看到这一复选框,目前的名字为“纯文本”。
replycredit
相关的一组键是回帖奖励。这里不对其进行具体的介绍。
readperm
是阅读权限,Discuz!最高的阅读权限是255。
price
是主题价格,Discuz!论坛允许对一些用户组设置可以发布付费主题,这样用户查看主题需要花费某种积分给发帖人。
tags
是主题的标签,目前Discuz!默认每个主题最多有5个标签。
rushreplyfrom
以及后续的几项是抢楼帖相关的选项,我们在这里也不再具体介绍。不过,当设置为抢楼帖时还会有一个叫做rushreply
的选项出现。
usesig
的含义是是否使用用户的个人签名档。
allownoticeauthor
是指发帖后,如果有其他用户回复这个主题,是否已“提醒”的方式通知楼主。
当然,还有一些其他选项,需要勾选后,其相关的键值对才会出现在post数据中,我在这里也就不再做介绍了。
下面再来看回复时候的post数据。
这次的post数据不多,和上面发帖时也有很多一样的。不过在回复时,不再需要subject
这一选项,我们只需要把formhash
和message
两项post过去就可以了。
接下来就是我的代码了。
第一个文件,依然是配置文件config.py,和昨天相比增加了如下的代码:
1 2 3 |
POSTURL = DOMAIN + r'forum.php?mod=post&action=newthread&fid=FID&extra=&topicsubmit=yes' REPLYURL = DOMAIN + r'forum.php?mod=post&action=reply&tid=TID&extra=&replysubmit=yes' |
这两行分别是发新主题和回复时的对应地址,我们可以从post的数据包中看到这个地址。
然后,我们修改discuz.py这个基类所在的文件,在Discuz类里添加一个字符串截断的代码,其余部分不变,可以参考昨天的文章:
1 2 3 4 5 6 |
def _interception(self, string, length): '''字符串截取(为简单起见,认为所有字均占3个字符)''' if (len(string) > (length / 3)): return string[0:(length / 3 - 1)] + '...' else: return string |
由于Discuz!默认主题题目不超过80个字符,对于utf-8来说也就是26个汉字,因此我们需要一个字符串截断方法,防止由于主题题目过长造成的发帖失败。在这里,为简单起见,认为任何字均为3个字符,不考虑英文字符、数字、半角标点等情况。
接下来,就是最重要的Post类了,我在post.py文件中进行实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# -*- coding: utf-8 -*- import re import config import discuz class Post(discuz.Discuz): def __init__(self): super(Post, self).__init__() self.post_success_pattern = re.compile(r'<meta name="keywords" content="(?u)(.+)" />') # 发帖成功时匹配 self.post_fail_pattern = re.compile(r'<div id="messagetext" class="alert_error">') # 发贴失败时匹配 self.post_error_pattern = re.compile(r'<p>(?u)(.+)</p>') # 发贴失败的错误信息 def newthread(self, fid, subject, message): postdata = { 'subject': self._interception(subject, 80), 'message': message, 'formhash': self.formhash, } base_url = config.POSTURL url = base_url.replace('FID', fid) self.operate = self._get_response(url, postdata) prefix = '主题 "%s" ' % postdata['subject'] self.__verify_post_status(prefix) def reply(self, tid, message): postdata = { 'message': message, 'formhash': self.formhash, } base_url = config.REPLYURL url = base_url.replace('TID', tid) self.operate = self._get_response(url, postdata) prefix = '回复 "%s" ' % self._interception(message, 80) self.__verify_post_status(prefix) def __verify_post_status(self, prefix): page_content = self.operate.read().decode('utf-8') if self.post_success_pattern.search(page_content): print "%s发布成功!" % prefix elif self.post_fail_pattern.search(page_content): post_error_message = self.post_error_pattern.search(page_content) try: print "%s发布失败!原因是:%s。" % (prefix, post_error_message.group(1)) except: print "%s发布失败!原因是:未知原因。" % prefix else: print "无法确定%s发布状态" % prefix |
这里包含两个公开的方法,分别是发新主题的newthread
和发回复的reply
。还有一个私有方法__verify_post_status
,是用于验证发表状态的。
最后是发帖和回复的使用方法。
1 2 3 4 5 6 7 8 9 10 |
# -*- coding: utf-8 -*- import config import post if __name__ == "__main__": my_account = post.Post() my_account.login(config.USERNAME, config.PASSWORD) my_account.newthread('2', u'发帖主题', u'发帖内容') my_account.reply('10', u'发帖回复') |
这样,我们就实现了Discuz!最基本的发帖(普通帖)和回复功能的脚本,一般的使用也以这种发帖为主。当然,如果还有更高需求,要发表一些特殊类型帖(如悬赏帖、投票帖、辩论帖、活动帖、商品帖)的话,可以自己得到传输的post数据,分析需要填写的内容,在post.py中进行完善。
博主加油 超级好的文章。通俗易懂,我在windows下各种报错
我就是在windows下测试的啊,具体原因是什么呢?这篇的代码要和上一篇的合起来看
编码会出错,改完后,又提示object has no arrtibute _interception,不过评论都正常发出去了。
my_account.newthread(‘2′, u’发帖主题’, u’发帖内容’)
my_account.reply(’10’, u’发帖回复’)
为何我测试,加上u就不能成功发帖和回复,提示UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-6: ordinal not in range(128) 这个错误
去年u就能成功运行?
字符编码问题
为何有中文的你写的代码都加个 u 呢? 首先不是有 # -*- coding: utf-8 -*- 这个了吗?
习惯而已,哈哈
老大,你的代码我用的python3.改了代码,也报了很多错,实在失去信心了。你能更新到python3运行下吗?