昨晚完成了一个带智能策略的采集系统。其实,这个策略的方案三年前就想好了,那时候打算用VB做,做了一半就搁置了。现在用C#才终于把这个方案实现了。
整个方案大概是这样的:
需要建立一个AC数据库,MSSQL也行,有四个表:PageType用于记录页面的种类,比如列表页和详细页两类;Url表用于记录要采集的网址,另外还有一个字段TypeID标明该网址属于哪一种页面类型,比如是列表页还是详细页;Rule表记录着各种规则,主要有三个字段,FromTypeID源页类型,ToTypeID目的页类型,Pattern规则;CjPage用于存储采集到的网页内容,还包含网址和页面种类。
采集策略的核心就在于规则库Rule。
工作过程大概这样:
1,采集线程从Url表抽取一个网址,并马上在表中将其删除,为了防止冲突,这个过程需要用多线程同步解决;
2,用WebClient请求该网址的页面内容;
3,取得内容后,给线程池的线程来分析处理,本线程回到1,继续去Url表取下一个网址;
4,线程池在有空闲线程时,会调用分析函数ParsePage去处理上次获得的页面内容;
5,先到Rule中取所有FromTypeID为当前网址TypeID;
6,如果没有取到任何规则Rule,则将本页内容写入到CjPage中;
7,如果取到规则,那么遍历规则,为每条规则执行ParseUrl方法;
8,ParseUrl根据规则的Pattern匹配到页面内容中的所有网址,并记录到Url中,规则的ToTypeID就是Url的TypeID。
至此,整个流程就完成了。下面举一个实际例子来说明一下:
我要截取动网开发者网络的所有ASP文章http://www.cndw.com/tech/asp/;
首先,在页面类型库中加入列表页和详细页两行,再把http://www.cndw.com/tech/asp/写入到Url中,页面类型是列表页;
其次,在Rule中加入两条规则:
一,从列表页取得详细页的网址FromTypeID=1 ToTypeID=2,Pattern是· <a href="([^>]*)" target=_blank>,这条规则将会识别列表页上的所有详细页的链接,并记入到Url中,TypeID是详细页;
二,从列表页取得列表页的网址FromTypeID=1 ToTypeID=1,Pattern是<a href='([^>]*)'>下一页<\/a>,这条规则将会取得当前列表页上的下一页的链接,并记入到Url中,TypeID还是列表页。
采集器工作时,如果采集的是详细页的内容,将会直接写入到CjPage中,因为没有FromTypeID=2的规则;而采集的是列表页的内容时,就要做两件事了,因为有两条FromTypeID=1的规则,一件事是识别当前列表页中所有文章的链接并存入Url,另一件事是识别下一列表页链接并存入Url。
由于规则具有递归性,使得采集器能递归采集到所有的文章。
下面是一些核心源码(没有公开的都是一些数据层的添删改查的代码):
| 以下是代码片段: using System; namespace CJ public WebClient Wc public String Name = ""; /// <summary> private void Work() private void ParsePage(Object state) |
| 以下是代码片段: using System; namespace CJ CaiJi[] cjs; richTextBox1.Text = ""; int k = 100; void cj_OnWriteLog(string log) |