Chengqi
Parce que j'ai déjà conçu un robot WeChat pour répondre aux articles des utilisateurs, cette application est très simple et ne nécessite pas de conception particulièrement approfondie, et mon idée est : obtenez Quoi qu'il en soit, il y en a tellement De nombreux systèmes de blog écrits en Python sur GitHub. Il me suffit d'implémenter la partie de réponse WeChat, qui consiste à obtenir les données de l'article de la base de données, puis à regrouper le titre de l'article, l'URL, les images et d'autres informations au format XML. serveur WeChat, et le serveur le renvoie à l'utilisateur. Et j’ai trouvé qu’il serait bien mieux d’avoir un menu, tout comme une application complète, sur lequel on peut directement cliquer pour voir un article au lieu de répondre de manière rigide. J'ai utilisé un système de blog écrit par d'autres pour le transformer - saepy-log. Et ce système de blog est basé sur le framework tornado. Au départ, je n'avais pas prévu de m'impliquer dans tornado, mais j'ai dû mordre la balle et m'y plonger. . J'ai rencontré beaucoup de difficultés, et j'ai beaucoup gagné en termes d'écriture d'instructions SQL et de révision de documents.
Déploiement et développement
Veuillez noter à l'avance que parce que j'ai traversé toutes sortes de problèmes, je ne pourrai peut-être pas le faire selon cet article. Après avoir téléchargé le code source de saepy-log et l'avoir téléchargé selon les opérations ici, vous pouvez installer le système de blog sur la plateforme sae, puis utiliser svn pour synchroniser le code avec le répertoire de travail local, et tout est prêt.
Ce que nous voulons modifier, c'est que blog.py est la fonction principale du blog et model.py est la clé du modèle de données. Nous allons étendre la fonction de modèle de données pour compléter notre fonction WeChat. .
Ajoutez notre classe de fonctions WeChat weixin.py dans blog.py (comme elle utilise le framework tornado, la méthode est légèrement différente de celle de django) :
Importez les packages requis
# weixin used package import xml.etree.ElementTree as ET import urllib,urllib2,time,hashlib import tornado.wsgi import tornado.escape
Principalement l'analyse XML et quelques packages pour le traitement des chaînes. Ensuite, nous définissons le corps principal de la classe weixin :
# 添加微信推送帐号 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
On peut voir que la difficulté de l'application n'est pas grande, et c'est toujours la même chose que La dernière fois que j'ai utilisé l'API WeChat, j'ai dû définir moi-même plusieurs variables globales, telles que le jeton, PIC_URL, etc. Le principe du programme est en fait d'analyser les demandes des utilisateurs. S'il commence par h, il fournira un menu d'aide. S'il commence par un numéro, il fournira un certain article, etc., puis fournira les fonctions correspondantes pour le traitement. L'explication ici est plus compliquée, alors obtenez simplement la classification Parlons de l'article :
Vous devez analyser la chaîne de requête de l'utilisateur :
# 分类 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)
La fonction de get_category_articles(category) a besoin à fournir ici, vous devez donc implémenter une telle fonction dans la classe weixin :
# 按照分类查找 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
Évidemment, nous devons traiter le modèle de base de données Article pour voir si Article implémente cette fonction. Malheureusement, c'est le cas. non, donc nous devons retrousser nos manches et le faire nous-mêmes - prolonger l'article, donc nous passons au combat Allez dans le fichier model.py et écrivez le code suivant :
# 返回一个包含若干篇文章的数组 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
Ici, une requête de base de données est effectué, le paramètre de catégorie est transmis, 5 articles avec catégorie comme paramètre sont sélectionnés et les packages sont renvoyés. post_detail_formate est déjà écrit dans le système de blog, il suffit de l'utiliser. En Python, vous devez être très prudent lors de l'écriture d'instructions SQL Lorsque vous rencontrez des paramètres qui doivent être transmis, il est préférable de les séparer par des virgules au lieu d'utiliser % pour remplir les paramètres. Surtout lorsque nous utilisons like, nous devons souvent écrire de telles instructions SQL :
SELECT * FROM `sp_posts` WHERE `category` LIKE '%study%'
Mais en python, il est utilisé %s est utilisé comme espace réservé de paramètre, cela provoquera donc de nombreuses erreurs inutiles, comme ici. Bref, pour les utiliser en toute sécurité, il est préférable de les passer en paramètres, Python les séparera du % dans la chaîne d'origine.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!