crawler4j是用Java实现的开源网络爬虫。提供了简单易用的接口,可以在几分钟内创建一个多线程网络爬虫。下面实例结合jsoup解析网页,javacsv存储采集数据;采集自如ziroom租房网(http://sz.ziroom.com/z/nl/)的出租房信息。

所有的过程仅需两步完成:

第一步:开发Ziroom采集核心部分代码:

  1. /**
  2. * @date 2016年8月20日 下午6:13:24
  3. * @version
  4. * @since JDK 1.8
  5. */
  6. public class ZiroomCrawler extends WebCrawler {
  7.  
  8. /** 爬取匹配原则 */
  9. private final static Pattern FILTERS = Pattern.compile(".*(\\.(css|js|bmp|gif|jpe?g|ico"
  10. + "|png|tiff?|mid|mp2|mp3|mp4" + "|wav|avi|mov|mpeg|ram|m4v|pdf" + "|rm|smil|wmv|swf|wma|zip|rar|gz))$");
  11. /** 爬取数据保存文件路径 */
  12. private final static String DATA_PATH = "data/crawl/ziroom.csv";
  13. /** 爬取link文件路径 */
  14. private final static String LINK_PATH = "data/crawl/link.csv";
  15. // private static final Logger logger =
  16. // LoggerFactory.getLogger(ZiroomCrawler.class);
  17.  
  18. private final static String URL_PREFIX = "http://sh.ziroom.com/z/nl/";
  19.  
  20. private final File fLinks;
  21. private final File fDatas;
  22.  
  23. private CsvWriter csvLinks;
  24. private CsvWriter csvDatas;
  25.  
  26. /**
  27. * You should implement this function to specify whether the given url
  28. * should be crawled or not (based on your crawling logic).
  29. */
  30. ZiroomCrawlStat myCrawlStat;
  31.  
  32. public ZiroomCrawler() throws IOException {
  33. myCrawlStat = new ZiroomCrawlStat();
  34. fLinks = new File(DATA_PATH);
  35. fDatas = new File(LINK_PATH);
  36. if (fLinks.isFile()) {
  37. fLinks.delete();
  38. }
  39. if (fDatas.isFile()) {
  40. fDatas.delete();
  41. }
  42. csvDatas = new CsvWriter(new FileWriter(fDatas, true), ',');
  43. csvDatas.write("请求路径");
  44. csvDatas.endRecord();
  45. csvDatas.close();
  46. csvLinks = new CsvWriter(new FileWriter(fLinks, true), ',');
  47. csvLinks.write("图片");
  48. csvLinks.write("价格");
  49. csvLinks.write("地址");
  50. csvLinks.write("说明");
  51. csvLinks.endRecord();
  52. csvLinks.close();
  53. }
  54.  
  55. public void dumpMyData() {
  56. final int id = getMyId();
  57. // You can configure the log to output to file
  58. logger.info("Crawler {} > Processed Pages: {}", id, myCrawlStat.getTotalProcessedPages());
  59. logger.info("Crawler {} > Total Links Found: {}", id, myCrawlStat.getTotalLinks());
  60. logger.info("Crawler {} > Total Text Size: {}", id, myCrawlStat.getTotalTextSize());
  61. }
  62.  
  63. @Override
  64. public Object getMyLocalData() {
  65. return myCrawlStat;
  66. }
  67.  
  68. @Override
  69. public void onBeforeExit() {
  70. dumpMyData();
  71. }
  72.  
  73. /*
  74. * 这个方法决定了要抓取的URL及其内容,例子中只允许抓取“http://sh.ziroom.com/z/nl/”这个域的页面,
  75. * 不允许.css、.js和多媒体等文件
  76. *
  77. * @see edu.uci.ics.crawler4j.crawler.WebCrawler#shouldVisit(edu.uci.ics.
  78. * crawler4j.crawler.Page, edu.uci.ics.crawler4j.url.WebURL)
  79. */
  80. @Override
  81. public boolean shouldVisit(Page referringPage, WebURL url) {
  82. final String href = url.getURL().toLowerCase();
  83.  
  84. if (FILTERS.matcher(href).matches() || !href.startsWith(URL_PREFIX)) {
  85. return false;
  86. }
  87. return true;
  88. }
  89.  
  90. /*
  91. * 当URL下载完成会调用这个方法。你可以轻松获取下载页面的url, 文本, 链接, html,和唯一id等内容。
  92. *
  93. * @see
  94. * edu.uci.ics.crawler4j.crawler.WebCrawler#visit(edu.uci.ics.crawler4j.
  95. * crawler.Page)
  96. */
  97. @Override
  98. public void visit(Page page) {
  99. final String url = page.getWebURL().getURL();
  100. logger.info("爬取路径:" + url);
  101. myCrawlStat.incProcessedPages();
  102. if (page.getParseData() instanceof HtmlParseData) {
  103. final HtmlParseData htmlParseData = (HtmlParseData) page.getParseData();
  104. final Set<WebURL> links = htmlParseData.getOutgoingUrls();
  105. try {
  106. linkToCsv(links);
  107. } catch (final IOException e2) {
  108. // TODO Auto-generated catch block
  109. e2.printStackTrace();
  110. }
  111. myCrawlStat.incTotalLinks(links.size());
  112. try {
  113. myCrawlStat.incTotalTextSize(htmlParseData.getText().getBytes("UTF-8").length);
  114. } catch (final UnsupportedEncodingException e1) {
  115. // TODO Auto-generated catch block
  116. e1.printStackTrace();
  117. }
  118. final String html = htmlParseData.getHtml();
  119.  
  120. final Document doc = Jsoup.parse(html);
  121.  
  122. final Elements contents = doc.select("li[class=clearfix]");
  123.  
  124. for (final Element c : contents) {
  125. // 图片
  126. final String img = c.select(".img img").first().attr("src");
  127. logger.debug("图片:" + img);
  128.  
  129. // 地址
  130. final Element txt = c.select("div[class=txt]").first();
  131. final String arr1 = txt.select("h3 a").first().text();
  132. final String arr2 = txt.select("h4 a").first().text();
  133. final String arr3 = txt.select("div[class=detail]").first().text();
  134.  
  135. final String arr = arr1.concat(arr1 + ",").concat(arr2 + ",").concat(arr3);
  136. logger.debug("地址:" + arr);
  137. // 说明
  138. final String rank = txt.select("p").first().text();
  139. logger.debug("说明:" + rank);
  140.  
  141. // 价格
  142. final String pirce = c.select("p[class=price]").first().text();
  143.  
  144. try {
  145. csvLinks = new CsvWriter(new FileWriter(fLinks, true), ',');
  146. csvLinks.write(img);
  147. csvLinks.write(pirce);
  148. csvLinks.write(arr);
  149. csvLinks.write(rank);
  150. csvLinks.endRecord();
  151. csvLinks.flush();
  152. csvLinks.close();
  153. } catch (final IOException e) {
  154. e.printStackTrace();
  155. }
  156. }
  157. }
  158. }
  159.  
  160. private void linkToCsv(Set<WebURL> links) throws IOException {
  161. csvDatas = new CsvWriter(new FileWriter(fDatas, true), ',');
  162. for (final WebURL webURL : links) {
  163. csvDatas.write(webURL.getURL());
  164. }
  165. csvDatas.flush();
  166. csvDatas.endRecord();
  167. csvDatas.close();
  168. }
  169. }

第二步:开发Ziroom采集控制部分代码:

  1. /**
  2. * @date 2016年8月20日 下午6:15:01
  3. * @version
  4. * @since JDK 1.8
  5. */
  6. public class ZiroomController {
  7.  
  8. public static void main(String[] args) {
  9.  
  10. final String crawlStorageFolder = "data/crawl/root";
  11. final int numberOfCrawlers = 3;
  12.  
  13. final CrawlConfig config = new CrawlConfig();
  14. config.setCrawlStorageFolder(crawlStorageFolder);
  15. config.setPolitenessDelay(1000);
  16. config.setIncludeBinaryContentInCrawling(false);
  17. config.setMaxPagesToFetch(50);
  18.  
  19. final PageFetcher pageFetcher = new PageFetcher(config);
  20. final RobotstxtConfig robotstxtConfig = new RobotstxtConfig();
  21. final RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcher);
  22. CrawlController controller;
  23. try {
  24. controller = new CrawlController(config, pageFetcher, robotstxtServer);
  25.  
  26. controller.addSeed("http://sh.ziroom.com/z/nl/");
  27.  
  28. controller.start(ZiroomCrawler.class, numberOfCrawlers);
  29.  
  30. final List<Object> crawlersLocalData = controller.getCrawlersLocalData();
  31. long totalLinks = 0;
  32. long totalTextSize = 0;
  33. int totalProcessedPages = 0;
  34. for (final Object localData : crawlersLocalData) {
  35. final ZiroomCrawlStat stat = (ZiroomCrawlStat) localData;
  36. totalLinks += stat.getTotalLinks();
  37. totalTextSize += stat.getTotalTextSize();
  38. totalProcessedPages += stat.getTotalProcessedPages();
  39. }
  40.  
  41. System.out.println("Aggregated Statistics:");
  42. System.out.println("\tProcessed Pages: {}" + totalProcessedPages);
  43. System.out.println("\tTotal Links found: {}" + totalLinks);
  44. System.out.println("\tTotal Text Size: {}" + totalTextSize);
  45. } catch (final Exception e) {
  46. // TODO Auto-generated catch block
  47. e.printStackTrace();
  48. }
  49. }
  50. }

