自动新闻抓取系统

来源:互联网 发布:php数组 编辑:程序博客网 时间:2024/04/27 15:56

http://www.zowee.cn/blog/blogArticle.aspx?id=2442&userid=2

 

 

自动新闻抓取系统,或称新闻小偷,已被很多人在使用,实现方式也多种多样。然而时至今日,设计一个完善的、功能强大的、能有效抓取到优质新闻的抓取系统,在技术实现上日趋复杂,因为有更多的问题需要解决。此次飞速的自动新闻系统升级,让我的此种感觉更加强烈,特写下此文,作为日后的回顾。 


一、项目背景
此次自动新闻系统升级,是在经历了以下三个阶段后,发现不改不行了,才最终确定彻底改变的:2005年--2006年:飞速从2005年初开始使用自动新闻抓取系统,并和客户网站后台管理系统有机结合,客户既可以手动添加新闻,也可以利用此系统自动抓取。当时我是用asp.net实现,利用新浪的爱问搜索,直接在新浪网上搜索指定关键词的新闻,并抓取入库。此阶段由于刚开始使用自动新闻系统,认识不深,所以相安无事的用了一年...2006年--2007年:从06年开始,发现自动新闻系统时好时坏,每天自动运行的公共抓取程序总是经常一条新闻也抓取不到,后来再三检查,在排除了程序的问题后,最终确定是因为新浪的爱问搜索时好时坏,经常在维护,导致无法搜索到新闻。没办法,只能修改程序,改为利用百度在新浪网站上搜索相关新闻,再抓取,用这种绕一圈的办法,总算解决了问题。2007年--现在:从06年改从利用百度搜索后,自动新闻系统运行良好,每天都有新闻被更新。但此时一个更严重的问题被提出来,那就是从新浪抓取的新闻基本上是社会新闻,往往和所设置关键词的本意相差十万八千里。例如:某客户是生产“管道”的公司,关键词当中也有一个“管道”,本意是想搜索到和“管道”相关的技术或行业方面的新闻,但从新浪上找到的反而是“下水管道导致儿童溺水身亡”之类的负面新闻,让客户屡有怨言。而且随着客户的增加,关键词规模也日益庞大,用web方式很难让程序一次运行完,经常出现超时现象,而且人机交互不友好,无法实时看到程序的运行状态。 


二、要解决的问题:
在确定了最终要重写整个程序、新闻改从行业网站抓取、不使用WebForm而用WinForm、程序语言采用C#后,我认真思考了一下,确定以下问题是必需解决的:1、自动变换IP(伪造IP?)在分析该行业网站后,发现他们有防止一个IP过度访问页面的功能,如果不变换IP,少则一分钟,多则几分钟,就一张页面也读取不到,所以程序必需具有在指定时间内更换IP的功能。2、抓取速度即使有了IP变换功能,考虑到对目标网站的负责,也不应长时间的去抓取,所以速度很关键,最好是能在夜深人静的时候,在几分钟内完成整个抓取过程,以免对目标网站造成过多的影响。所以程序必需使用多线程,而且要充分利用缓存,以提高速度。3、人机界面友好WebForm抓取程序的一个缺点就是人机交互不友好,往往不知道程序运行的怎么样了,所以这次重写,我决定在人机交互上要做的很好,可以随时相应用户的操作,确保任一时候UI都能有反应。4、软件健壮性由于网络的复杂性,而且我准备让这个程序在每天凌晨3点运行,属于无人值守,所以必需要解决好容错性,在断网、更换IP、更新数据库出错、未抓取完时都能重启线程继续执行,以确保每个关键词都能被抓取一遍。5、其它一些实用方面的功能。比如自动关机;把缓存上传到服务器的某一个位置,供单个抓取程序利用;程序结构要合理,以适应目标网站经常改版的需要等等.... 


