Chengqi
이전에 사용자의 기사에 응답하기 위해 WeChat 로봇을 디자인했기 때문에 이 앱은 매우 간단하고 특별히 심층적인 디자인이 필요하지 않으며 내 아이디어는 다음과 같습니다. GitHub에서 Python으로 작성된 많은 블로그 시스템에서는 데이터베이스에서 기사 데이터를 가져온 다음 기사 제목, URL, 사진 및 기타 정보를 xml 형식으로 패키지하는 WeChat 응답 부분만 구현하면 됩니다. WeChat 서버와 서버는 이를 사용자에게 반환합니다. 그리고 완강한 답변을 하는 것보다 바로 클릭하여 기사를 볼 수 있는 완전한 앱과 같은 메뉴가 있으면 훨씬 더 좋겠다는 것을 깨달았습니다. 나는 그것을 변환하기 위해 다른 사람들이 작성한 블로그 시스템인 saepy-log를 사용했습니다. 그리고 이 블로그 시스템은 원래 토네이도에 참여할 계획이 없었지만, 열심히 탐구해야 했습니다. . SQL 문처럼 작성하고 문서를 보는 면에서 많은 어려움도 겪었고, 얻은 것도 많았습니다.
배포 및 개발
여러 가지 어려움을 겪었기 때문에 본 글대로 진행하지 못할 수도 있다는 점 미리 양해 부탁드립니다. saepy-log의 소스 코드를 다운로드하고 여기 작업에 따라 업로드한 후 sae 플랫폼에 블로그 시스템을 설치한 다음 svn을 사용하여 코드를 로컬 작업 디렉터리에 동기화하면 모든 준비가 완료됩니다.
수정하고 싶은 점은 blog.py가 블로그의 핵심 기능이고, model.py가 데이터 모델의 핵심이라는 점입니다. 데이터 모델 기능을 확장하여 WeChat 기능을 완성할 예정입니다. . 주로 XML 구문 분석과 문자열 처리를 위한 일부 패키지를 정의합니다. 다음으로 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앱의 난이도가 크지 않고 여전히 어렵다는 것을 알 수 있습니다. 지난번 WeChat을 사용했을 때와 동일합니다. API에서 PIC_URL과 같은 토큰과 같이 사용해야 하는 여러 전역 변수를 직접 정의해야 합니다. 프로그램의 원리는 실제로 사용자 요청을 구문 분석하는 것입니다. h로 시작하면 도움말 메뉴를 제공하고, 숫자로 시작하면 특정 항목 등을 제공한 다음 해당 기능을 처리합니다. 여기서는 설명이 더 복잡하므로 분류만 가져오세요. 기사에 대해 이야기해 보겠습니다. 사용자 요청 문자열을 분석해야 합니다.
# 分类 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)get_category_articles(category) 함수를 제공해야 합니다. 여기에서는 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물론 Article이 이 함수를 구현하는지 확인하기 위해 데이터베이스 모델 Article을 처리해야 하지만, 그렇지 않습니다. 소매 걷어붙이고 직접 하려고 - Article을 확장하여 model.py로 이동합니다. 파일에 다음 코드를 작성했습니다.
# 返回一个包含若干篇文章的数组 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여기서는 데이터베이스 쿼리가 수행되고 카테고리 매개변수가 전달됩니다. in에서는 카테고리를 매개변수로 하는 5개의 기사가 선택되고 패키지가 반환됩니다. post_detail_formate는 이미 블로그 시스템에 작성되어 있으므로 이를 사용하기만 하면 됩니다. Python에서는 SQL 문을 작성할 때 매우 주의해야 합니다. 전달해야 하는 매개변수가 있는 경우 %를 사용하여 매개변수를 채우는 대신 쉼표로 구분하는 것이 가장 좋습니다. 특히 like를 사용할 때 다음과 같은 SQL 문을 작성해야 하는 경우가 많습니다. SELECT * FROM `sp_posts` WHERE `category` LIKE '%study%'그러나 Python에서는 %s로 사용됩니다. 매개변수 자리 표시자로 사용되므로 여기와 같이 불필요한 오류가 많이 발생합니다. 즉, 안전하게 사용하려면 매개변수로 전달하는 것이 가장 좋습니다. Python은 이를 원래 문자열의 %와 분리합니다.
위 내용은 메시지 수신을 활용한 WeChat 공개 개발 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!