爬虫6:多页面增量Java爬虫-sina主页
之前写过很多单页面python爬虫,感觉python还是很好用的,这里用java总结一个多页面的爬虫,迭代爬取种子页面的所有链接的页面,全部保存在tmp路径下。
1 序言
实现这个爬虫需要两个数据结构支持,unvisited队列(priorityqueue:可以适用pagerank等算法计算出url重要度)和visited表(hashset:可以快速查找url是否存在);队列用于实现宽度优先爬取,visited表用于记录爬取过的url,不再重复爬取,避免了环。java爬虫需要的工具包有httpclient和htmlparser1.5,可以在maven repo中查看具体版本的下载。
1目标网站:新浪 http://www.sina.com.cn/
2结果截图:
下面说说爬虫的实现,后期源码会上传到github中,需要的朋友可以留言:
二 爬虫编程
1创建种子页面的url
MyCrawler crawler = new MyCrawler();
crawler.crawling(new String[]{"http://www.sina.com.cn/"});
2初始化unvisited表为上面的种子url
LinkQueue.addUnvisitedUrl(seeds[i]);
3最主要的逻辑实现部分:在队列中取出没有visit过的url,进行下载,然后加入visited的表,并解析改url页面上的其它url,把未读取的加入到unvisited队列;迭代到队列为空停止,所以这个url网络还是很庞大的。注意,这里的页面下载和页面解析需要java的工具包实现,下面具体说明下工具包的使用。
while(!LinkQueue.unVisitedUrlsEmpty()&&LinkQueue.getVisitedUrlNum()<=)
{
//队头URL出队列
String visitUrl=(String)LinkQueue.unVisitedUrlDeQueue();
if(visitUrl==null)
continue;
DownLoadFile downLoader=new DownLoadFile();
//下载网页
downLoader.downloadFile(visitUrl);
//该 url 放入到已访问的 URL 中
LinkQueue.addVisitedUrl(visitUrl);
//提取出下载网页中的 URL Set<String> links=HtmlParserTool.extracLinks(visitUrl,filter);
//新的未访问的 URL 入队
for(String link:links)
{
LinkQueue.addUnvisitedUrl(link);
}
}
4下面html页面的download工具包
public String downloadFile(String url) {
        String filePath = null;
        /* 1.生成 HttpClinet 对象并设置参数 */
        HttpClient httpClient = new HttpClient();
        // 设置 Http 连接超时 5s
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(
                );
        /* 2.生成 GetMethod 对象并设置参数 */
        GetMethod getMethod = new GetMethod(url);
        // 设置 get 请求超时 5s
        getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, );
        // 设置请求重试处理
        getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler());
        /* 3.执行 HTTP GET 请求 */
        try {
            int statusCode = httpClient.executeMethod(getMethod);
            // 判断访问的状态码
            if (statusCode != HttpStatus.SC_OK) {
                System.err.println("Method failed: "
                        + getMethod.getStatusLine());
                filePath = null;
            }
            /* 4.处理 HTTP 响应内容 */
            byte[] responseBody = getMethod.getResponseBody();// 读取为字节数组
            // 根据网页 url 生成保存时的文件名
            filePath = "temp\\"
                    + getFileNameByUrl(url, getMethod.getResponseHeader(
                            "Content-Type").getValue());
            saveToLocal(responseBody, filePath);
        } catch (HttpException e) {
            // 发生致命的异常,可能是协议不对或者返回的内容有问题
            System.out.println("Please check your provided http address!");
            e.printStackTrace();
        } catch (IOException e) {
            // 发生网络异常
            e.printStackTrace();
        } finally {
            // 释放连接
            getMethod.releaseConnection();
        }
        return filePath;
    }
