纯干货:实现一个简单的新闻抓取推送工具(抓取、相似度排重)

背景介绍

金融市场中消息是无价的,怎么更快获得消息直接决定了投资收益。《货币战争》书中第一章即介绍了罗斯柴尔德家族提前一天拿到拿破仑欧洲战争失败的消息利用英国公债狂赚20倍收益的故事。而现代金融市场中,甚至只要公开消息获得足够及时,就能够跑赢大部分散户而获得盈利。

为什么我会写这篇文章呢?今年5月份,我买了一些比特币,到现在经历过大大小小几十次“暴涨暴跌”,最近的几次是国内监管的消息频出导致国内市场动荡。每次动荡短则半小时,长则1-2天,事后大多能找到引起动荡的原因,而消息是促使暴涨暴跌的原因,更快地获得消息,就能够更快买入或者卖出,于是就萌生了写一个新闻推送工具的想法。

需求分析

对于新闻抓取工具,我希望能够实现以下几个简单功能:

  • 尽快获得新闻
  • 新闻保存
  • 推送到手机
  • 新闻排重

看起来比较简单,下面逐一讲解每个功能的实现方式。

尽快获得新闻

新闻的获取方式很多,一般都是通过去主流新闻网站或者搜索引擎抓取页面后提取关键字得到新闻的发布时间、标题、URL、简介等信息。

主流的实时金融相关新闻网站有:华尔街实时财联社电报
搜索引擎,国内用的比较方便的就百度和搜狗了。

我目前主要抓取了华尔街实时,百度和搜狗的比特币相关新闻,财联社电报的消息和华尔街实时的消息实时性差不多,而财联社不支持搜索关键字实时新闻,华尔街实时支持搜索,比如搜索实时比特币的url为https://wallstreetcn.com/search?q=%E6%AF%94%E7%89%B9%E5%B8%81&tab=live

获得新闻页面后,就是通过DOM或者正则表达式将所需要的内容解析出来,注意搜狗的编码是GB2312,可能需要转换成UTF8,相关的工具类在这个GitHub项目中,这里贴一段百度新闻搜索比特币的解析代码以供参考,其他的可以依葫芦画瓢完成:

上面的代码将百度新闻的结构保存在vector<NewsInfo> news_infos中,这样就完成了新闻的抓取工作。

新闻的保存

新闻可以每隔1分钟抓取一次,抓取下来的新闻,可以存储到数据库中,也可以按照项目需要存储。我是存储到MySQL数据库中,使用URL作为主键保存即可。

推送到手机

新闻抓取后,及时推送到手机是个比较纠结的事情,我也想过很多方法,包括方糖推送,短信,甚至自己想写个专门用来推送的APP,最后发现QQ邮箱的推送很不错,QQ邮箱发QQ邮箱为秒级延时,只需要往指定的邮箱发送邮件就好了,代码也有现成的。发件箱建议使用QQ邮箱,也可以用其他的,只是延时会稍微大一些。

使用过程中也遇到了一些问题,主要是推送频率需要控制一下,如果发送频率太快,就会返回错误,可以通过申请多个QQ邮箱来解决这个问题,QQ邮箱目前是免费申请,开通IMAP功能需要2周。每个QQ号至少可以申请2个邮箱账号(一个数字邮箱,一个英文邮箱)。有了足够多的邮箱后,每次发送前,将邮箱乱序,然后选择第一个邮箱进行发送,如果失败就换下一个,直到全部失败,这样可以最大可能避免发送失败的情况发生。

如果所有邮箱都发送失败,可以使用方糖推送结果作为最终的告警,方糖推送还是比较稳定的,而且频率也放得比较宽,只是显示和管理上没有邮箱这么方便,因此作为备选方式。

不多说,直接贴代码吧,发送邮件用的是Python脚本写的,C++实现比较麻烦,Python还是省事点,在C++中可以使用CppSystem::ExcuteCommand进行调用:

新闻排重

以上的方案基本上就是我的新闻推送工具的第一版了,但是用了一段时间后发现虽然使用了URL排重,但是同样标题的新闻还是非常多,一篇新闻稿出来后,各家网站都会转载热门新闻,无疑给信息的获取增加了很多噪声,我们往往只关注一条新闻第一时间发出来,比如这样:

这个问题如何解决呢?

想想我的需求,我需要看到最新的没有被发送过到我手机的新闻。
所以最简单的做法,是判断这个标题有没有存在过就好了。
但是看上面的图,同样的标题,可能各家媒体会增删少量内容,或者标点符号从全角改变成半角,从中文符号改变成英文符号,这样的话,字符串比较就失去作用了。
解决这个问题,需要使用一种方式来衡量2个字符串之间的相似度,方法很多,Google一搜一大把,其中比较简单效果也不错的方式是使用编辑距离。编辑距离可以使用CppString.h中的CppString::EditDistance来计算,因为都使用同样的编码,所以不用考虑中文的问题。
使用编辑距离乘以100除以两个字符串中较长的字符串的长度,就可以得到一个百分比值,这个值我存储在NewsInfo::unique_value中,称它为新闻的独特程度,值越大,说明这个新闻的标题与另一个新闻标题越不匹配。

然后实现方式就很简单了,从数据库中取出最近1000条(这个数值可以调节撒)title,使用抓取的新闻的title与数据库中的每一个title计算编辑距离,取出最小的编辑距离记录下来,如果最小独特程度大于一定阈值(比如45),就认为这个新闻是没有发送过的,可以推送到手机,否则就是已经发送过的新闻,不再推送,可以看到排重后的效果还是非常不错的,可以根据运行一段时间的独特程度确定独特程度的阈值,下图中红色框内的就是被排除的新闻标题:

广告时间

根据这篇文章实现一个新闻推送工具非常简单,如果读者编程能力有限但是想直接使用这个新闻推送工具,可以在文章下留言,免费使用,你只需要提供你的Email和关注的新闻关键词即可。

anyShare分享到:

原文地址:http://godmoon.wicp.net/blog/index.php/post_514.html,转载请注明出处

Moon发表于2017年9月28日
打赏作者

您的支持将鼓励我们继续创作!

[微信] 扫描二维码打赏

[支付宝] 扫描二维码打赏

发布者

sytzz

学会用简单的语言将复杂的问题说清楚。

发表评论

电子邮件地址不会被公开。