配色: 字号:
教你如何编写简单的网络爬虫
2016-10-08 | 阅:  转:  |  分享 
  
教你如何编写简单的网络爬虫

实际的爬虫是从一系列的种子链接开始。种子链接是起始节点,种子页面的超链接指向的页面是子节点(中间节点),对于非html文档,如excel等,不能从中提取超链接,看做图的终端节点

一、网络爬虫的基本知识

网络爬虫通过遍历互联网络,把网络中的相关网页全部抓取过来,这体现了爬的概念。爬虫如何遍历网络呢,互联网可以看做是一张大图,每个页面看做其中的一个节点,页面的连接看做是有向边。图的遍历方式分为宽度遍历和深度遍历,但是深度遍历可能会在深度上过深的遍历或者陷入黑洞。所以,大多数爬虫不采用这种形式。另一方面,爬虫在按照宽度优先遍历的方式时候,会给待遍历的网页赋予一定优先级,这种叫做带偏好的遍历。

实际的爬虫是从一系列的种子链接开始。种子链接是起始节点,种子页面的超链接指向的页面是子节点(中间节点),对于非html文档,如excel等,不能从中提取超链接,看做图的终端节点。整个遍历过程中维护一张visited表,记录哪些节点(链接)已经处理过了,跳过不作处理。

使用宽度优先搜索策略,主要原因有:

a、重要的网页一般离种子比较近,例如我们打开的新闻网站时候,往往是最热门的新闻,随着深入冲浪,网页的重要性越来越低。

b、万维网实际深度最多达17层,但到达某个网页总存在一条很短路径,而宽度优先遍历可以最快的速度找到这个网页

c、宽度优先有利于多爬虫合作抓取。

二、网络爬虫的简单实现

1、定义已访问队列,待访问队列和爬取得URL的哈希表,包括出队列,入队列,判断队列是否空等操作

复制代码代码如下:

packagewebspider;importjava.util.HashSet;importjava.util.PriorityQueue;importjava.util.Set;importjava.util.Queue;

publicclassLinkQueue{//已访问的url集合privatestaticSetvisitedUrl=newHashSet();//待访问的url集合privatestaticQueueunVisitedUrl=newPriorityQueue();

//获得URL队列publicstaticQueuegetUnVisitedUrl(){returnunVisitedUrl;}

//添加到访问过的URL队列中publicstaticvoidaddVisitedUrl(Stringurl){visitedUrl.add(url);}

//移除访问过的URLpublicstaticvoidremoveVisitedUrl(Stringurl){visitedUrl.remove(url);}

//未访问的URL出队列publicstaticObjectunVisitedUrlDeQueue(){returnunVisitedUrl.poll();}

//保证每个url只被访问一次publicstaticvoidaddUnvisitedUrl(Stringurl){if(url!=null&&!url.trim().equals("")&&!visitedUrl.contains(url)&&!unVisitedUrl.contains(url))unVisitedUrl.add(url);}

//获得已经访问的URL数目publicstaticintgetVisitedUrlNum(){returnvisitedUrl.size();}

//判断未访问的URL队列中是否为空publicstaticbooleanunVisitedUrlsEmpty(){returnunVisitedUrl.isEmpty();}

}

2、定义DownLoadFile类,根据得到的url,爬取网页内容,下载到本地保存。此处需要引用commons-httpclient.jar,commons-codec.jar,commons-logging.jar。

复制代码代码如下:

packagewebspider;

importjava.io.DataOutputStream;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importorg.apache.commons.httpclient.DefaultHttpMethodRetryHandler;importorg.apache.commons.httpclient.HttpClient;importorg.apache.commons.httpclient.HttpException;importorg.apache.commons.httpclient.HttpStatus;importorg.apache.commons.httpclient.methods.GetMethod;importorg.apache.commons.httpclient.params.HttpMethodParams;

