配置:
depthInSite ,waitDuration ,noExternalLinks 可根据需要修改,注释写得很明确。
打开options.h
注释掉不需要的项目,以下为我的配置文件
定义网页保存方式,如下是保存在dxxxxxx目录下,文件以fxxxxx流水号命名
//#define DEFAULT_OUTPUT // do nothing...
#define SIMPLE_SAVE // save in files named save/dxxxxxx/fyyyyyy
//#define MIRROR_SAVE // save in files (respect sites hierarchy)镜像方式保存
#define STATS_OUTPUT // do some stats on pages 输出统计
#define FOLLOW_LINKS // do you want to follow links in pages
#define LINKS_INFO
#define NO_DUP //不允许重复
#define EXIT_AT_END //完成时退出
#define COOKIES
#define CGILEVEL 2 //不包含cgi
#define DEPTHBYSITE
#define THREAD_OUTPUT
#define RELOAD
#define GRAPH
#define STATS
#define BIGSTATS
编辑完成后,需要注意的是如果只修改larbin.conf文件,不需要重新编译,如果修改了options.h文件,需要运行 gmake 重新进行编译。
运行
运行了,会看到如下信息
larbin_2.6.3 is starting its search
Fri Jun 29 15:01:44 2007
urls : 3 (rate : 0)
pages : 3 (rate : 0)
success : 1 (rate : 0)
运行过程中还有web方式的统计页面, http://localhost:8081 即可访问
如果想重新抓取,运行 ./larbin -scratch
终止运行:Ctrl+C
之后就可以到 ./save 目录下看抓取的webpage了
另外,types.h中有些项也可以自行设置,如 maxUrlsBySite ,maxPageSize
这是目前使用的比较多的一种做法,无论在client还是server都有着广泛的应用。在一个线程内打开多个非阻塞的连接,通过poll/epoll/select对连接状态进行判断,在第一时间响应请求,不但充分利用了网络资源,同时也将本机CPU资源的消耗降至最低。这种方法需要对dns请求,连接,读写操作都采用异步非阻塞操作,其中第一种比较复杂,可以采用adns作为解决方案,后面三个操作相对简单可以直接在程序内实现。
效率问题解决后就需要考虑具体的设计问题了。
url肯定需要一个单独的类进行处理,包括显示,分析url,得到主机,端口,文件数据。
然后需要对url进行排重,需要一个比较大的url Hash表。
如果还要对网页内容进行排重,则还需要一个Document Hash表。
爬过的url需要记录下来,由于量比较大,我们将它写到磁盘上,所以还需要一个FIFO的类(记作urlsDisk)。
现在需要爬的url同样需要一个FIFO类来处理,重新开始时,url会从定时从爬过的url FIFO里取出来,写到这个FIFO里。正在运行的爬虫需要从这个FIFO里读数据出来,加入到主机类的url列表里。当然,也会从前一个FIFO里直接读url出来,不过优先级应该比这个里面出来的url低,毕竟是已经爬过的。
爬虫一般是对多个网站进行爬取,但在同时站点内dns的请求可以只做一次,这就需要将主机名独立于url,单独有一个类进行处理。
主机名解析完成后需要有一个解析完成的IP类与之应用,用于connect的时候使用。
HTML文档的解析类也要有一个,用来分析网页,取出里面的url,加入到urlsDisk。
再加上一些字符串,调度类,一个简单的爬虫基本上就完成了。
以上基本上是Larbin的设计思路,Larbin在具体实现上还有一些特殊的处理,例如带了一个webserver,以及对特殊文件的处理。 Larbin有一点设计不不太好,就是慢的访问会越来越多,占用大量的连接,需要改进,另外如果对于大规模的爬虫,这仅仅实现了抓取的部分,要分布式的扩展还需要增加url的集中管理与调度以及前台spider的分布式算法。
sequencer.cc 页面优先级
checker.cc检查并过滤url
void check (url *u);//检查url是否可知?
bool filter1 (char *host, char *file);//检查url后缀是否合法
fetchOpen.cc
void fetchOpen () //打开socket,不会在主线程阻塞
void fetchDns () //dns调用