社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

【Python实战】聊一聊如何把1024论坛的搜索搬到了皮克啪的铲屎官公众号上来的开发心得,彩蛋依旧

皮克啪的铲屎官 • 7 年前 • 869 次点击  

【Python实战】聊一聊如何把1024论坛的搜索搬到了皮克啪的铲屎官公众号上来的开发心得,彩蛋依旧

此文包含:

  • WeRoBot微信公众号自动回复机器人
  • 同一个需求,两个版本不同变化的分析
  • mongoengine库的使用
  • tornado如何给前端传值
  • request.session()的使用
  • 以上几点全部包含,还有一些杂七杂八的知识点在文章里

上一篇文章横空出世之后,在微信公众号里面添加了查看每日技术讨论区的帖子,有一位同学和我说,他没有账号。虽然只是随口一提,但是对信息敏感的我,立刻发觉到,没有账号,就不能够搜索,但是搜索这是个刚需啊。苦恼的肯定不止这一个人,肯定还有好多人都有这样的烦扰。

所以这回,我就尝试着在公众号里面加入搜索功能。先说一下目前的情况,搜索功能还在开发中,先后尝试了两种方案,这里我主要从技术的角度来说一下整体的开发流程,和大家分享一下。

先明确一点,开发这个东西,就是从技术出发,为了提升技术而做的。

废话不多说,先来看一下效果图吧。

这个是旧版本的效果:



这个是新版本的效果:



为什么会有新旧两个版本呢?我这里就把我整个的开发思路和大家说一下。

首先,就是拿到需求,有位同学说没有账号。没有账号就不能搜索,那么我能不能将搜索功能添加进来。

然后,就考虑怎么添加搜索功能。社区是自带搜索的,我首先想到的就是通过借助社区的搜索功能来做我自己的搜索,也就是,将用户的搜多信息,通过我提交到社区,然后社区会返回给我结果,我在将结果编辑一下,返回给用户。这样,在用户看来,就实现了搜索功能。其实在里面,我的公众号是做了一层代理商而已。这就是旧版本的思路。

有了思路,我就开始开发,最后,开发出来一个逻辑能跑通的版本,发现这个版本的限制比较多。所以,就开始研究有没有其他办法能够实现搜索。

搜索的本质,就是从数据库里面拿到我要找的数据。所以,我这里需要:第一,数据库的容量足够大;第二,我能够操作数据库,执行查找操作。第一个条件,数据库容量足够大,我这里肯定是可以做到,无非就是爬虫不停地爬,然后将爬下来的结果塞到数据库中呗。第二个,代码要能够支持MongoDB的查找操作。由于之前一直使用的都是PyMongo库,经过仔细检查,我发现这个库不支持数据库的查找功能,而另一个mongoengine库是可以支持查找的,果断将库换成了mongoengine,这下就可以执行查找功能了。

依照新版本的思路,同样,我也开发出来一个能跑通逻辑的版本,效果就如同上面的效果图展示的一样。但是,新版本的搜索还是有很多硬伤。蛋疼。

首先,先扯一会儿微信公众号这个自动回复机器人的事儿。

闲扯自动回复机器人

这里用到的自动回复机器人,是用WeRoBot框架开发的,并且是将WeRoBot嵌入了Tornado框架中。大家一听到这里可能觉得很高深,其实这个是WeRoBot框架提供的一种功能而已。

具体做法就是,将WeRoBot新建出来的Robot,作为一个Tornado的Handler处理就可以,然后,通过annotation的方式,来编写回复函数即可。

标准的信息回复,即Text回复长这个样子:

1@robot.filter('呵呵')
2def replyDaGaier(message):
3    reply = """欢迎你来到皮克啪的铲屎官"""
4    return reply

看到上面用到了filter(),这个就是过滤器,指当客户端发送过来“呵呵”固定的两个字的时候,我们的公众号会自动回复上面的内容,并且是按照文字形式回复。

如果是想回复成文章形式,就像上面的效果图中展示的那样,那么应该这么写:

 1@robot.filter('Daily')
 2def replyDaily(message):
 3    time = datetime.datetime.now()
 4    cur_time = str(time.year) + "-" + str(time.month) + "-" + str(time.day)
 5    return [
 6        [
 7            "这里是标题",
 8            "这里面写的是描述信息",
 9            "图片URL",
10            "跳转的URL"
11        ]
12    ]

这个就是,客户端发送“Daily”,然后公众号回复一个网页的入口。点击那个文章,就会自动跳转到“跳转的URL”里面。我就是靠这样的方法来实现查看社区技术讨论区每日资讯的。

最后补充一句:个人的微信公众号,不支持自定义菜单的开发!不支持自定义菜单的开发!不支持自定义菜单的开发!

也就是说,一旦你打开的这个自动回复机器人了,那么,你公众号最下面一行的快捷菜单将会消失。这一点真的很不爽啊,个人的灵活性大大的降低了。开发热情一下子下来不少。但是企业公众号是可以开发自定义菜单的,但是企业公众号,一个月只能发4篇文章。所以,个人和企业之间,酌情选择吧。

