2017-12 -13
我想做一个项目,连接各位IT大佬的私人站点。因为站点多了,评论交流不方便,博客与博客之间没有强关联,大佬更新没有通知推送等问题暴露。现在我的收藏夹里放满了他们的博客。但是如果我每天都要点开一次,是很费时间的。
2017- 12-14
我想用python或者node这样的工具,爬下各位大佬的博客,每隔几分钟查一下。有更新就推送通知。这种通知可以是基于邮件的。也可以是基于App的。甚至是微信也行。最后我选择了node,因为相比python起来,我稍微要熟悉一些。
2017- 12-20
我开始寻找适合做这件事情的脚手架,最后找到了puppeteer 它是chrome团队的项目,挺适合我的需求。
2017- 12-22
好心的小姐姐,帮我申请了一台阿里云6个月的免费服务器给我耍。感谢。
2017- 12-28
棘手的问题出现了,我在爬数据的时候,试图将HTML中的文章主体提取出来。这没什么毛病。通过api就能拿到。但是我不能直接就这样赤裸裸的存在数据库里。我想把他们转回markdown格式。找了一些前人留下的h2m的库。发现没有几个能完美解析的。多多少少都有点问题。反正这种结果我是无法接受的。
转markdown
发现效果很差。针对每一个博客去做适配是不存在的。
如果针对站点html+css全部提取出来也不太合理,站点太多。
这时我想起了掘金的分享,通过分析他们对简书、CSND文章的提取变成掘金站内网页。这里一定是在后台做了单独的适配的。
csnd源页面
掘金转换后
可以清晰的发现不仅仅是class发生了变化,元素也变了。而同样的code标签在简书里提取出来又不一样。但是他们都统一的在掘金里完好的展示。
另一个办法是全部用pdf生成整页的的博客文章。这个已经在puppeteer中得到支持。但这并不友好。我选择了弃用。
到今天为止,可以抓到文章的链接和标题了。或许我们先做资源整合吧。用户点击就跳到原文上去。然后给粉丝们添加推送功能。我们每五分钟刷新一次数据。
2018- 01-04
今天晚上和老毛把表设计了一下,准备看怎么去适配爬页面。 这里有一点,要注意业务和爬虫一定是分离的。简单来说就是爬虫只负责抓数据往库里塞。业务上只管读数据返回给接口。业务上并不能感知爬虫的存在。只是爬虫每次轮训完成后会通过接口的方式通知业务说爬虫的任务做完啦,业务可以更新业务数据。
2018- 01-05
我准备放弃puppeteer框架,虽然它很棒,但是相比起来比较吃内存。我更需要一个更稳定不吃资源的内核。所有我找到了。cheerio框架,它提供了类似jQuery的语法可以操作dom。再一个我这里要爬的页面大多数都是静态页面。可以不用考虑渲染的问题,即便出现了动态渲染的页面,可以单独提取ajax或其他异步请求的url。
下面是单独拿一个页面的内容和下一页的内容,我这里不打算爬列表,因为本身也要进详情去拿body,所以一个个往上找,拿到next文章。再一次爬去。存到数据库里就行啦。
1 | var request = require('request'); |
2018- 01-08
优化了一下采集策略,可以通过主站host链接访问接口,先拿第一个最新页面,而后往通过详情向下寻找下一个页面,直到最后一个页面。适配了一下hexo的next主题,已经完美的可以拿到整站数据了。其它主题和站点应该需要单独适配。刚在想如果我每一个都去适配一下岂不是累死去,不知道业界其它成熟的方案怎么做的。通过机器学习吗?
今天还做了下面几个事情:
- 中文url转码
- http头自动拼接
- 空字符串和换行符内容过滤
- 拆分不同站点模块方便适配
2018- 01-09
阿里云服务器安全规则问题会导致防火墙开放了3306端口也无法穿透,mysql无法远程连接。尝试去修改/etc/sysconfig/iptables来开放端口,发现文件被占用。最后的解决办法是在在宝塔Linux上安全里放行里3306端口。也许就是因为这个宝塔Linux程序导致该文件一直被占用,结果就是自己改防火墙不让改。
今天碰到了一个比较坑的地方,相信以后也会有很多。在采集吴彦祖大佬(刘望舒)博客时,发现它优化过hexo的文章底部导航。导致我爬第一篇文章后就歇菜了。解决的办法也很简单,单独做一个反向爬适配。如下:
1 | let nextUrl; |
然后在接口上变成这样的:http://127.0.0.1:8088/?blog=liuwangshu.cn&isReverse=true
就可以了,采集其它hexo站点可以默认不传,或者传false即可。
但很快我就又发现,这种爬法是不对的。如果作者不按顺序出牌,比如首位连接相连,那么很快就会成为一个死循环爬个不停。而且吴彦祖大佬的博客分成了很多tag,也不完全按照顺序来的。那么这样只好放弃之前的思路。改成先爬pagelist再通过pagelist取每一片文章,通过文章再取详情。这样应该总没问题啦吧?
2018- 01-12
express
这里我简单的把爬去封装成了不同的Map去爬去链接。这里有一个问题暂时不好解决,就是不同类型的网站选择器是不一致的。而我要得到的结果是固定的。我现在只能很愚蠢的写了很多个对象去取。可发发现不管是取巴掌的还是取薇薇的都是同样的方法只是他们的对象不同。
好的一方面是我的数据层是剥离开的。这不会影响我统一存储。
1 | app.get('/xxx', function(req, res) { |
下面说下问题,一开始还好由于我和巴掌还有薇薇的文章数目都不是特别多。用浏览器Url的方式去调用接口比如这样:http://127.0.0.1:8088/XXX?blog=yifeiyuan.me
文章能一个个正常的爬出来存到数据库里。
当我爬到刘望舒和程序亦非猿的文章时,就开始出问题了。文章会重复的爬很多进去。而且是死循环。一开始我以为是网页的设计问题导致了循环引用的爬去。我静下去分析着他们的网页节点。最后发现程序亦非猿的第一篇文章和中间的文章并未出现收尾相连的引用方式。
好吧,直觉告诉我可能是浏览器惹的祸。因为我一直没有调用response。导致谷歌阻塞了。试了一下立刻返回.爬出来的数据就正常了。res.json({re:"ok"});
selector
再说另一个问题:
1 | <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1 text-center"> |
在爬去薇薇的博客时,时间标签拿到的selector是span.meta span
,到程序亦非猿的时候时间标签一样是span.meta span
.但是恐怖的是一旦到程序亦非猿的时候,在很少一部分文章里取到的会多一段奇怪的字符。
后面发现单独对HTML页面分析,发现我这种取法是不可靠的。会导致一个页面里,多处标签上出现了同样的selector时。就会被拼接进去。解决的办法也很粗暴。我们换一种选择器。
1 | let time = StringUtil.replaceDirtyString($(".post-heading span").text()); |
虽然不是每个标签都有class存在。但是我们可以用父子约束来取。这样就万无一失了。
更新中,未完。手头的事有点多,可以发现我做得很慢,然后现在还只是一个雏形。基本上只要能有一点点空闲时间我就会切回来捣鼓。期待不?