三、软件实现过程
有了问题,就有了目标,也有了做事的方问,以下是一些主要的实现过程。1、如何实现自动更换IP这是第一个需要解决的问题,在网上搜索了一下,发现问这个问题的人很多,但没有什么实用价值。象有人提出伪造IP,可是IP伪造后,你的程序又怎么和服务器通信、怎么接收你要抓取的网页数据呢?在测试了无数方法后,以我的浅见,要达到自动更换IP,只有两个方法
一是利用代理服务器,把有效的代理服务器地址存入文件或数据库,你的程序每隔指定时间就为WebProxy读取一个随机代理IP,这种方法能实现需求,但如果你不想花钱,不想用收费的代理,基本上无用,因为网上免费的代理服务器大都没用,且速度奇慢,而抓取程序最需要的就是速度,所以这个方法看似很棒,实则没用。另外,有的网站能透过代理读取你的真实IP,那这个方法就更没用了。

二是如果你的程序能操控宽带拔号器或路由器,就每隔指定时间让它们断开网络再重连,这样每重连一次就能获得一个新的IP,这种方法效果好,而且不影响速度,实现也不难,我采用的就是这种方法,经测试,完全能满足需求。2、如何满足抓取速度。这个问题本来没什么好说的,就是多线程了,数据库的结构也要设计合理。但我在开发过程中,发现很多关键词需要访问的新闻列表页或内容页是相同的,这给我启发,能不能一边抓取一边把访问过的页面缓存下来,让后面的线程不需要再去网站取数据、而是直接从缓存中拿?当时想到这里,那是相当兴奋,如果采用这种方法,速度提高何止十倍!于是立马实现,采用HashTable缓存数据,发现程序越到后来,缓存的数据越多,命中缓存的机率也越高,抓取速度也越快,真是爽,一切皆如我愿!这是在开发这个软件过程中最让我高兴的事了。3、人机界面友好本来采用多线程,UI和抓取线程分离,UI界面自能实时响应用户的操作。但在实现过程中,发现抓取基本上不能一次执行完,都需要让某些线程重新启动继续抓取。我最开始的做法是每当一个线程未抓取完它负责部分的关键词而退出时,就让它立即重启。但可能是我低估了多线程的复杂,用这种方法后,什么稀奇古怪的问题都出现了:关键词计数不准,线程数不准,更可怕的是在更新ListView和更新数据库时,居然出现了:“System.ExecutionEngineException”错误,关于ExecuteEngineException,微软是这样描述:
执行引擎错误是致命错误,决不应该发生。此类错误主要是在执行引擎被破坏或丢失数据时发生的。系统会随时引发此异常。在可能的情况下,系统将引发比 ExecutionEngineException 异常能提供更多信息的异常。应用程序不应引发ExecutionEngineException从这个描述可以看出,ExecutionEngineException这个异常在正常的程序中应当是不可能发生的,致命错误啊。然而我却反复与这个异常多次碰头。一开始是怀疑某些共享资源存在同步问题,于是Lock、Monitor、Mutex这些同步、互斥机制统统拿来试验一番,然而错误依旧...。在经历了两天折磨后,重新审视代码,发现问题最有可能是在线程退出的一刹那,又让它立既重启,也许它的扫尾工作还没结束呢,又让它投入工作,不罢工才怪。而此时我也不想再在这个问题上继续浪费时间了,直接换一种方法:等所有线程都退出后,再检查有没有未被抓取的关键词,再根据需要启动相应数量的线程,来完成未尽的革命事业....。唉,乌云散了,终于看到太阳出来了,一切正常了....如果不在这个问题上花了三天时间,软件本来是能在预定时间内完成的,但问题总在你认为最有把握的时候出现。这个问题是在做这个软件过程最让我抓狂的事。4、软件健壮性这个也是需要保证的,网络总是很复杂,而且还有可能在你一开始抓取,你的IP就被屏蔽了,而程序还得继续。在多线程中读取数据库,出错机率也大增,据我的观察,在几分种的运行过程中,在数据库方面总会出错一二次...5、其它一些问题在缓存方面,主要是利用了序列化和反序列化,以便缓存能多次使用。而且考虑到客户单个使用的抓取程序也需要用到这些缓存,所以增加了把序列化后的缓存文件上传到服务器的功能。

原创粉丝点击