Maison  >  Article  >  Applet WeChat  >  Méthode de développement public WeChat utilisant la réception de messages

Méthode de développement public WeChat utilisant la réception de messages

高洛峰
高洛峰original
2017-03-23 13:15:521347parcourir

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 = {&#39;articles&#39;:[]}
            for i in range(0,count):
                article = {
                        &#39;title&#39;: article_list[i].slug,
                        &#39;description&#39;:article_list[i].description,
                        &#39;picUrl&#39;:PIC_URL,
                        &#39;url&#39;:article_list[i].absolute_url
                    }
                # 插入文章
                articles_msg[&#39;articles&#39;].append(article)
                article = {}
            # 返回文章
            return articles_msg
                                                  
    #-----------------------------------------------------------------------
    # 解析请求,拆解到一个字典里    
    def parse_request_xml(self,root_elem):
        msg = {}
        if root_elem.tag == &#39;xml&#39;:
            for child in root_elem:
                msg[child.tag] = child.text  # 获得内容
            return msg
                                              
    #-----------------------------------------------------------------------
    def get_help_menu(self):
        menu_msg = &#39;&#39;&#39;欢迎关注南苑随笔,在这里你能获得关于校园的资讯和故事。回复如下按键则可以完成得到相应的回应
        h :帮助(help)
        l :文章列表(article list)
        f : 获得分类列表
        n : 获取最新文章
        a + 数字 :察看某篇文章 a2 察看第2篇文章
        s + 关键字 : 搜索相关文章 s科研 察看科研相关
        c + 分类名 : 获取分类文章 c校园生活 察看校园生活分类
        其他 : 功能有待丰富&#39;&#39;&#39;
        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 + &#39; &#39; + art_title + &#39; &#39; + art_category + &#39;\n&#39;
        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 = {&#39;articles&#39;:[]}
            for i in range(0,count):
                article = {
                        &#39;title&#39;: article_list[i].slug,
                        &#39;description&#39;:article_list[i].description,
                        &#39;picUrl&#39;:PIC_URL,
                        &#39;url&#39;:article_list[i].absolute_url
                    }
                # 插入文章
                articles_msg[&#39;articles&#39;].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 = {&#39;articles&#39;:[]}
            for i in range(0,count):
                article = {
                        &#39;title&#39;:title,
                        &#39;description&#39;:description,
                        &#39;picUrl&#39;:picUrl,
                        &#39;url&#39;:url
                    }
                # 插入文章
                articles_msg[&#39;articles&#39;].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 = {&#39;articles&#39;:[]}
            for i in range(0,count):
                article = {
                        &#39;title&#39;:title,
                        &#39;description&#39;:description,
                        &#39;picUrl&#39;:picUrl,
                        &#39;url&#39;:url
                    }
                # 插入文章
                articles_msg[&#39;articles&#39;].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 = {&#39;articles&#39;:[]}
            for i in range(0,count):
                article = {
                        &#39;title&#39;: article_list[i].slug,
                        &#39;description&#39;:article_list[i].description,
                        &#39;picUrl&#39;:PIC_URL,
                        &#39;url&#39;:article_list[i].absolute_url
                    }
                # 插入文章
                articles_msg[&#39;articles&#39;].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(&#39;SELECT * FROM `sp_posts` WHERE `category` = %s LIMIT 5&#39;, 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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn