Java网络爬虫的实现


网络爬虫是一个自动提取网页的程序,它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成,其基本架构如下图所示:

传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。对于垂直搜索来说,聚焦爬虫,即有针对性地爬取特定主题网页的爬虫,更为适合。

本文爬虫程序的核心代码如下:

Java代码

  1. publicvoidcrawl()throwsThrowable{
  2. while(continueCrawling()){
  3. CrawlerUrlurl=getNextUrl();//获取待爬取队列中的下一个URL
  4. if(url!=null){
  5. printCrawlInfo();
  6. Stringcontent=getContent(url);//获取URL的文本信息
  7. //聚焦爬虫只爬取与主题内容相关的网页,这里采用正则匹配简单处理
  8. if(isContentRelevant(content,this.regexpSearchPattern)){
  9. saveContent(url,content);//保存网页至本地
  10. //获取网页内容中的链接,并放入待爬取队列中
  11. CollectionurlStrings=extractUrls(content,url);
  12. addUrlsToUrlQueue(url,urlStrings);
  13. }else{
  14. System.out.println(url+"isnotrelevantignoring...");
  15. }
  16. //延时防止被对方屏蔽
  17. Thread.sleep(this.delayBetweenUrls);
  18. }
  19. }
  20. closeOutputStream();
  21. }

整个函数由getNextUrl、getContent、isContentRelevant、extractUrls、addUrlsToUrlQueue等几个核心方法组成,下面将一一介绍。先看getNextUrl:

Java代码

复制代码

  1. privateCrawlerUrlgetNextUrl()throwsThrowable{
  2. CrawlerUrlnextUrl=null;
  3. while((nextUrl==null)&&(!urlQueue.isEmpty())){
  4. CrawlerUrlcrawlerUrl=this.urlQueue.remove();
  5. //doWeHavePermissionToVisit:是否有权限访问该URL,友好的爬虫会根据网站提供的"Robot.txt"中配置的规则进行爬取
  6. //isUrlAlreadyVisited:URL是否访问过,大型的搜索引擎往往采用BloomFilter进行排重,这里简单使用HashMap
  7. //isDepthAcceptable:是否达到指定的深度上限。爬虫一般采取广度优先的方式。一些网站会构建爬虫陷阱(自动生成一些无效链接使爬虫陷入死循环),采用深度限制加以避免
  8. if(doWeHavePermissionToVisit(crawlerUrl)
  9. &&(!isUrlAlreadyVisited(crawlerUrl))
  10. &&isDepthAcceptable(crawlerUrl)){
  11. nextUrl=crawlerUrl;
  12. //System.out.println("Nexturltobevisitedis"+nextUrl);
  13. }
  14. }
  15. returnnextUrl;
  16. }

更多的关于robot.txt的具体写法,可参考以下这篇文章:

http://www.bloghuman.com/post/67/

getContent内部使用apache的httpclient 4.1获取网页内容,具体代码如下:

Java代码

  1. privateStringgetContent(CrawlerUrlurl)throwsThrowable{
  2. //HttpClient4.1的调用与之前的方式不同
  3. HttpClientclient=newDefaultHttpClient();
  4. HttpGethttpGet=newHttpGet(url.getUrlString());
  5. StringBufferstrBuf=newStringBuffer();
  6. HttpResponseresponse=client.execute(httpGet);
  7. if(HttpStatus.SC_OK==response.getStatusLine().getStatusCode()){
  8. HttpEntityentity=response.getEntity();
  9. if(entity!=null){
  10. BufferedReaderreader=newBufferedReader(
  11. newInputStreamReader(entity.getContent(),"UTF-8"));
  12. Stringline=null;
  13. if(entity.getContentLength()>0){
  14. strBuf=newStringBuffer((int)entity.getContentLength());
  15. while((line=reader.readLine())!=null){
  16. strBuf.append(line);
  17. }
  18. }
  19. }
  20. if(entity!=null){
  21. entity.consumeContent();
  22. }
  23. }
  24. //将url标记为已访问
  25. markUrlAsVisited(url);
  26. returnstrBuf.toString();
  27. }

对于垂直型应用来说,数据的准确性往往更为重要。聚焦型爬虫的主要特点是,只收集和主题相关的数据,这就是isContentRelevant方法的作用。这里或许要使用分类预测技术,为简单起见,采用正则匹配来代替。其主要代码如下:

Java代码

  1. publicstaticbooleanisContentRelevant(Stringcontent,
  2. PatternregexpPattern){
  3. booleanretValue=false;
  4. if(content!=null){
  5. //是否符合正则表达式的条件
  6. Matcherm=regexpPattern.matcher(content.toLowerCase());
  7. retValue=m.find();
  8. }
  9. returnretValue;
  10. }

extractUrls的主要作用,是从网页中获取更多的URL,包括内部链接和外部链接,代码如下:

Java代码

  1. publicListextractUrls(Stringtext,CrawlerUrlcrawlerUrl){
  2. MapurlMap=newHashMap();
  3. extractHttpUrls(urlMap,text);
  4. extractRelativeUrls(urlMap,text,crawlerUrl);
  5. returnnewArrayList(urlMap.keySet());
  6. }
  7. //处理外部链接
  8. privatevoidextractHttpUrls(MapurlMap,Stringtext){
  9. Matcherm=httpRegexp.matcher(text);
  10. while(m.find()){
  11. Stringurl=m.group();
  12. String[]terms=url.split("ahref=\"");
  13. for(Stringterm:terms){
  14. //System.out.println("Term="+term);
  15. if(term.startsWith("http")){
  16. intindex=term.indexOf("\"");
  17. if(index>0){
  18. term=term.substring(0,index);
  19. }
  20. urlMap.put(term,term);
  21. System.out.println("Hyperlink:"+term);
  22. }
  23. }
  24. }
  25. }
  26. //处理内部链接
  27. privatevoidextractRelativeUrls(MapurlMap,Stringtext,
  28. CrawlerUrlcrawlerUrl){
  29. Matcherm=relativeRegexp.matcher(text);
  30. URLtextURL=crawlerUrl.getURL();
  31. Stringhost=textURL.getHost();
  32. while(m.find()){
  33. Stringurl=m.group();
  34. String[]terms=url.split("ahref=\"");
  35. for(Stringterm:terms){
  36. if(term.startsWith("/")){
  37. intindex=term.indexOf("\"");
  38. if(index>0){
  39. term=term.substring(0,index);
  40. }
  41. Strings="http://"+host+term;
  42. urlMap.put(s,s);
  43. System.out.println("Relativeurl:"+s);
  44. }
  45. }
  46. }
  47. }

如此,便构建了一个简单的网络爬虫程序,可以使用以下程序来测试它:

Java代码

  1. publicstaticvoidmain(String[]args){
  2. try{
  3. Stringurl="http://www.amazon.com";
  4. QueueurlQueue=newLinkedList();
  5. Stringregexp="java";
  6. urlQueue.add(newCrawlerUrl(url,0));
  7. NaiveCrawlercrawler=newNaiveCrawler(urlQueue,100,5,1000L,
  8. regexp);
  9. //booleanallowCrawl=crawler.areWeAllowedToVisit(url);
  10. //System.out.println("Allowedtocrawl:"+url+""+
  11. //allowCrawl);
  12. crawler.crawl();
  13. }catch(Throwablet){
  14. System.out.println(t.toString());
  15. t.printStackTrace();
  16. }
  17. }

当然,你可以为它赋予更为高级的功能,比如多线程、更智能的聚焦、结合Lucene建立索引等等。更为复杂的情况,可以考虑使用一些开源的蜘蛛程序,比如Nutch或是Heritrix等等,就不在本文的讨论范围了。









评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值