5html页面的解析工具包:
public static Set<String> extracLinks(String url, LinkFilter filter) {
        Set<String> links = new HashSet<String>();
        try {
            Parser parser = new Parser(url);
            parser.setEncoding("gb2312");
            // 过滤 <frame >标签的 filter,用来提取 frame 标签里的 src 属性所表示的链接
            NodeFilter frameFilter = new NodeFilter() {
                public boolean accept(Node node) {
                    if (node.getText().startsWith("frame src=")) {
                        return true;
                    } else {
                        return false;
                    }
                }
            };
            // OrFilter 来设置过滤 <a> 标签,和 <frame> 标签
            OrFilter linkFilter = new OrFilter(new NodeClassFilter(
                    LinkTag.class), frameFilter);
            // 得到所有经过过滤的标签
            NodeList list = parser.extractAllNodesThatMatch(linkFilter);
            for (int i = ; i < list.size(); i++) {
                Node tag = list.elementAt(i);
                if (tag instanceof LinkTag)// <a> 标签
                {
                    LinkTag link = (LinkTag) tag;
                    String linkUrl = link.getLink();// url
                    if (filter.accept(linkUrl))
                        links.add(linkUrl);
                } else// <frame> 标签
                {
                    // 提取 frame 里 src 属性的链接如 <frame src="test.html"/>
                    String frame = tag.getText();
                    int start = frame.indexOf("src=");
                    frame = frame.substring(start);
                    int end = frame.indexOf(" ");
                    if (end == -)
                        end = frame.indexOf(">");
                    String frameUrl = frame.substring(, end - );
                    if (filter.accept(frameUrl))
                        links.add(frameUrl);
                }
            }
        } catch (ParserException e) {
            e.printStackTrace();
        }
        return links;
    }
6未访问页面使用PriorityQueue带偏好的队列保存,主要是为了适用于pagerank等算法,有的url忠诚度更高一些;visited表采用hashset实现,注意可以快速查找是否存在;
public class LinkQueue {
    //已访问的 url 集合
    private static Set visitedUrl = new HashSet();
    //待访问的 url 集合
    private static Queue unVisitedUrl = new PriorityQueue();
    //获得URL队列
    public static Queue getUnVisitedUrl() {
        return unVisitedUrl;
    }
    //添加到访问过的URL队列中
    public static void addVisitedUrl(String url) {
        visitedUrl.add(url);
    }
    //移除访问过的URL
    public static void removeVisitedUrl(String url) {
        visitedUrl.remove(url);
    }
    //未访问的URL出队列
    public static Object unVisitedUrlDeQueue() {
        return unVisitedUrl.poll();
    }
    // 保证每个 url 只被访问一次
    public static void addUnvisitedUrl(String url) {
        if (url != null && !url.trim().equals("")
 && !visitedUrl.contains(url)
                && !unVisitedUrl.contains(url))
            unVisitedUrl.add(url);
    }
    //获得已经访问的URL数目
    public static int getVisitedUrlNum() {
        return visitedUrl.size();
    }
    //判断未访问的URL队列中是否为空
    public static boolean unVisitedUrlsEmpty() {
        return unVisitedUrl.isEmpty();
    }
}
爬虫6:多页面增量Java爬虫-sina主页的更多相关文章
- 爬虫入门  手写一个Java爬虫
		本文内容 涞源于 罗刚 老师的 书籍 << 自己动手写网络爬虫一书 >> ; 本文将介绍 1: 网络爬虫的是做什么的? 2: 手动写一个简单的网络爬虫; 1: 网络爬虫是做 ... 
- JAVA爬虫 WebCollector
		JAVA爬虫 WebCollector 爬虫简介: WebCollector是一个无须配置.便于二次开发的JAVA爬虫框架(内核),它提供精简的的API,只需少量代码即可实现一个功能强大的爬虫. 爬虫 ... 
- Java爬虫系列之实战:爬取酷狗音乐网 TOP500 的歌曲(附源码)
		在前面分享的两篇随笔中分别介绍了HttpClient和Jsoup以及简单的代码案例: Java爬虫系列二:使用HttpClient抓取页面HTML Java爬虫系列三:使用Jsoup解析HTML 今天 ... 
