美文网首页我爱编程
【Python实战】是的,我在公众号上面实现了“1024搜索”功

【Python实战】是的,我在公众号上面实现了“1024搜索”功

作者: c2aa1d94244a | 来源:发表于2018-06-19 00:24 被阅读87次

    此文包含:

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

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

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

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

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

    这个是旧版本的效果:

    旧版本

    这个是新版本的效果:

    新版本

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

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

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

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

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

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

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

    闲扯自动回复机器人

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

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

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

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

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

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

    @robot.filter('Daily')
    def replyDaily(message):
        time = datetime.datetime.now()
        cur_time = str(time.year) + "-" + str(time.month) + "-" + str(time.day)
        return [
            [
                "这里是标题",
                "这里面写的是描述信息",
                "图片URL",
                "跳转的URL"
            ]
        ]
    

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

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

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

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

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

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

    旧版本研发故事 v0.1

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

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

    账号

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

    登录

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

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

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

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

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

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

    搜索查询

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

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

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

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

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

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

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

    http://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提供的方法

    self.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()方法就可以:

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

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

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

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

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

    search_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爬虫一步一步部署到腾讯云上

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


    底部二维码.png

    相关文章

      网友评论

        本文标题:【Python实战】是的,我在公众号上面实现了“1024搜索”功

        本文链接:https://www.haomeiwen.com/subject/qdpoeftx.html