最近为了练手而且对网页爬虫也挺感兴趣,决定自己写一个网页爬虫程序。
首先看看爬虫都应该有哪些功能。

内容来自(http://www.ibm.com/developerworks/cn/java/j-lo-dyse1/index.html?ca=drs-)

网页收集的过程如同图的遍历,其中网页就作为图中的节点,而网页中的超链接则作为图中的边,通过某网页的超链接 得到其他网页的地址,从而可以进一步的进行网页收集;图的遍历分为广度优先和深度优先两种方法,网页的收集过程也是如此。综上,Spider 收集网页的过程如下:从初始 URL 集合获得目标网页地址,通过网络连接接收网页数据,将获得的网页数据添加到网页库中并且分析该网页中的其他 URL 链接,放入未访问 URL 集合用于网页收集。下图表示了这个过程:

网页收集器 Gather

网页收集器通过一个 URL 来获取该 URL 对应的网页数据,其实现主要是利用 Java 中的 URLConnection 类来打开 URL 对应页面的网络连接,然后通过 I/O 流读取其中的数据,BufferedReader 提供读取数据的缓冲区提高数据读取的效率以及其下定义的 readLine() 行读取函数。代码如下 ( 省略了异常处理部分 ):

URL url = new URL(“http://www.xxx.com”);
URLConnection conn = url.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null; while((line = reader.readLine()) != null)          document.append(line + "\n");

网页处理

收集到的单个网页,需要进行两种不同的处理,一种是放入网页库,作为后续处理的原始数据;另一种是被分析之后,抽取其中的 URL 连接,放入 URL 池等待对应网页的收集。

网页的保存需要按照一定的格式,以便以后数据的批量处理。这里介绍一种存储数据格式,该格式从北大天网的存储格式简化而来:

  • 网页库由若干记录组成,每个记录包含一条网页数据信息,记录的存放为顺序添加;
  • 一条记录由数据头、数据、空行组成,顺序为:头部 + 空行 + 数据 + 空行;
  • 头部由若干属性组成,有:版本号,日期,IP 地址,数据长度,按照属性名和属性值的方式排列,中间加冒号,每个属性占用一行;
  • 数据即为网页数据。

需要说明的是,添加数据收集日期的原因,由于许多网站的内容都是动态变化的,比如一些大型门户网站的首页内容,这就意味着如果不是当天爬取的网页数据,很可能发生数据过期的问题,所以需要添加日期信息加以识别。

URL 的提取分为两步,第一步是 URL 识别,第二步再进行 URL 的整理,分两步走主要是因为有些网站的链接是采用相对路径,如果不整理会产生错误。URL 的识别主要是通过正则表达式来匹配,过程首先设定一个字符串作为匹配的字符串模式,然后在 Pattern 中编译后即可使用 Matcher 类来进行相应字符串的匹配。实现代码如下:

public ArrayList<URL> urlDetector(String htmlDoc)
{
final String patternString = "<[a|A]\\s+href=([^>]*\\s*>)";
Pattern pattern = Pattern.compile(patternString,Pattern.CASE_INSENSITIVE);
ArrayList<URL> allURLs = new ArrayList<URL>();
Matcher matcher = pattern.matcher(htmlDoc);
String tempURL; //初次匹配到的url是形如:<a href="http://bbs.life.xxx.com.cn/" target="_blank">
//为此,需要进行下一步的处理,把真正的url抽取出来,
//可以对于前两个"之间的部分进行记录得到url
while(matcher.find()){      try {          tempURL = matcher.group();          tempURL = tempURL.substring(tempURL.indexOf("\"")+1);          if(!tempURL.contains("\"")) continue;          tempURL = tempURL.substring(0, tempURL.indexOf("\""));          }       catch (MalformedURLException e)          { e.printStackTrace(); }   }
return allURLs; }

按照“<[a|A]\\s+href=([^>]*\\s*>)”这个正则表达式可以匹配出 URL 所在的整个标签,形如“<a href="http://bbs.life.xxx.com.cn/" target="_blank">”,所以在循环获得整个标签之后,需要进一步提取出真正的 URL,我们可以通过截取标签中前两个引号中间的内容来获得这段内容。如此之后,我们可以得到一个初步的属于该网页的 URL 集合。

接下来我们进行第二步操作,URL 的整理,即对之前获得的整个页面中 URL 集合进行筛选和整合。整合主要是针对网页地址是相对链接的部分,由于我们可以很容易的获得当前网页的 URL,所以,相对链接只需要在当前网页的 URL 上添加相对链接的字段即可组成完整的 URL,从而完成整合。另一方面,在页面中包含的全面 URL 中,有一些网页比如广告网页是我们不想爬取的,或者不重要的,这里我们主要针对于页面中的广告进行一个简单处理。一般网站的广告连接都有相应的显示表达, 比如连接中含有“ad”等表达时,可以将该链接的优先级降低,这样就可以一定程度的避免广告链接的爬取。

经过这两步操作时候,可以把该网页的收集到的 URL 放入 URL 池中,接下来我们处理爬虫的 URL 的派分问题。

Dispatcher 分配器

分配器管理 URL,负责保存着 URL 池并且在 Gather 取得某一个网页之后派分新的 URL,还要避免网页的重复收集。分配器采用设计模式中的单例模式编码,负责提供给 Gather 新的 URL,因为涉及到之后的多线程改写,所以单例模式显得尤为重要。

重复收集是指物理上存在的一个网页,在没有更新的前提下,被 Gather 重复访问,造成资源的浪费,主要原因是没有清楚的记录已经访问的 URL 而无法辨别。所以,Dispatcher 维护两个列表 ,“已访问表”,和“未访问表”。每个 URL 对应的页面被抓取之后,该 URL 放入已访问表中,而从该页面提取出来的 URL 则放入未访问表中;当 Gather 向 Dispatcher 请求 URL 的时候,先验证该 URL 是否在已访问表中,然后再给 Gather 进行作业。

Spider 启动多个 Gather 线程

现在 Internet 中的网页数量数以亿计,而单独的一个 Gather 来进行网页收集显然效率不足,所以我们需要利用多线程的方法来提高效率。Gather 的功能是收集网页,我们可以通过 Spider 类来开启多个 Gather 线程,从而达到多线程的目的。代码如下:

public void start()
{
Dispatcher disp = Dispatcher.getInstance();
for(int i = 0; i < gatherNum; i++)
{     Thread gather = new Thread(new Gather(disp));     gather.start();
}
}
在开启线程之后,网页收集器开始作业的运作,并在一个作业完成之后,向 Dispatcher 申请下一个作业,因为有了多线程的 Gather,为了避免线程不安全,需要对 Dispatcher 进行互斥访问,在其函数之中添加 synchronized 关键词,从而达到线程的安全访问。

网页爬虫的设计与实现(Java版)相关推荐

  1. java扫雷设计_毕业设计Java版扫雷的设计与实现介绍

    毕业设计Java版扫雷的设计与实现介绍 java语言eclipse环境 源码+精品文档 价格98元 扫雷是一款玩法相当简单的大众化的小游戏,游戏的胜利条件是在最短的时间内根据点击格子出现的数字找出所有 ...

  2. 利用Fiddler手机抓包对ONE·APP网页爬虫实现电影资讯微信Java开发

    前言 好久没写博客了,打算把之前做的一个电影评分资讯推送的微信开发全程记录一下,适合对网络爬虫.微信开发感兴趣的童鞋.在教程开始之前,我想先引出两个问题(这次写博客假装很有条理的样子= =) 1. 为 ...

  3. 利用Fiddler手机抓包对ONE APP网页爬虫实现电影资讯微信Java开发

    前言 好久没写博客了,打算把之前做的一个电影评分资讯推送的微信开发全程记录一下,适合对网络爬虫.微信开发感兴趣的童鞋.在教程开始之前,我想先引出两个问题(这次写博客假装很有条理的样子= =) 1. 为 ...

  4. 网页上爬取数据(Java版)通俗易懂

    学习目标: 当我们需要获取一些网络上的资源时,爬虫成了一种不可获取的技术,但是各大网站基本都限制通过接口来获取,本文将手把手教大家如何通过网页来获取我们想要的资源(仅供学习使用),一招学会,天下无敌! ...

  5. 分布式网页爬虫系统 设计和实现

    分布式爬虫设计和实现 1.总体设计 功能模块划分: 数据抓取引擎 1.1 调研市面上爬虫框架或库 pholcus colly gocrawl 开发工具:goland 开发语言:golang 数据存储: ...

  6. 红黑树——课程设计(自顶向下JAVA版)

    红黑树(自顶向下) 前言 课程设计,仅供参考. 实现插入及调整和删除及调整. 具体实现流程讲解可参考下面的链接文章. 说明:提供文章的学姐与我的课程设计算法相同. 答辩幻灯片不再提供. 红黑树(自顶向 ...

  7. java网页爬虫xml_基于webmagic的java网页爬虫,抓取网页指定节点,然后使用dom4j分析xml数据...

    /* * Android数据存储之SharedPreferences * 步骤: * 一.根据Context获取SharedPreferences对象 * 二.利用edit()方法获取Editor对象 ...

  8. 设计自己的基于Selenium 的自动化测试框架-Java版(2) - 定义自己的工作流程

    设计自己的基于Selenium的自动化测试框架-Java版(2) -定义自己的工作流程 Work flow chart 上图是整个工作流程,红色虚线上面的需要手动来完成,红色虚线下面的实现自动化. 我 ...

  9. LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口

    目录 1114. 按序打印 解法 1115. 交替打印FooBar 解法 1116. 打印零与奇偶数 解法 1117. H2O 生成 解法 1118. 设计有限阻塞队列 解法 1195. 交替打印字符 ...

最新文章

  1. Activity应用场景解析
  2. 转发:Datawhale第七期组队学习计划
  3. 通过Roslyn构建自己的C#脚本(更新版)
  4. Sql 四大排名函数(ROW_NUMBER、RANK、DENSE_RANK、NTILE)
  5. 一道money计算题引发的思考
  6. 计算机xp系统恢复以前设置,电脑xp系统怎么恢复出厂设置,xp系统怎么恢复出厂设置...
  7. java移位操作示例
  8. 夏令营/保研/考研复试被问到优缺点怎么回答?
  9. 这些 Google 高级搜索技巧,你都知道么?
  10. 论文阅读:CCX-RAYNET: A CLASS CONDITIONED CONVOLUTIONAL NEURAL NETWORK FOR BIPLANAR X-RAYS TO CT VOLUME
  11. 什么是数字孪生技术?
  12. java最大文件描述符,java – 为什么JDK NIO使用这么多的anon_inode文件描述符?
  13. 呼叫中心ACD系统的介绍
  14. python设计迷宫_用Python制作迷宫GIF
  15. Source Insight——C/C++代码阅读器
  16. Altium Designer绘制原理图
  17. 学霸(bushi)读python3
  18. selenium 处理多浏览器测试
  19. PHP 查看真实文件类型、图片有效性
  20. 日本东映动画遭黑客入侵,《海贼王》等多部作品遭停播

热门文章

  1. python自己做个定时器_技术图文:如何利用 Python 做一个简单的定时器类?
  2. python函数和模块的使用方法_Python学习06_函数和模块的使用
  3. java简单计算机程序_JAVA程序编的简单计算器程序??
  4. 光模块该如何使用,光模块的使用方法介绍!
  5. 二层和三层工业交换机的主要参数说明
  6. 【渝粤题库】国家开放大学2021春2444酒店管理概论答案
  7. 5G三兄弟NB-IoT排老几?NB-IoT介绍
  8. 王者体验服服务器注册人数已满,王者荣耀体验服注册人数达到上限怎么回事?体验服测试最新申请方法...
  9. latex-bib参考文献人名特殊字符
  10. 深入理解C指针第一章小结1