publicclassDownLoadFile{/根据url和网页类型生成需要保存的网页的文件名去除掉url中非文件名字符/publicStringgetFileNameByUrl(Stringurl,StringcontentType){//removehttp://url=url.substring(7);//text/html类型if(contentType.indexOf("html")!=-1){url=url.replaceAll("[\\?/:|<>\"]","_")+".html";returnurl;}//如application/pdf类型else{returnurl.replaceAll("[\\?/:|<>\"]","_")+"."+contentType.substring(contentType.lastIndexOf("/")+1);}}

/保存网页字节数组到本地文件filePath为要保存的文件的相对地址/privatevoidsaveToLocal(byte[]data,StringfilePath){try{DataOutputStreamout=newDataOutputStream(newFileOutputStream(newFile(filePath)));for(inti=0;i
/下载url指向的网页/publicStringdownloadFile(Stringurl){StringfilePath=null;/1.生成HttpClinet对象并设置参数/HttpClienthttpClient=newHttpClient();//设置Http连接超时5shttpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);

/2.生成GetMethod对象并设置参数/GetMethodgetMethod=newGetMethod(url);//设置get请求超时5sgetMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT,5000);//设置请求重试处理getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,newDefaultHttpMethodRetryHandler());

/3.执行HTTPGET请求/try{intstatusCode=httpClient.executeMethod(getMethod);//判断访问的状态码if(statusCode!=HttpStatus.SC_OK){System.err.println("Methodfailed:"+getMethod.getStatusLine());filePath=null;}

/4.处理HTTP响应内容/byte[]responseBody=getMethod.getResponseBody();//读取为字节数组//根据网页url生成保存时的文件名filePath="f:\\spider\\"+getFileNameByUrl(url,getMethod.getResponseHeader("Content-Type").getValue());saveToLocal(responseBody,filePath);}catch(HttpExceptione){//发生致命的异常,可能是协议不对或者返回的内容有问题System.out.println("Pleasecheckyourprovidedhttpaddress!");e.printStackTrace();}catch(IOExceptione){//发生网络异常e.printStackTrace();}finally{//释放连接getMethod.releaseConnection();}returnfilePath;}}

3、定义HtmlParserTool类,用来获得网页中的超链接(包括a标签,frame中的src等等),即为了得到子节点的URL。需要引入htmlparser.jar

复制代码代码如下:

packagewebspider;

importjava.util.HashSet;importjava.util.Set;importorg.htmlparser.Node;importorg.htmlparser.NodeFilter;importorg.htmlparser.Parser;importorg.htmlparser.filters.NodeClassFilter;importorg.htmlparser.filters.OrFilter;importorg.htmlparser.tags.LinkTag;importorg.htmlparser.util.NodeList;importorg.htmlparser.util.ParserException;

publicclassHtmlParserTool{//获取一个网站上的链接,filter用来过滤链接publicstaticSetextracLinks(Stringurl,LinkFilterfilter){

Setlinks=newHashSet();try{Parserparser=newParser(url);//parser.setEncoding("utf-8");//过滤标签的filter,用来提取frame标签里的src属性所表示的链接NodeFilterframeFilter=newNodeFilter(www.hunanwang.net){publicbooleanaccept(Nodenode){if(node.getText().startsWith("framesrc=")){returntrue;}else{returnfalse;}}};//OrFilter来设置过滤标签,和标签OrFilterlinkFilter=newOrFilter(newNodeClassFilter(LinkTag.class),frameFilter);//得到所有经过过滤的标签NodeListlist=parser.extractAllNodesThatMatch(linkFilter);for(inti=0;i标签{LinkTaglink=(LinkTag)tag;StringlinkUrl=link.getLink();//urlif(filter.accept(linkUrl))links.add(linkUrl);}else//标签{//提取frame里src属性的链接如Stringframe=tag.getText();intstart=frame.indexOf("src=");frame=frame.substring(start);intend=frame.indexOf("www.visa158.com");if(end==-1)end=frame.indexOf(">");StringframeUrl=frame.substring(5,end-1);if(filter.accept(frameUrl))links.add(frameUrl);}}}catch(ParserExceptione){e.printStackTrace();}returnlinks;}}

4、编写测试类MyCrawler,用来测试爬取效果

复制代码代码如下:

packagewebspider;

importjava.util.Set;

publicclassMyCrawler{/使用种子初始化URL队列@return@paramseeds种子URL/privatevoidinitCrawlerWithSeeds(String[]seeds){for(inti=0;i
/抓取过程@return@paramseeds/publicvoidcrawling(String[]seeds){//定义过滤器,提取以http://www.lietu.com开头的链接LinkFilterfilter=newLinkFilter(){publicbooleanaccept(Stringurl){if(url.startsWith("http://www.baidu.com"))returntrue;elsereturnfalse;}};//初始化URL队列initCrawlerWithSeeds(seeds);//循环条件:待抓取的链接不空且抓取的网页不多于1000while(!LinkQueue.unVisitedUrlsEmpty()&&LinkQueue.getVisitedUrlNum()<=1000){//队头URL出队列StringvisitUrl=(String)LinkQueue.unVisitedUrlDeQueue();if(visitUrl==null)continue;DownLoadFiledownLoader=newDownLoadFile();//下载网页downLoader.downloadFile(visitUrl);//该url放入到已访问的URL中LinkQueue.addVisitedUrl(visitUrl);//提取出下载网页中的URLSetlinks=HtmlParserTool.extracLinks(visitUrl,filter);//新的未访问的URL入队for(Stringlink:links){LinkQueue.addUnvisitedUrl(link);}}}

//main方法入口publicstaticvoidmain(String[]args){MyCrawlercrawler=newMyCrawler();crawler.crawling(newString[]{"http://www.baidu.com"});}

}

至此,可以看到f:\spider文件夹下面已经出现了很多html文件,都是关于百度的,以“www.baidu.com”为开头。























献花(0)
+1
(本文系白狐一梦首藏)