成成
Because I previously designed a WeChat robot to respond to users’ articles, this app is very simple and does not require particularly in-depth design, and my idea is: use Anyway, there are so many blog systems written in Python on GitHub. I only need to implement the WeChat response part, which is to get the article data from the database, and then package the article title, URL, pictures and other information into xml format. Return to the WeChat server, and the server returns it to the user. And I found that it would be much better to have a menu, like a complete app, where you can directly click to view an article instead of rigidly replying. I used a blog system written by others to transform it - saepy-log. And this blog system is based on the tornado framework. I didn't originally plan to get involved in tornado, but I had to bite the bullet and delve into it. I encountered a lot of difficulties, and I gained a lot in terms of writing like SQL statements and viewing documents.
Deployment and Development
Let me explain in advance that because I have gone through all kinds of troubles, I may not be able to do it according to this article. After downloading the source code of saepy-log and uploading it according to the operations here, you can install the blog system on the sae platform, and then use svn to synchronize the code to the local working directory, and everything is ready.
What we want to modify is that blog.py is the core function of the blog, and model.py is the key to the data model. We are going to extend the data model function to complete our WeChat function.
Add our WeChat function class weixin.py in blog.py (since it uses the tornado framework, the method is slightly different from that in django):
Import the packages that need to be used
# weixin used package import xml.etree.ElementTree as ET import urllib,urllib2,time,hashlib import tornado.wsgi import tornado.escape
Mainly xml parsing and some packages for processing strings. Next we define the main body of the weixin class:
# 添加微信推送帐号 class WeiXinPoster(BaseHandler): #----------------------------------------------------------------------- # 处理get方法 对应check_signature def get(self): global TOKEN signature = self.get_argument("signature") timestamp = self.get_argument("timestamp") nonce = self.get_argument("nonce") echoStr = self.get_argument("echostr") token = TOKEN tmpList = [token,timestamp,nonce] tmpList.sort() tmpstr = "%s%s%s" % tuple(tmpList) tmpstr = hashlib.sha1(tmpstr).hexdigest() if tmpstr == signature: self.write(echoStr) #return echoStr else: self.write(None); #return None # 处理post方法,对应response_msg def post(self): global SORRY # 从request中获取请求文本 rawStr = self.request.body # 将文本进行解析,得到请求的数据 msg = self.parse_request_xml(ET.fromstring(rawStr)) # 根据请求消息来处理内容返回 query_str = msg.get("Content") query_str = tornado.escape.utf8(query_str) # TODO 用户发来的数据类型可能多样,所以需要判别 response_msg = "" return_data = "" # 使用简单的处理逻辑,有待扩展 if query_str[0] == "h": # send help menu to user response_msg = self.get_help_menu() # 返回消息 # 包括post_msg,和对应的 response_msg if response_msg: return_data = self.pack_text_xml(msg, response_msg) else: response_msg = SORRY return_data = self.pack_text_xml(msg, response_msg) self.write(return_data) # 分类 elif query_str[0] =="c": category = query_str[1:] response_msg = self.get_category_articles(category) if response_msg: return_data = self.pack_news_xml(msg, response_msg) else: response_msg = SORRY return_data = self.pack_text_xml(msg, response_msg) self.write(return_data) # 列出文章列表 elif query_str[0] =="l": response_msg = self.get_article_list() if response_msg: return_data = self.pack_text_xml(msg, response_msg) else: response_msg = SORRY return_data = self.pack_text_xml(msg, response_msg) self.write(return_data) # 直接获取某篇文章 elif query_str[0] == "a": # 直接获取文章的id,然后在数据库中查询 article_id = int(query_str[1:]) # 进行操作 response_msg = self.get_response_article_by_id(article_id) if response_msg: return_data = self.pack_news_xml(msg, response_msg) else: response_msg = SORRY return_data = self.pack_text_xml(msg, response_msg) self.write(return_data) # 还要考虑其他 elif query_str[0] == "s": keyword = str(query_str[1:]) # 搜索关键词,返回相关文章 response_msg = self.get_response_article(keyword) # 返回图文信息 if response_msg: return_data = self.pack_news_xml(msg, response_msg) else: response_msg = SORRY return_data = self.pack_text_xml(msg, response_msg) self.write(return_data) elif query_str[0] == "n": response_msg = self.get_latest_articles() # 返回图文信息 if response_msg: return_data = self.pack_news_xml(msg, response_msg) else: response_msg = SORRY return_data = self.pack_text_xml(msg, response_msg) self.write(return_data) # 如果找不到,返回帮助信息 else: response_msg = get_help_menu() if response_msg: return_data = response_msg else: return_data = SORRY self.write(return_data) # n for 获取最新的文章 def get_latest_articles(self): global MAX_ARTICLE global PIC_URL article_list = Article.get_articles_by_latest() article_list_length = len(article_list) count = (article_list_length < MAX_ARTICLE) and article_list_length or MAX_ARTICLE if article_list: # 构造图文消息 articles_msg = {'articles':[]} for i in range(0,count): article = { 'title': article_list[i].slug, 'description':article_list[i].description, 'picUrl':PIC_URL, 'url':article_list[i].absolute_url } # 插入文章 articles_msg['articles'].append(article) article = {} # 返回文章 return articles_msg #----------------------------------------------------------------------- # 解析请求,拆解到一个字典里 def parse_request_xml(self,root_elem): msg = {} if root_elem.tag == 'xml': for child in root_elem: msg[child.tag] = child.text # 获得内容 return msg #----------------------------------------------------------------------- def get_help_menu(self): menu_msg = '''欢迎关注南苑随笔,在这里你能获得关于校园的资讯和故事。回复如下按键则可以完成得到相应的回应 h :帮助(help) l :文章列表(article list) f : 获得分类列表 n : 获取最新文章 a + 数字 :察看某篇文章 a2 察看第2篇文章 s + 关键字 : 搜索相关文章 s科研 察看科研相关 c + 分类名 : 获取分类文章 c校园生活 察看校园生活分类 其他 : 功能有待丰富''' return menu_msg #----------------------------------------------------------------------- # 获取文章列表 def get_article_list(self): # 查询数据库获取文章列表 article_list = Article.get_all_article_list() article_list_str = "最新文章列表供您点阅,回复a+数字即可阅读: \n" for i in range(len(article_list)): art_id = str(article_list[i].id) art_id = tornado.escape.native_str(art_id) art_title = article_list[i].title art_title = tornado.escape.native_str(art_title) art_category = article_list[i].category art_category = tornado.escape.native_str(art_category) article_list_str += art_id + ' ' + art_title + ' ' + art_category + '\n' return article_list_str # 按照分类查找 def get_category_articles(self, category): global MAX_ARTICLE global PIC_URL article_list = Article.get_articles_by_category(category) article_list_length = len(article_list) count = (article_list_length < MAX_ARTICLE) and article_list_length or MAX_ARTICLE if article_list: # 构造图文消息 articles_msg = {'articles':[]} for i in range(0,count): article = { 'title': article_list[i].slug, 'description':article_list[i].description, 'picUrl':PIC_URL, 'url':article_list[i].absolute_url } # 插入文章 articles_msg['articles'].append(article) article = {} # 返回文章 return articles_msg #----------------------------------------------------------------------- # 获取用于返回的msg def get_response_article(self, keyword): global PIC_URL keyword = str(keyword) # 从数据库查询得到若干文章 article = Article.get_article_by_keyword(keyword) # 这里先用测试数据 if article: title = article.slug description = article.description picUrl = PIC_URL url = article.absolute_url count = 1 # 也有可能是若干篇 # 这里实现相关逻辑,从数据库中获取内容 # 构造图文消息 articles_msg = {'articles':[]} for i in range(0,count): article = { 'title':title, 'description':description, 'picUrl':picUrl, 'url':url } # 插入文章 articles_msg['articles'].append(article) article = {} # 返回文章 return articles_msg else: return def get_response_article_by_id(self, post_id): global PIC_URL # 从数据库查询得到若干文章 article = Article.get_article_by_id_detail(post_id) # postId为文章id if article: title = article.slug description = article.description picUrl = PIC_URL url = article.absolute_url count = 1 # 这里实现相关逻辑,从数据库中获取内容 # 构造图文消息 articles_msg = {'articles':[]} for i in range(0,count): article = { 'title':title, 'description':description, 'picUrl':picUrl, 'url':url } # 插入文章 articles_msg['articles'].append(article) article = {} # 返回文章 return articles_msg else: return
It can be seen that the difficulty of the app is not great, and it is still the same as the last time I used WeChat In the API, several global variables that need to be used need to be defined by yourself, such as token, PIC_URL, etc. The principle of the program is actually to parse user requests. If it starts with h, it will provide a help menu. If it starts with a number, it will provide a certain article, etc., and then provide corresponding functions for processing. The explanation here is more complicated, so just get the classification Let’s talk about the article:
You need to analyze the user request string:
# 分类 elif query_str[0] =="c": category = query_str[1:] response_msg = self.get_category_articles(category) if response_msg: return_data = self.pack_news_xml(msg, response_msg) else: response_msg = SORRY return_data = self.pack_text_xml(msg, response_msg) self.write(return_data)
The function of get_category_articles(category) needs to be provided here, so you need to implement such a function in the weixin class:
# 按照分类查找 def get_category_articles(self, category): global MAX_ARTICLE global PIC_URL article_list = Article.get_articles_by_category(category) article_list_length = len(article_list) count = (article_list_length < MAX_ARTICLE) and article_list_length or MAX_ARTICLE if article_list: # 构造图文消息 articles_msg = {'articles':[]} for i in range(0,count): article = { 'title': article_list[i].slug, 'description':article_list[i].description, 'picUrl':PIC_URL, 'url':article_list[i].absolute_url } # 插入文章 articles_msg['articles'].append(article) article = {} # 返回文章 return articles_msg
Obviously, we need to deal with the database model Article here to see if Article implements this function. Unfortunately, it does not, so we have to roll up our sleeves and do it ourselves - extend Article, so we move to model.py In the file, I wrote the following code:
# 返回一个包含若干篇文章的数组 limit 5 def get_articles_by_category(self, category): sdb._ensure_connected() article_list = sdb.query('SELECT * FROM `sp_posts` WHERE `category` = %s LIMIT 5', str(category)) for i in range(len(article_list)): article_list[i] = post_detail_formate(article_list[i]) return article_list
Here, a database query is performed, the category parameter is passed in, 5 articles with category as the parameter are selected, and the package is returned. post_detail_formate is already written in the blog system, we just need to use it. In Python, you must be very careful when writing SQL statements. When you encounter parameters that need to be passed in, it is best to separate them with commas instead of using % to fill the parameters. Especially when using like, we often need to write such sql statements:
SELECT * FROM `sp_posts` WHERE `category` LIKE '%study%'
But it is used in python %s is used as a parameter placeholder, so it will cause many unnecessary errors, such as here. In short, to use them safely, it is best to pass them as parameters. Python will separate them from the % in the original string.
The above is the detailed content of WeChat public development method of using message reception. For more information, please follow other related articles on the PHP Chinese website!