南航计网课设——基于Hadoop的网络爬虫技术

本文详述了一位作者使用Java实现的分布式网络爬虫,该爬虫针对CSDN社区进行数据抓取和搜索。实验涉及Hadoop伪分布式环境搭建、正则表达式、HTML解析、MapReduce和Lucene中文分词。作者通过广度优先算法爬取网页,利用HDFS存储数据,并构建倒排索引进行搜索。过程中,作者分享了遇到的挑战和学习体会,表达了对分布式爬虫的浓厚兴趣。
摘要由CSDN通过智能技术生成

作者:shmily

实验概述

本实验使用java语言编程,实现了利用分布式爬虫对CSDN社区(http://www.csdn.com)的爬取和搜索。

实现搜索引擎的思路大致分为三步:一、从网上爬取数据;二、对拿到的数据进行整理即分词;三、通过关键字匹配拿到数据。

涉及到的关键技术有:Hadoop 伪分布式环境搭建、正则表达式匹配、HTML语言解析、MapReduce及Lucene中文分词。

环境搭建

这次实验是运行在Linux操作系统(CentOS)上的工程,并在其上搭建了hadoop集群。hadoop采用2.8.5版本,并在做好Master,之后直接用Virtual Box的复制功能复制三份虚拟机后,修改一下每个机器的ip地址,即可得到其他三台slave机器。分配ip地址如下:

192.168.56.101 hp-master

192.168.56.102 hp-slave1

192.168.56.103 hp-slave2

192.168.56.104 hp-slave3

ping一下其他三个slave,都已ping通:

在这里插入图片描述

查看http://192.168.168.101:50070,在datanode里可以看到已经启动的4给node

在这里插入图片描述
到这里hadoop的集群环境就已经搭建好了。

分布式网络爬虫的工作原理

分布式网络爬虫可以看做是多个集中式网络爬虫系统组合而成,运行于机器集群之上的,集群中每一个节点都是一个集中式爬虫,其工作原理与集中式爬虫系统的工作原理相同。这些集中式爬虫在分布式爬虫系统中是由一个主节点控制来协同工作的。由于分布式爬虫系统要求多个节点协同工作,这样多个节点需要相互通信来交互信息,所以搭建分布式爬虫系统的关键是网络通信。因为,分布式爬虫系统可以利用多个节点抓取网页,所以,分布式爬虫系统的效率远远高于集中式爬虫系统。

分布式爬虫系统的体系结构有很多种,工作方式和存储方式也很多。但是,典型的分布式爬虫系统都采取主从方式的体系结构。即有一个主节点控制所有从节点执行抓取任务,这个主节点负责分配URL,保证集群中所有节点的负载均衡。另外,关于存储方式,比较流行的是将抓取的网页保存在分布式文件系统上,这样管理多个节点上的数据更加方便。通常情况下使用的分布式文件系统是都是基于Hadoop的HDFS系统。

分布式爬虫系统的结构设计

本实验的整体框架图如下:
在这里插入图片描述

其功能可大致分为三部分:网络爬虫部分、倒排索引+中文分词部分和用户搜索模拟部分。

网络爬虫

爬虫部分的功能是下载网页数据,为搜索引擎部分提供数据来源。实验中以CSDN网站的URL作为种子URL。网络爬虫系统以种子集合作为初始URL,开始数据的抓取。因为网页中含有链接信息,通过已有网页的 URL会得到一些新的 URL,可以把网页之间的指向结构视为一棵树,种子URL对应的网页是树的根节点。这样,爬虫系统就可以根据广度优先算法或者深度优先算法遍历所有的网页。

由于深度优先搜索算法可能会使爬虫系统陷入一个网站内部,不利于搜索比较靠近网站首页的网页信息,因此本实验采用广度优先搜索算法采集网页。爬虫系统首先将种子URL放入下载队列,然后简单地从队首取出一个URL,解析DNS得到主机ip地址,下载其对应的网页。得到网页的内容将其存储后,再经过解析网页中的链接信息可以得到一些新的URL,将这些URL加入下载队列。然后再取出一个URL,对其对应的网页进行下载,然后再解析,如此反复进行,直到遍历了整个网络或满足某个条件才会停止下来。

在这里插入图片描述

以上面的图为例,遍历路径:A-B-C-D-E-F-G-H-I.

具体实现:

1.建立一个队列对象,首先将传入的url存入代表未爬取的队列中,循环未爬取队列中所有url进行爬取,并将爬取的url转移到代表已爬取的队列中。使用HttpURLConnection获得页面信息,使用正则表达式从页面信息中所需的信息输出到文件中,并将从页面信息中匹配到的超链接存入代表未爬取的队列中,实现垂直爬取数据。

2.通过模拟浏览器,去访问网站,如果返回的code为200,说明访问成功,就可以将这个网页的数据进行下载。

3.拿到爬取后的数据,即将网页转化成一个String的形式,存下来了。然后通过正则表达式,选取我们所需要的标签,这里取的是a标签,这里会对a标签进行过滤和分组,只取到有连接的,在写正则时写多个分组,有利于后面拿到,标题,跟对应的地址。

4.拿到标题跟地址后,将地址中的“/”等进行替换,因为后面要将地址作为文件的名字,标题作为内容存到HDFS中。

源码分析:(以注释的形式体现)

所用到的包:

在这里插入图片描述

一、LinkCollection,建立url的队列:

URL的一般语法格式为:protocol 😕/ hostname[:port] / path / [;parameters][?query]#fragment,本实验中protocol均为http协议。

package com.ls.spider;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

 /***当爬到一个超链接后,将其加入到队列中,接着爬这个超链接,并将这个超链接放入标示已查的队列中***/
public class LinkCollection {
   
    //待访问url的集合:队列
    private List<String> unVisitedUrls=Collections.synchronizedList(new ArrayList<String>());
    private Set<String> visitedUrls=Collections.synchronizedSet(new HashSet<String>());

 /**************入队操作***************/
    public void addUnVisitedUrl(String url){
   
        if(url!=null&&!"".equals(url.trim())&&!visitedUrls.contains(url)&&!unVisitedUrls.contains(url)){
   
            unVisitedUrls.add(url);
        }
    }
    
  /***************出队****************/
    public String deQueueUnVisitedUrl(){
   
        if(unVisitedUrls.size()>0){
   
            String url=unVisitedUrls.remove(0);
            visitedUrls.add(url);
            return url;
        }
        return null;
    }
    
   /**********判断队列是否为空************/
    public boolean isUnVisitedUrisEmpty(){
   
        if(unVisitedUrls!=null&&!"".equals(unVisitedUrls)){
   
            return false;
        }else{
   
            return true;
        }
    }
   
    /***********hadoop出队**********/
    public String deQueueVisitedUrl(){
   
        if(visitedUrls.iterator().hasNext()){
   
            String url=visitedUrls.iterator().next();
            visitedUrls.remove(0);
            return url;
        }
        return null;
    }

    /***********判断Visited队列是否为空**********/
    public boolean isVisitedUrisEmpty(){
   
        if(visitedUrls!=null&&!"".equals(visitedUrls)){
   
            return false;
        }else{
   
            return true;
        }
    }
}

二、DownLoadTool,下载页面

package com.ls.spider;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;  //发送请求到网页
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.Scanner;

/***************下载页面******************/
public class DownLoadTool {
   
    private static String encoding="GBK";
    //下载的文件保存的位置
    private String savePath=System.getProperty("user.dir")+File.separator;
    
    /******自动生成保存的目录目录名的命名规范:myproject******/
    public static File createSaveDirectory(){
   
        DateFormat df=new SimpleDateFormat("myproject");
        String directoryName=df.format(new Date());
        return createSaveDirectory(directoryName);
    }
    public static File createSaveDirectory(String directoryName) {
   
        File file=new File(directoryName);
        if(!file.exists()){
   
            file.mkdirs();
        }
        return file;
    }
    
     /***************下载页面的内容**************/
        static String downLoadUrl(String addr){
   
            StringBuffer sb=new StringBuffer();
            try {
   
                URL url=new URL(addr);
                HttpURLConnection con=(HttpURLConnection) url.openConnection();

                con.setConnectTimeout(5000);
                con.connect();
                //产生文件名
                Random r=new Random();
                try {
   
                    Thread.sleep(r.nextInt(2000));
                } catch (InterruptedException e) {
   
                    e.printStackTrace();
                }

                System.out.println(con.getResponseCode());
                System.out.println(con.getHeaderFields());
                if(con.getResponseCode()==200){
   
                    BufferedInputStream bis=new BufferedInputStream(con.getInputStream());
                    Scanner sc=new Scanner(bis,encoding);
                        while(sc.<
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值