第三步:开发Ziroom采集状态搜集代码:

  1. /**
  2. * @date 2016年8月20日 下午6:14:13
  3. * @version
  4. * @since JDK 1.8
  5. */
  6. public class ZiroomCrawlStat {
  7. private long totalLinks;
  8. private int totalProcessedPages;
  9. private long totalTextSize;
  10.  
  11. public long getTotalLinks() {
  12. return totalLinks;
  13. }
  14.  
  15. public int getTotalProcessedPages() {
  16. return totalProcessedPages;
  17. }
  18.  
  19. public long getTotalTextSize() {
  20. return totalTextSize;
  21. }
  22.  
  23. public void incProcessedPages() {
  24. this.totalProcessedPages++;
  25. }
  26.  
  27. public void incTotalLinks(int count) {
  28. this.totalLinks += count;
  29. }
  30.  
  31. public void incTotalTextSize(int count) {
  32. this.totalTextSize += count;
  33. }
  34.  
  35. public void setTotalLinks(long totalLinks) {
  36. this.totalLinks = totalLinks;
  37. }
  38.  
  39. public void setTotalProcessedPages(int totalProcessedPages) {
  40. this.totalProcessedPages = totalProcessedPages;
  41. }
  42.  
  43. public void setTotalTextSize(long totalTextSize) {
  44. this.totalTextSize = totalTextSize;
  45. }
  46. }

