您的位置:首页 > 其它

Crawler学习:3.Crawler Design

2013-12-29 23:50 204 查看
声明:所有内容均为本人学习《自己动手写网络爬虫》心得,有任何疑问可以参考原文。



爬虫示例结构示意图

我们可以简单得把每一个url代表的网页看作一个节点,那么网络可以看成是由若干个节点及其边组成的图。

那么爬虫的过程就是要遍历这个图,搜索我们有用的信息。

遍历图的过程有很多种,最简单的为宽度遍历、深度遍历。

以宽度遍历为例,假设我们的爬虫不具有任何偏好,我们规定它的爬行路线为宽度遍历的路线。

宽度遍历首先需要一个存储队列,也就是我们的爬虫队列。

package chici.structure;

import java.util.LinkedList;

public class Queue {
private LinkedList queue = new LinkedList();
// 进队列
public void enQueue(Object obj){
queue.addLast(obj);
}
// 出队列
public Object deQueue(){
return queue.removeFirst();
}
// 判断队列是否为空
public boolean isQueueEmpty(){
return queue.isEmpty();
}
//判断队列是否包含obj
public boolean contians(Object obj) {
return queue.contains(obj);
}
}


及爬虫队列的操作方法。

package chici.structure;

import java.util.HashSet;
import java.util.Set;

public class LinkQueue {
private static Set visitedUrl = new HashSet();
private static Queue unvisitedUrl = new Queue();

// 获得URL队列
public static Queue getUnVisitedUrl(){
return unvisitedUrl;
}
// 添加到访问过的URL队列
public static void addVisitedUrl(String url){
visitedUrl.add(url);
}
//移除访问过的URL
public static void removeVisitedUrl(String url) {
visitedUrl.remove(url);
}
//未访问的URL 出队列
public static Object unVisitedUrlDeQueue() {
return unvisitedUrl.deQueue();
}
// 保证每个URL 只被访问一次
public static void addUnvisitedUrl(String url) {
if (url != null && !url.trim().equals("")
&& !visitedUrl.contains(url)
&& !unvisitedUrl.contians(url) )
unvisitedUrl.enQueue(url);
}
//获得已经访问的URL 数目
public static int getVisitedUrlNum() {
return visitedUrl.size();
}
//判断未访问的URL 队列中是否为空
public static boolean unVisitedUrlsEmpty() {
return unvisitedUrl.isQueueEmpty();
}
}


除此之外,我们以url作为搜索索引。

当然我们通过url获得的是整个网页内容,我们需要一个HTML提取工具(HtmlPaserTool)从网页中提取url。

package chici.util;

import java.util.HashSet;
import java.util.Set;

import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

public class HtmlParserTool {
// 获取一个网站上的链接,filter 用来过滤链接
public interface LinkFilter {
public boolean accept(String url);
}

public static Set<String> extracLinks(String url, LinkFilter filter) {
Set<String> links = new HashSet<String>();
try {
Parser parser = new Parser(url);
parser.setEncoding("UTF-8");

NodeFilter frameFilter = new TagNameFilter("A");

// OrFilter 来设置过滤<a> 标签和<frame> 标签
OrFilter linkFilter = new OrFilter(new NodeClassFilter(LinkTag.class), frameFilter);
// 得到所有经过过滤的标签
NodeList list = parser.extractAllNodesThatMatch( linkFilter );

for (int i = 0; i < list.size(); i++) {
Node tag = (Node) list.elementAt(i);
if (tag instanceof LinkTag){
LinkTag link = (LinkTag) tag;
String linkUrl = link.getLink();// URL
//if (filter.accept(linkUrl))
links.add(linkUrl);
}
}
} catch (ParserException e) {
e.printStackTrace();
}
return links;
}
}


之后就是进行宽度遍历,方法在此就不赘述了。见代码吧。

package chici.util;

import java.util.Set;

import chici.structure.LinkQueue;
import chici.util.HtmlParserTool.LinkFilter;

public class ChiciBug {
/**
* 使用种子初始化URL 队列
* @return
* @param seeds 种子URL
*/
private void initCrawlerWithSeeds(String[] seeds)	{
for( int i=0; i<seeds.length; i++ )
LinkQueue.addUnvisitedUrl(seeds[i]);
}

/**
* 抓取过程
* @return
* @param seeds
*/
public void crawling(String[] seeds)	{
//定义过滤器,提取以http://www.baidu.com 开头的链接
LinkFilter filter = new LinkFilter(){
public boolean accept(String url) {
if(url.startsWith("http://www.baidu.com"))
return true;
else
return false;
}
};
//初始化URL 队列
initCrawlerWithSeeds(seeds);

//循环条件:待抓取的链接不空且抓取的网页不多于1000
while( !LinkQueue.unVisitedUrlsEmpty()	&& LinkQueue.getVisitedUrlNum() <= 1000 )	{
//队头URL 出队列
String visitUrl=(String)LinkQueue.unVisitedUrlDeQueue();
if(visitUrl==null) 	continue;
DownloadFile downLoader=new DownloadFile();
//下载网页
downLoader.downloadFile(visitUrl);
//该URL 放入已访问的URL 中
LinkQueue.addVisitedUrl(visitUrl);
//提取出下载网页中的URL
Set<String> links=HtmlParserTool.extracLinks(visitUrl,filter);
//新的未访问的URL 入队
for(String link:links){
LinkQueue.addUnvisitedUrl(link);
}
}
}
//main 方法入口
public static void main(String[]args){
ChiciBug chici = new ChiciBug();
chici.crawling(new String[]{"http://www.baidu.com"});
System.out.println("Crawling over.");
}
}


我们的爬虫只分析出url,并download整个网页。之后我们遍可以进一步筛选我们需要的信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: