使用Java实现网络爬虫_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 使用Java实现网络爬虫

使用Java实现网络爬虫

 2013/9/30 10:17:54  flycars001  程序员俱乐部  我要评论(0)
  • 摘要:记得在刚找工作时,隔壁的一位同学在面试时豪言壮语曾实现过网络爬虫,当时的景仰之情犹如滔滔江水连绵不绝。后来,在做图片搜索时,需要大量的测试图片,因此萌生了从Amazon中爬取图书封面图片的想法,从网上也吸取了一些前人的经验,实现了一个简单但足够用的爬虫系统。网络爬虫是一个自动提取网页的程序,它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成,其基本架构如下图所示:传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列
  • 标签:实现 使用 Java 网络 网络爬虫

记得在刚找工作时,隔壁的一位同学在面试时豪言壮语曾实现过网络爬虫,当时的景仰之情犹如滔滔江水连绵不绝。后来,在做图片搜索时,需要大量的测试图片,因此萌生了从Amazon中爬取图书封面图片的想法,从网上也吸取了一些前人的经验,实现了一个简单但足够用的爬虫系统。

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



?

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

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

Java代码

?

?

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

?

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

Java代码

?

复制代码files/uploadimg/20110309/1015301.gif">

?

?

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

?

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

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

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

Java代码

?

?

  1. private?String?getContent(CrawlerUrl?url)?throws?Throwable?{??? ?
  2. ????//HttpClient4.1的调用与之前的方式不同??? ?
  3. ????HttpClient?client?=?new?DefaultHttpClient();??? ?
  4. ????HttpGet?httpGet?=?new?HttpGet(url.getUrlString());??? ?
  5. ????StringBuffer?strBuf?=?new?StringBuffer();??? ?
  6. ????HttpResponse?response?=?client.execute(httpGet);??? ?
  7. ????if?(HttpStatus.SC_OK?==?response.getStatusLine().getStatusCode())?{??? ?
  8. ????????HttpEntity?entity?=?response.getEntity();??? ?
  9. ????????if?(entity?!=?null)?{??? ?
  10. ????????????BufferedReader?reader?=?new?BufferedReader(??? ?
  11. ????????????????new?InputStreamReader(entity.getContent(),?"UTF-8"));??? ?
  12. ????????????String?line?=?null;??? ?
  13. ????????????if?(entity.getContentLength()?>?0)?{??? ?
  14. ????????????????strBuf?=?new?StringBuffer((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. ????return?strBuf.toString();??? ?
  27. }?? ?

?

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

Java代码

?

?

  1. public?static?boolean?isContentRelevant(String?content,??? ?
  2. Pattern?regexpPattern)?{??? ?
  3. ????boolean?retValue?=?false;??? ?
  4. ????if?(content?!=?null)?{??? ?
  5. ????????//是否符合正则表达式的条件??? ?
  6. ????????Matcher?m?=?regexpPattern.matcher(content.toLowerCase());??? ?
  7. ????????retValue?=?m.find();??? ?
  8. ????}??? ?
  9. ????return?retValue;??? ?
  10. }?? ?

?

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

Java代码

?

?

  1. public?List?extractUrls(String?text,?CrawlerUrl?crawlerUrl)?{??? ?
  2. ????Map<string,?string>?urlMap?=?new?HashMap<string,?string>();??? ?
  3. ????extractHttpUrls(urlMap,?text);??? ?
  4. ????extractRelativeUrls(urlMap,?text,?crawlerUrl);??? ?
  5. ????return?new?ArrayList(urlMap.keySet());??? ?
  6. }??? ?
  7. ?? ?
  8. //处理外部链接??? ?
  9. private?void?extractHttpUrls(Map<string,?string>?urlMap,?String?text)?{??? ?
  10. ????Matcher?m?=?httpRegexp.matcher(text);??? ?
  11. ????while?(m.find())?{??? ?
  12. ????????String?url?=?m.group();??? ?
  13. ????????String[]?terms?=?url.split("a?href=\"");??? ?
  14. ????????for?(String?term?:?terms)?{??? ?
  15. ????????????//?System.out.println("Term?=?"?+?term);??? ?
  16. ????????????if?(term.startsWith("http"))?{??? ?
  17. ????????????????int?index?=?term.indexOf("\"");??? ?
  18. ????????????????if?(index?>?0)?{??? ?
  19. ????????????????????term?=?term.substring(0,?index);??? ?
  20. ????????????????}??? ?
  21. ????????????????urlMap.put(term,?term);??? ?
  22. ????????????????System.out.println("Hyperlink:?"?+?term);??? ?
  23. ????????????}??? ?
  24. ????????}??? ?
  25. ????}??? ?
  26. }??? ?
  27. ?? ?
  28. //处理内部链接??? ?
  29. private?void?extractRelativeUrls(Map<string,?string>?urlMap,?String?text,??? ?
  30. ????????CrawlerUrl?crawlerUrl)?{??? ?
  31. ????Matcher?m?=?relativeRegexp.matcher(text);??? ?
  32. ????URL?textURL?=?crawlerUrl.getURL();??? ?
  33. ????String?host?=?textURL.getHost();??? ?
  34. ????while?(m.find())?{??? ?
  35. ????????String?url?=?m.group();??? ?
  36. ????????String[]?terms?=?url.split("a?href=\"");??? ?
  37. ????????for?(String?term?:?terms)?{??? ?
  38. ????????????if?(term.startsWith("/"))?{??? ?
  39. ????????????????int?index?=?term.indexOf("\"");??? ?
  40. ????????????????if?(index?>?0)?{??? ?
  41. ????????????????????term?=?term.substring(0,?index);??? ?
  42. ????????????????}??? ?
  43. ????????????????String?s?=?"http://"?+?host?+?term;??? ?
  44. ????????????????urlMap.put(s,?s);??? ?
  45. ????????????????System.out.println("Relative?url:?"?+?s);??? ?
  46. ????????????}??? ?
  47. ????????}??? ?
  48. ????}??? ?
  49. ?? ?
  50. }?? ?

?

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

Java代码

?

?

  1. public?static?void?main(String[]?args)?{??? ?
  2. ????try?{??? ?
  3. ????????String?url?=?"http://www.amazon.com";??? ?
  4. ????????Queue?urlQueue?=?new?LinkedList();??? ?
  5. ????????String?regexp?=?"java";??? ?
  6. ????????urlQueue.add(new?CrawlerUrl(url,?0));??? ?
  7. ????????NaiveCrawler?crawler?=?new?NaiveCrawler(urlQueue,?100,?5,?1000L,??? ?
  8. ????????????????regexp);??? ?
  9. ????????//?boolean?allowCrawl?=?crawler.areWeAllowedToVisit(url);??? ?
  10. ????????//?System.out.println("Allowed?to?crawl:?"?+?url?+?"?"?+??? ?
  11. ????????//?allowCrawl);??? ?
  12. ????????crawler.crawl();??? ?
  13. ????}?catch?(Throwable?t)?{??? ?
  14. ????????System.out.println(t.toString());??? ?
  15. ????????t.printStackTrace();??? ?
  16. ????}??? ?
  17. }?? ?

?

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

  • 大小: 14.5 KB
  • 查看图片附件
发表评论
用户名: 匿名