如果自动机器人还有什么问题,可以给我留言,也可以进群交流。我都会为大家解答的。

好了,接下来我们就说今天的正事儿。

下面就详细的来聊聊两个版本的开发过程吧。

旧版本研发故事 v0.1

这个版本的基本思想是:用已有的账号,通过社区提供的搜索功能,来做搜索。

所以,这里就涉及到几个环节:账号,登录,查询搜索,返回结果处理,展示结果这几个环节。我们一个一个的来说。

账号

这个不是问题。只有有了账号,才能用社区的搜索功能。大家不要问了,我的账号买不起邀请码。

登录

登录这块,我之前写过一篇文章『【Python实战】用代码在1024论坛实现自动回贴』,这里用到的是,request的session,因为我们要保存cookie。即要保存账号的登录状态。

登录,就是自己模拟出来一个表头,然后,将登录需要传入的数据,自己拼凑出来,然后通过session.post()方法去执行登录操作,看返回的结果。如果返回结果成功,就说明登录成功。如果不成功,那就得看具体什么地方出现问题了。

这里简单谈一下,由于社区是有二次验证的功能存在,即每次登录的时候,在输入完账号密码之后,还会有个页面,要求输入一个动态密码,有点像将军令,或者Steam的登录方式。这个没办法用程序来破解,只能找到相对应的绑定设备,来手动输入号码,继续登录。

主语怎么在程序中间等待输入,Python提供了一个很好的函数input()

1input_num = input("Input the f***** number:")

就这么简单的一行,就可以将输入的数字赋值给input_num变量。

搜索查询

搜索查询的思路就是:在登录成功之后,进入社区的搜索页面,然后填入相对应的变量,执行一个HTTP POST请求,就可以了。

这里我们得需要拆开来说一下。

首先,是如何能够拿到我们需要搜索的关键字,即搜索的key_word。因为,我们的远端服务器,在通过客户端访问那个url的时候,是一个HTTP GET请求,这个问题就变成了如何在GET请求中传递参数的问题了。

其实不难,tornado框架给了我们方法:

1key_word = self.get_argument("key", "")

直接调用self.get_argument()方法即可。第一个参数是在URL中的变量名,即URL中等号前面的那个部分,第二个参数是默认值,这里默认值填写成空。

至于,如何在URL中加入变量,这里简单说一下,就是在URL后面,先加一个?,然后通过键值对的形式,用=号连接键值对,填写在?后面即可,键值对与键值对之间,通过&号来做连接。

1http://www.google.com?usr=root&psd=toor

上面这个URL中,就有两个变量,一个是usr,它的值是 root,另一个是psd,它的值是toor。URL的传值就是这么写就好。

拿到关键字key_word之后,我们需要来到搜索页面。这里,我们需要通过Charles来抓一个POST请求的包,来分析一下,当搜索按钮按下的时候,到底发生了什么。

其实,POST请求就是把搜索页面的表格数据,直接传了上去。那这里就简单了,我们只需要拼凑出来一个表格数据就可以。但是!这里有个问题,就是,社区为了防止机器人,在表格的最下面添加了一个验证码。通过分析网页的源码,发现,那个输入验证码的数字,是页面已经传给我们的。我们只需要将页面用BeautifulSoup来解析一下,然后找到对应的值,塞到我们拼凑的数据里面,在传一个POST请求就可以了。

返回结果 和 数据展示

当上面讨论的POST请求传送成功之后,我们会拿到社区返回来的结果。

这是个页面,同样用BeautifulSoup来解析页面,找到每一条帖子的link,然后拼凑出来帖子的URL。

将结果放到一个列表里面,通过tornado提供的方法

1self.render("search.html", key_word=key_word, result_info="成功", info=search_result_list, count=len(search_result_list))

将结果给到前端的html页面即可。

不要小看这里,这里是一种后端传值给前端的方法。在前端,只需要通过{{result_info}}就可以显示传入的值,即成功

旧版本小结

旧版本是通过社区提供的功能来进行搜索的。搜索功能虽然强大,但是限制很多:

  • 必须得有账号
  • 2秒刷新限制,两次刷新不得小于2秒
  • 两次搜索之间也有限制
  • 搜搜板块也死板
  • 这样的模块架设起来,会服务器的要求很高,并发性不是很好解决

所以,我尝试着研发一下新版本。

新版本研发故事 v0.2

新版本的思路:用庞大的数据库作为搜索的支撑,通过对数据库的操作,来实现搜索。

强大的数据库支撑的数据,就是要爬取更多的社区论坛的页面,然后把帖子信息整合到数据库中。这点不是很难,难点就在,社区的国内地址总是在换,以前的地址一旦失效,那么之前爬的数据都失效了。这点很蛋疼。

在有了大量数据作为支撑之后,我们就开始寻找能够通过代码来操作数据库的东西了。