- java爬虫系列第三讲-获取页面中绝对路径的各种方法
		在使用webmgiac的过程中,很多时候我们需要抓取连接的绝对路径,总结了几种方法,示例代码放在最后. 以和讯网的一个页面为例: xpath方式获取 log.info("{}", ... 
- Java爬虫系列二:使用HttpClient抓取页面HTML
		爬虫要想爬取需要的信息,首先第一步就要抓取到页面html内容,然后对html进行分析,获取想要的内容.上一篇随笔<Java爬虫系列一:写在开始前>中提到了HttpClient可以抓取页面内 ... 
- webmagic的设计机制及原理-如何开发一个Java爬虫
		之前就有网友在博客里留言,觉得webmagic的实现比较有意思,想要借此研究一下爬虫.最近终于集中精力,花了三天时间,终于写完了这篇文章.之前垂直爬虫写了一年多,webmagic框架写了一个多月,这方 ... 
- JAVA爬虫挖取CSDN博客文章
		开门见山,看看这个教程的主要任务,就去csdn博客,挖取技术文章,我以<第一行代码–安卓>的作者为例,将他在csdn发表的额博客信息都挖取出来.因为郭神是我在大学期间比较崇拜的对象之一.他 ... 
- 推荐几个优秀的java爬虫项目
		java爬虫项目 大型的: Nutch apache/nutch · GitHub 适合做搜索引擎,分布式爬虫是其中一个功能. Heritrix internetarchive/heritrix3 ... 
- Java爬虫搜索原理实现
		permike 原文 Java爬虫搜索原理实现 没事做,又研究了一下爬虫搜索,两三天时间总算是把原理闹的差不多了,基本实现了爬虫搜索的原理,本次实现还是俩程序,分别是按广度优先和深度优先完成的,广度优 ... 
随机推荐
- Local Database Sample Model
			[Table] public class AddTableNameHere : INotifyPropertyChanged, INotifyPropertyChanging { // // TODO ... 
- preventDefault()方法
			该方法将通知 Web 浏览器不要执行与事件关联的默认动作(如果存在这样的动作). 例如,如果 type 属性是 "submit",在事件传播的任意阶段可以调用任意的事件句柄,通过调 ... 
- 数位DP HDU2089
			不要62 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ... 
- Web前端开发基础 第四课(颜色值)
			颜色值 在网页中的颜色设置是非常重要,有字体颜色(color).背景颜色(background-color).边框颜色(border)等,设置颜色的方法也有很多种: 1.英文命令颜色 前面几个小节中经 ... 
- PHP 上传大文件
- A trip through the Graphics Pipeline 2011_07_Z/Stencil processing, 3 different ways
			In this installment, I’ll be talking about the (early) Z pipeline and how it interacts with rasteriz ... 
- C语言输入多组问题~ungetc回退字符到stdin
			题目描述 输入数组长度 n 输入数组 a[1...n] 输入查找个数m 输入查找数字b[1...m] 输出 YES or NO 查找有则YES 否则NO . 输入描述: 输入有多组数据 ... 
- 关于mac下面用Parallels装ubuntu时分辨率问题[已解决]
			最近由于要深入下Android系统,在Parallels虚拟机上安装了ubuntu系统,刚开始安装成功的时候,分辨率只有800*600.本来想着去设置里面改动呢,可是坑爹的是设置里面只有800*600 ... 
- VC 菜单前的勾的切换
			if (pMenu->GetSubMenu(2)->GetMenuState(ID_STOP_SPOT_OP_MOSUE,MF_BYCOMMAND) == MF_UNCHECKED) { ... 
- Spark在Yarn上运行Wordcount程序
			前提条件 1.CDH安装spark服务 2.下载IntelliJ IDEA编写WorkCount程序 3.上传到spark集群执行 一.下载IntellJ IDEA编写Java程序 1.下载IDEA ... 
