网页爬虫的设计与实现(Java版)
网页爬虫的设计与实现(Java版)
最近为了练手而且对网页爬虫也挺感兴趣,决定自己写一个网页爬虫程序。
首先看看爬虫都应该有哪些功能。
内容来自(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版)的更多相关文章
- 老李分享:网页爬虫java实现
老李分享:网页爬虫java实现 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821 ...
- 第八篇 :微信公众平台开发实战Java版之如何网页授权获取用户基本信息
第一部分:微信授权获取基本信息的介绍 我们首先来看看官方的文档怎么说: 如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑. 关于网页授权回调域 ...
- java实现网页爬虫
接着上面一篇对爬虫需要的java知识,这一篇目的就是在于网页爬虫的实现,对数据的获取,以便分析. -----> 目录: 1.爬虫原理 2.本地文件数据提取及分析 3.单网页数据的读取 4.运 ...
- JAVA之旅(三十四)——自定义服务端,URLConnection,正则表达式特点,匹配,切割,替换,获取,网页爬虫
JAVA之旅(三十四)--自定义服务端,URLConnection,正则表达式特点,匹配,切割,替换,获取,网页爬虫 我们接着来说网络编程,TCP 一.自定义服务端 我们直接写一个服务端,让本机去连接 ...
- Java正则表达式--网页爬虫
网页爬虫:其实就一个程序用于在互联网中获取符合指定规则的数据 爬取邮箱地址,爬取的源不同,本地爬取或者是网络爬取 (1)爬取本地数据: public static List<String> ...
- Python 网页爬虫 & 文本处理 & 科学计算 & 机器学习 & 数据挖掘兵器谱(转)
原文:http://www.52nlp.cn/python-网页爬虫-文本处理-科学计算-机器学习-数据挖掘 曾经因为NLTK的缘故开始学习Python,之后渐渐成为我工作中的第一辅助脚本语言,虽然开 ...
- [resource-]Python 网页爬虫 & 文本处理 & 科学计算 & 机器学习 & 数据挖掘兵器谱
reference: http://www.52nlp.cn/python-%e7%bd%91%e9%a1%b5%e7%88%ac%e8%99%ab-%e6%96%87%e6%9c%ac%e5%a4% ...
- [JsonSchema] 关于接口测试 Json 格式比对核心算法实现 (Java 版)
引言 为什么要自己重新造轮子,而不是采用第三方的JsonSchema方法进行实现存在以下痛点:1.我之前在网上找了很久,没有找到java版直接进行jsonschema生成的方法或直接比较的方法2.ht ...
- 【Python】Python 网页爬虫 & 文本处理 & 科学计算 & 机器学习 & 数据挖掘兵器谱
本文转载自:https://www.cnblogs.com/colipso/p/4284510.html 好文 mark http://www.52nlp.cn/python-%E7%BD%91%E9 ...
随机推荐
- 软件工程课后作业——用JAVA编写的随机产生30道四则运算
package com.java.sizeyunsuan; public class lianxi { String f() { int i=(int)(Math.random()*10); int ...
- “我爱淘”冲刺阶段Scrum站立会议8
完成任务: 今天最大的成功就是解决了昨天的问题,可以将xml文件的内容解析出来显示到软件中. 计划任务: 可以通过webservice将数据库中的内容解析出来,通过查询可以得到想要的内容. 遇到问题: ...
- 四则运算出题器(c++)
一.设计思路 这次版本加入了一下功能: 可定制题目的数量:修改循环次数: 可以定制每行打印的题目数和行间距的大小(当前题目序号可以整除定制数时输出输入的行间距个换行符): 可以定制算式的范围(修改随机 ...
- 30道小学生四则运算题C/C++编程
软件工程科课上,老师通过实例讲解什么是程序,程序和软件的区别,要求我们通过短时间写一道编程题, 题目就是编写30道小学生四则运算题.以下就是源代码: #include<iostream.h> ...
- Mysql 导出数据库和指定表中的数据
参考地址:http://jingyan.baidu.com/article/b7001fe14240ab0e7282dde9.html [root@youo zw]# mysqldump -u roo ...
- OpenCms 集成外部Solr Server
OpenCms默认是以内嵌的Solr作为全文搜索服务的,不过我们也可以配置一个独立的Solr搜索服务器 设置外部Solr Server 1. 从Solr 官方站点http://lucene.apach ...
- ASP.NET本质论阅读----线程与异步
线程 概要:操作系统通过线程对程序的执行进行管理 线程的数据结构:1.线程的核心对象(包含线程的当前寄存器状态),调用线程时-寄存器状态被加载到CPU中. 2.线程环境块TEB:一块用户模式下的内存 ...
- Java8 Lambda sample (iwantmoon.com出品)
转载请注明出处:http://iwantmoon.com/Post/83a4497a74674612834965857e7bc044 .Net转到Java来,不知不觉已经有两年了,之前已经用习惯的li ...
- firefox浏览器live http headers无法使用
手贱的将firefox升级后,很多的插件不能使用.我这里因为用到live http headers,所以以此为例子.主要表现为live http headers修改数据包后,尤其是post数据包后,r ...
- Win8必知快捷键汇总
* Win+C:调出应用Charm菜单(开始界面.传统桌面) * Win+D:所有程序最小化,再次按下恢复(开始界面.传统桌面) * Win+E:打开我的电脑(开始界面.传统桌面) * Win+F:调 ...