之前我一直用的都是PyMongo,因为这个封装的分好,用起来非常简单,ORM性特别强,但是!这个库他不支持查找操作!!准确的说,不支持数据库的查找。若是强行查找也是可以的,你一次取出所有数据,然后for循环找符合条件的。这样做太慢了。经过网上搜索,发现另一个Python的MongoDB的库叫mongoengine。这个库是支持查找操作的。

使用起来也是非常的方便。感觉,这个库的开发,有些部分是借鉴了其他MySql库的操作方法。这里简单说一下使用。

首先是连接你的MongoDB,直接全局调用connect()方法就可以:

1connect("DBName", host="XX.XX.XX.XX", port=27017)

然后,你得对应到你的每一张表里。这里,一张表的数据,就是一个类。表名要和类名一一对应,而且里面的colume也要一一对应。

1class table16(Document):  # 父类是mongoengine的Document
2    post_title = StringField(required=True)
3    post_url = StringField(required=True)

上面的信息就是,表table16里面,有两列,一个是post_title另一个是post_url

如果要搜索,只需要调用:

1search_result = table16.objects(post_title__contains=key_word)

直接调用post_title__contains就可以。非常好用。

接下来,就是拿到数据,然后展示给前段了,和旧版本中的一样。这里就不多说了。

新版本小结

新版本,虽然速度要比旧版本快,但是也是有不少问题的:

  • 数据量太少
  • 一旦URL变了,地址就失效了
  • 数据库的I/O操作消耗太高

就在刚才写文章的时候,我脑子里又出现了一个新的想法,停下手中的笔,试了试,应该是出来了搜索v0.3的版本了。

此文的精华

最后来给大家说一下在这次项目中,我是如何开展的。其实,我和大家也是一样的,好多知识点并不熟悉。但是有时候,项目开发中会遇到,遇到那种让人头大的,怎么办?

其实这个很简单。就是硬着头皮查,分析,然后学习,再动手实战,解决问题。大家不要觉得这样子会很麻烦,我估计,80%的人,遇到问题第一时间都是退缩,而我不一样,遇到问题第一时间就撸起袖子来分析问题,然后去网上查。说道网上查,这个该怎么查,是个学问。

我这里举个简单的例子,就比如新版本的开发中,需要在数据库中查找。我给大家来捋一下我是如何搞的:

首先,我的项目中,一直使用的是pymongo库。这个库,其实我也就是使用了大概30%不到。好多地方还不是很熟。既然要查找,首先看库里面的方法,有个find(),还有个find_one()方法,没有提供search或者其他类似的方法。那么,点find()方法进去,看里面的文档说明是怎样的。最后看到,这个库其实是不支持数据库搜索操作的。如果要用pymongo做查找,得先找到所有的结果,然后for循环来找。我自己试了一下,几千条数据,查找一下,太特么的慢了。果断放弃pymongo。这个时候,我就在网上查:python mongodb 查找。看看有没有别人写的博客总结。结果,就发现了一个人写的,用到了mongoengine这个库。看到这里,我是先研究他写的例子,是什么个套路:connect()连接数据库,然后用一个Class来做表的结构,直接调用class的方法,传入参数就可以查找。分析到这里,我认为,我需要的东西我已经找到了。那么下一步就是在我的项目里面先简单的写一个demo,测试一下,看看能不能跑出来预期的结果。果然,结果正确。这下,我就找到了解决问题的办法。接下来,就是完善我的代码了,将真正的逻辑写入到正式的代码里面。这样,一个问题就解决了。继续去解决下一个遇到的问题。。。。

解决问题的思路就是这个样子。当遇到问题,不会的,查百度,查谷歌,看官方文档,看代码的源码注释,都是很好的思路。甚至,在做出来一个东西之后,要想着迭代这个东西,优化他,就像我一样,做了个v0.1版本,太卡,就想换一个思路来做,搞出来一个v0.2版本。就在写文章的时候,其实v0.3版本已经出来了。效果目前不错。这里就不多说了。想了解的,可以关注我的公众号『

皮克啪的铲屎官
』,公众号下方有个『
进群交流
』的按钮,里面有入群的方式,完全免费。我会在群里和大家交流技术问题。你如果有疑问,也可以在里面提出来,大家一起讨论,共同进步。

至于服务器的代码,我已经分享出来,关注『

皮克啪的铲屎官
』,回复『
服务器代码
』,就可以获取到下载地址了。

推荐阅读

【Python实战】手把手超详细教程教你Scrapy爬达盖尔社区,有彩蛋
【Python实战】用Scrapy编写“1024网站种子吞噬爬虫”,送福利
【Python实战】用代码来访问1024网站,送福利
【Python实战】用Scrapyd把Scrapy爬虫一步一步部署到腾讯云上

                      这么硬货的公众号,你们不关注一下啊?

                       



今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/IxnxajqgYn
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/13820
 
869 次点击