web爬虫的广度优先算法

web爬虫中需要设计一个广度优先的算法,以控制爬虫爬行网址的先后顺序,这里用一个链表实现,用链表是因为链表的插入速度够快。

设计思路:
1、取下一个地址:从链表的头部取出一个,并将头部元素删除
2、加入地址池:将URL地址加入到适当的位置

   为了保证加入的时候能够加入到合适的地址,最容易想到的办法就是遍历那个地址池,但遍历的效率确实不高,当地址池中数量增大的时候,消耗在遍历上的cpu资源过多,导致爬行效率降低。还有一种方法就是记录每一个深度的URL地址的最后一个元素在地址池中索引,当加入的时候就不需要遍历地址池,只需通过需要加入的URL地址,找到同级URL地址在地址池中的索引,然后加入到地址池中,加入位置为这个索引的后面一个,并且更新索引表,当然如果没有找到同级别的索引,这依次找上一级的索引,若在回溯的过程中,都没有找到,这可以确定索引为0,即将该URL地址加入到地址池的最前面。

下面是一个索引表内容变化的例子:

深度 索引
2 5
3 6

当加入一个这样的URL地址(new URL(1,"http://www.sina.com.cn"))之后
深度 索引
1 1
2 6
3 7

当加入一个这样的URL地址(new URL(2,"http://www.baidu.cn"))之后
深度 索引
1 1
2 7
3 8

当加入一个这样的URL地址(new URL(4,"http://tieba.baidu.cn"))之后
深度 索引
1 1
2 7
3 8
4 9




实现的核心代码(代码不完整,无下载及url地址提取等)
  • Crawler.java
  • import java.util.HashMap;
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    import java.util.Map.Entry;
    
    
    public class Crawler {
    
    	private List<Url> uncrawedUrl = new LinkedList<Url>();// 待爬行网址集合
    
    	private Map<String, Url> urls = new HashMap<String, Url>(10000);// 去重网址集合,防止重复爬
    
    	private Map<Integer, Integer> urlsIndexPointor = new HashMap<Integer, Integer>();//索引表
    
    	
    	/**
    	 * 
    	 * 将URL地址添加到未采集池
    	 * 
    	 * 
    	 * @param url
    	 * @return
    	 */
    	private boolean addUrlToPool(Url url) {
    		boolean result = false;
    		try {
    			if (!urls.containsKey(url.getUrl())) {
    				int index = 0;//默认为0,当下面的搜索过程没有找到index的时候
    				for (int i = 0; url.getDepth() - i > 0; i++) {// 从索引表中寻找需要插入的位置
    					if (urlsIndexPointor.containsKey(url.getDepth() - i)) {
    						index = urlsIndexPointor.get(url.getDepth() - i) + 1;
    						break;
    					}
    				}
    
    				uncrawedUrl.add(index, url);
    				urlsIndexPointor.put(url.getDepth(), index);
    				urls.put(url.getUrl(), url);
    				
    				//更新索引表(这个表的内容不会扩展很大,因此遍历效率可以忽略)
    				Iterator<Entry<Integer, Integer>> iter = urlsIndexPointor.entrySet().iterator();
    				while (iter.hasNext()) {
    					Entry<Integer, Integer> entry = iter.next();
    					if (entry.getKey() > url.getDepth()) {
    						entry.setValue(entry.getKey() + 1);
    					}
    				}
    				
    				result = true;
    			}
    		} catch (Exception e) {			
    			e.printStackTrace();
    		}
    		return result;
    	}
    	
    	
    	/**
    	 * 
    	 * 从URL池中取出一条未爬去过的地址
    	 * 
    	 * 
    	 * @return 没有则返回null
    	 */
    	private Url getUrlFromPool() {
    		Url result = null;
    		if (uncrawedUrl.size() > 0) {
    			result = uncrawedUrl.get(0);
    			uncrawedUrl.remove(0);
    			
    			// 更新索引表,将所有的位置指针向前移动一位
    			Iterator<Entry<Integer, Integer>> iter = urlsIndexPointor.entrySet().iterator();
    			while (iter.hasNext()) {
    				Entry<Integer, Integer> entry = iter.next();
    				if (entry.getValue() == 0) {
    					iter.remove();
    				}
    				entry.setValue(entry.getValue() - 1);
    			}			
    
    		}		
    		return result;
    	}
    }
    
    

  • Url.java
  • class Url {
    	private int depth;
    	private String url;
    
    	public int getDepth() {
    		return depth;
    	}
    
    	public String getUrl() {
    		return url;
    	}
    
    	public void setDepth(int depth) {
    		this.depth = depth;
    	}
    
    	public void setUrl(String url) {
    		this.url = url;
    	}
    }
    





    你可能感兴趣的:(算法,Web)