Ziroom采集数据展示:

crawler4j源码学习(2):Ziroom租房网房源信息采集爬虫的更多相关文章

  1. crawler4j源码学习(1):搜狐新闻网新闻标题采集爬虫

    crawler4j是用Java实现的开源网络爬虫.提供了简单易用的接口,可以在几分钟内创建一个多线程网络爬虫.下面实例结合jsoup,采集搜狐新闻网(http://news.sohu.com/)新闻标 ...

  2. NewBluePill源码学习

    NewBluePill的源码也看的差不多了,一直说等有时间了再写学习的一些心得,拖来拖去弄到现在了,时间不是等来的,慢慢开始吧. 0x00     初识硬件虚拟化 硬件虚拟化对大数人来讲还是比较陌生. ...

  3. 框架源码系列十一:事务管理(Spring事务管理的特点、事务概念学习、Spring事务使用学习、Spring事务管理API学习、Spring事务源码学习)

    一.Spring事务管理的特点 Spring框架为事务管理提供一套统一的抽象,带来的好处有:1. 跨不同事务API的统一的编程模型,无论你使用的是jdbc.jta.jpa.hibernate.2. 支 ...

  4. Vue源码学习1——Vue构造函数

    Vue源码学习1--Vue构造函数 这是我第一次正式阅读大型框架源码,刚开始的时候完全不知道该如何入手.Vue源码clone下来之后这么多文件夹,Vue的这么多方法和概念都在哪,完全没有头绪.现在也只 ...

  5. NewBluePill源码学习 <一>

    NewBluePill的源码也看的差不多了,一直说等有时间了再写学习的一些心得,拖来拖去弄到现在了,时间不是等来的,慢慢开始吧. 0x00     初识硬件虚拟化 硬件虚拟化对大数人来讲还是比较陌生. ...

  6. Vue源码学习二 ———— Vue原型对象包装

    Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...

  7. SpringBoot源码学习系列之SpringMVC自动配置

    目录 1.ContentNegotiatingViewResolver 2.静态资源 3.自动注册 Converter, GenericConverter, and Formatter beans. ...

  8. SpringBoot源码学习系列之嵌入式Servlet容器

    目录 1.博客前言简单介绍 2.定制servlet容器 3.变换servlet容器 4.servlet容器启动原理 SpringBoot源码学习系列之嵌入式Servlet容器启动原理 @ 1.博客前言 ...

  9. vue-elemnt-admin源码学习

    vue-elemnt-admin源码学习 vue-element-admin是一个基于vue,element-ui的集成的管理后台.它的安装部分就不说了,按照官网的步骤一步步就可以执行了. https ...

随机推荐

  1. websocket总结

    一.WebSocket简介 WebSocket  protocol是HTML5一种新的协议,WebSocket 是目前唯一真正实现全双工通信的服务器向客户端推送的互联网技术.WebSocket的出现使 ...

  2. steps animation

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. HDU 1264 Counting Squares(线段树求面积的并)

    Counting Squares Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  4. A trip through the Graphics Pipeline 2011_10_Geometry Shaders

    Welcome back.     Last time, we dove into bottom end of the pixel pipeline. This time, we’ll switch ...

  5. ThinkPHP 3.2.3 中设置和使用 Session

    Session 的配置 可以在 config.php(可以是应用公用的 config.php 或模块的 config.php)中对 Session 进行配置,例如: config.php <?p ...

  6. mysql组合索引顺序参考

    问题背景 : 当我们需要创建一个组合索引, 索引的顺序对于效率影响很大, 怎么确定索引的顺序; 解决方法 : 我们应该依据字段的全局基数和选择性, 而不是字段的某个具体的值来确定; 表结构 :  dc ...

  7. NEC学习 ---- 模块 -水平文字链接列表

    HTML代码: <div class="container"> <div class="m-list1"> <ul class=& ...

  8. Thinking in Java——笔记(10)

    Inner Classes It allows you to group classes that logically belong together and to control the visib ...

  9. yii2知识点理解(成员属性)

    yii2成员属性 成员变量类似于public $a; 成员属性类似于 public function a(){} 成员变量是就类的结构构成而言的概念,而属性是就类的功能逻辑而言的概念 成员属性应用: ...

  10. LeetCode Alien Dictionary

    原题链接在这里:https://leetcode.com/problems/alien-dictionary/ 题目: There is a new alien language which uses ...