Crawler学习:3.Crawler Design

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



爬虫示例结构示意图


我们可以简单得把每一个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整个网页。之后我们遍可以进一步筛选我们需要的信息。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值