java从网页抓取数据(网络编程众多基础包和类如何实现一个)

优采云 发布时间: 2022-03-29 13:18

  java从网页抓取数据(网络编程众多基础包和类如何实现一个)

  首先,我们应该解释一下使用Java语言而不是C/C++等其他语言的原因,因为Java提供了很多网络编程的基础包和类,比如URL类、InetAddress类、正则表达式等。这是我们的搜索引擎。这些实现为专注于搜索引擎本身的实现提供了良好的基础,而不会因这些基础类的实现而分心。

  这个由三部分组成的系列将逐步解释如何设计和实现搜索引擎。第一部分先学习搜索引擎的工作原理,同时了解它的架构,然后讲解如何实现搜索引擎的第一部分,网络爬虫模块,完成网页采集功能。系列的第二部分将介绍预处理模块,即如何对采集到的网页进行处理,排序、分词和索引都收录在这一部分中。系列的第三部分会介绍信息查询服务的实现,主要是查询接口的建立、查询结果的返回和快照的实现。

  dySE的整体结构

  在开始学习搜索引擎的模块实现之前,需要了解dySE的整体结构和数据传输的流程。实际上,搜索引擎的三部分是相互独立的,三部分是分开工作的。主要关系是前一部分得到的数据结果为后一部分提供了原创数据。三者的关系如下图所示:

  图1. 搜索引擎三阶段工作流程

  

  在介绍搜索引擎的整体结构之前,我们参考了《计算机网络——一种自顶向下的方法来描述互联网的特征》一书的叙述方式,从普通的角度来介绍搜索引擎的具体工作流程。使用搜索引擎的用户。

  自上而下的方法描述了搜索引擎的执行过程:

  用户通过浏览器提交查询词或词组P,搜索引擎根据用户查询返回匹配网页信息列表L;

  上述过程涉及到两个问题:如何匹配用户的查询,网页信息列表来自哪里,排名依据是什么?啊等),根据系统维护的倒排索引,可以查询到某个词pi出现在了哪些网页中,与出现的网页匹配的网页集合可以作为初始结果。再进一步,计算返回的初始网页集合与查询词的相关度,得到页面排名,即Page Rank,根据页面的排名顺序可以得到最终的页面列表;

  假设建立了分词器和网页排名的计算公式,那么倒排索引和原创网页集从哪里来?它存储在本地,倒排索引,即词组到网页的映射表,是建立在正向索引的基础上的,前向索引是对网页内容进行分析并对其内容进行切分后得到的网页到词组。映射表,倒排索引可以通过正向索引倒置得到;

  网页的分析究竟是做什么的?由于爬虫采集到的原创网页收录大量信息,例如html表单和一些广告等垃圾信息,网页分析将这些信息去除,提取文本信息作为后续基础数据。

  经过以上分析,我们可以得到搜索引擎的整体结构如下图:

  图2.搜索引擎整体结构

  

  爬虫从互联网上抓取很多网页,并作为原创网页库存储在本地,然后网页分析器将网页中的主题内容提取出来,交给分词器进行分词。获得索引数据库。用户查询时,通过分词器对输入的查询词组进行切割,通过检索器对索引数据库进行查询,将得到的结果返回给用户。

  不管一个搜索引擎有多大,它的主要结构都是由这些部分组成的,并没有太大的区别。一个搜索引擎的好坏主要取决于各个部分的内部实现。

  有了上面对搜索引擎的整体了解,下面我们来了解一下dySE中爬虫模块的具体设计和实现。

  蜘蛛的设计

  网页采集的过程就像遍历一个图,其中网页作为图中的节点,网页中的超链接作为图中的边。通过网页的超链接可以获取其他网页的地址,从而可以进行进一步的网页采集。; 图遍历分为广度优先和深度优先方法,网页的采集过程也是如此。综上所述,蜘蛛采集网页的过程如下:从初始URL集合中获取目标网页地址,通过网络连接接收网页数据,将获取的网页数据加入网页库,分析其他网页中的 URL 链接,放在未访问的 URL 集合中,用于网页采集。下图表示此过程:

  图3. 蜘蛛工作流

  

  Spider的具体实现

  网络采集器采集

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

  列表1.网页抓取

  网址 url=newURL("http://");

  URLConnection conn=url.openConnection();

  BufferedReader reader=newBufferedReader(newInputStreamReader(conn.getInputStream()));

  字符串=空;

  而((line=reader.readLine()) !=null)

  document.append(line+"\n");

  使用Java语言的好处是不需要自己去处理底层的连接操作。喜欢或精通Java网络编程的读者,不用上述方法也能实现URL类及相关操作,也是一个很好的练习。

  网页处理

  采集到的单个网页需要以两种不同的方式进行处理。一是将其作为原创数据放入网页库中进行后续处理;另一种是解析后提取URL连接,放入URL池等待对应的网页。采集。

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

  网页库由多条记录组成,每条记录收录一条网页数据信息,记录存储以便添加;

  一条记录由数据头、数据和空行组成,顺序为:表头+空行+数据+空行;

  头部由几个属性组成,包括:版本号、日期、IP地址、数据长度,以属性名和属性值的方式排列,中间加一个冒号,每个属性占一行;

  数据是网页数据。

  需要注意的是,之所以加上数据采集日期,是因为很多网站的内容是动态变化的,比如一些大型门户网站的首页内容网站,也就是说如果不爬取同日 对于网页数据,很可能会出现数据过期的问题,所以需要添加日期信息来识别。

  URL的提取分为两步。第一步是识别URL,第二步是组织URL。这两个步骤主要是因为 网站 的一些链接使用了相对路径。如果它们没有排序,就会出现错误。. URL的标识主要是通过正则表达式来匹配的。该过程首先将一个字符串设置为匹配字符串模式,然后在Pattern中编译后使用Matcher类匹配对应的字符串。实现代码如下:

  列表2. URL 识别

  publicArrayListurlDetector(StringhtmlDoc){

  finalStringpatternString="]*\\s*>)";

  模式 pattern=pile(patternString,Pattern.CASE_INSENSITIVE);

  ArrayListallURLs=newArrayList();

  匹配器 matcher=pattern.matcher(htmlDoc);

  字符串临时网址;

  //第一次匹配的url是这样的形式:

  //为此,需要下一步提取真实的url,

  //可以记录前两个"之间的部分来获取url

  同时(matcher.find()){

  尝试 {

  tempURL=matcher.group();

  tempURL=tempURL.substring(tempURL.indexOf("\"")+1);

  if(!tempURL.contains("\""))

  继续;

  tempURL=tempURL.substring(0, tempURL.indexOf("\""));

  } 捕捉(MalformedURLException e){

  e.printStackTrace();

  }

  }

  返回所有网址;

  }

  根据正则表达式“]*\\s*>)”可以匹配到URL所在的整个标签,形式为“”,所以循环获取整个标签后,我们需要进一步提取真实网址。我们可以通过截取标签前两个引号之间的内容来得到这个内容。在此之后,我们可以得到属于该网页的一组初步 URL。

  接下来我们进行第二步,URL的排序,也就是对之前获取的整个页面中的URL集合进行过滤和整合。集成主要针对网页地址为相对链接的部分。由于我们可以很方便的获取当前网页的URL,所以相对链接只需要在当前网页的URL上加上一个相对链接字段就可以形成一个完整的URL,从而完成整合。另一方面,在页面所收录的综合URL中,也有一些我们不想抓取或者不重要的网页,比如广告网页。这里我们主要关注页面中广告的简单处理。一般网站的广告链接都有相应的展示表达方式。例如,当链接收录诸如“

  完成这两步之后,就可以将采集到的网页URL放入URL池中,然后我们来处理爬虫URL的分配。

  调度员调度员

  分配器管理URL,负责保存URL池,在Gather拿到某个网页后调度新的URL,同时也避免了网页的重复采集。分配器在设计模式中以单例模式编码,负责提供新的 URL 给 Gather。因为涉及到多线程重写,所以单例模式尤为重要。

  重复采集是指物理上存在的网页,被Gather重复访问而不更新,造成资源浪费。因此,Dispatcher 维护两个列表,“已访问表”和“未访问表”。爬取每个URL对应的页面后,将URL放入visited表,将页面提取的URL放入unvisited表;当 Gather 从 Dispatcher 请求一个 URL 时,它首先验证 URL 是否在 Visited 表中,然后再给 Gather 工作。

  Spider 启动多个 Gather 线程

  现在互联网上的网页数以亿计,通过单一的Gather来采集网页显然是低效的,所以我们需要使用多线程的方式来提高效率。Gather的功能是采集网页,我们可以通过Spider类开启多个Gather线程,从而达到多线程的目的。代码显示如下:

  /**

  * 开始线程采集,然后开始采集网页数据

  */

  公共无效开始(){

  调度程序 disp=newDispatcher.getInstance();

  for(inti=0; 我

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线