关闭

关闭

封号提示

内容

首页 自己动手写网络爬虫.pdf

自己动手写网络爬虫.pdf

自己动手写网络爬虫.pdf

上传者: 小田 2012-12-30 评分1 评论1 下载666 收藏0 阅读量1388 暂无简介 简介 举报

简介:本文档为《自己动手写网络爬虫pdf》,可适用于IT/计算机领域,主题内容包含第篇自己动手抓取数据第章全面剖析网络爬虫你知道百度、Google是如何获取数以亿计的网页并且实时更新的吗?你知道在搜索引擎领域人们常说的Spider符等。

第篇自己动手抓取数据第章全面剖析网络爬虫你知道百度、Google是如何获取数以亿计的网页并且实时更新的吗?你知道在搜索引擎领域人们常说的Spider是什么吗?本章将全面介绍网络爬虫的方方面面。读完之后你将完全有能力自己写一个网络爬虫随意抓取互联网上任何感兴趣的东西。既然百度、Google这些搜索引擎巨头已经帮我们抓取了互联网上的大部分信息为什么还要自己写爬虫呢?因为深入整合信息的需求是广泛存在的。在企业中爬虫抓取下来的信息可以作为数据仓库多维展现的数据源也可以作为数据挖掘的来源。甚至有人为了炒股专门抓取股票信息。既然从美国中情局到普通老百姓都需要那还等什么让我们快开始吧。抓取网页网络爬虫的基本操作是抓取网页。那么如何才能随心所欲地获得自己想要的页面?这一节将从URL开始讲起然后告诉大家如何抓取网页并给出一个使用Java语言抓取网页的例子。最后要讲一讲抓取过程中的一个重要问题:如何处理HTTP状态码。深入理解URL抓取网页的过程其实和读者平时使用IE浏览器浏览网页的道理是一样的。比如你打开一个浏览器输入猎兔搜索网站的地址如图所示。图使用浏览器浏览网页“打开”网页的过程其实就是浏览器作为一个浏览的“客户端”向服务器端发送了一次请求把服务器端的文件“抓”到本地再进行解释、展现。更进一步可以通过浏览器端查看“抓取”过来的文件源代码。选择“查看”|“源文件”命令就会出现从服务器上“抓取”下来的文件的源代码如图所示。在上面的例子中我们在浏览器的地址栏中输入的字符串叫做URL。那么什么是URL呢?直观地讲URL就是在浏览器端输入的http:wwwlietucom这个字符串。下面我们深入介绍有关URL的知识。在理解URL之前首先要理解URI的概念。什么是URI?Web上每种可用的资源如HTML文档、图像、视频片段、程序等都由一个通用资源标志符(UniversalResourceIdentifierURI)进行定位。URI通常由三部分组成:访问资源的命名机制存放资源的主机名资源自身的名称由路径表示。如下面的URI:http:wwwwebmonkeycomcnhtmlhtml第章全面剖析网络爬虫图浏览器端源代码我们可以这样解释它:这是一个可以通过HTTP协议访问的资源位于主机wwwwebmonkeycomcn上通过路径“htmlhtml”访问。URL是URI的一个子集。它是UniformResourceLocator的缩写译为“统一资源定位符”。通俗地说URL是Internet上描述信息资源的字符串主要用在各种WWW客户程序和服务器程序上特别是著名的Mosaic。采用URL可以用一种统一的格式来描述各种信息资源包括文件、服务器的地址和目录等。URL的格式由三部分组成:第一部分是协议(或称为服务方式)。第二部分是存有该资源的主机IP地址(有时也包括端口号)。第三部分是主机资源的具体地址如目录和文件名等。第一部分和第二部分用“:”符号隔开第二部分和第三部分用“”符号隔开。第一部分和第二部分是不可缺少的第三部分有时可以省略。根据URL的定义我们给出了常用的两种URL协议的例子供大家参考。.HTTP协议的URL示例使用超级文本传输协议HTTP提供超级文本信息服务的资源。例:http:wwwpeopledailycomcnchannelwelcomehtm其计算机域名为wwwpeopledailycomcn。超级文本文件(文件类型为html)是在目录channel下的welcomehtm。这是中国人民日报的一台计算机。例:http:wwwrolcnnettalktalkhtm其计算机域名为wwwrolcnnet。超级文本文件(文件类型为html)是在目录talk下的talkhtm。这是瑞得聊天室的地址可由此进入瑞得聊天室的第室。.文件的URL用URL表示文件时服务器方式用file表示后面要有主机IP地址、文件的存取路径(即目录)和文件名等信息。有时可以省略目录和文件名但“”符号不能省略。例:file:ftpyoyodynecompubfilesfoobartxt上面这个URL代表存放在主机ftpyoyodynecom上的pubfiles目录下的一个文件文件名是foobartxt。例:file:ftpyoyodynecompub代表主机ftpyoyodynecom上的目录pub。例:file:ftpyoyodynecom代表主机ftpyoyodynecom的根目录。爬虫最主要的处理对象就是URL它根据URL地址取得所需要的文件内容然后对它进行进一步的处理。因此准确地理解URL对理解网络爬虫至关重要。从下一节开始我们将详细地讲述如何根据URL地址来获得网页内容。通过指定的URL抓取网页内容上一节详细介绍了URL的构成这一节主要阐述如何根据给定的URL来抓取网页。所谓网页抓取就是把URL地址中指定的网络资源从网络流中读取出来保存到本地。类似于使用程序模拟IE浏览器的功能把URL作为HTTP请求的内容发送到服务器端然后读取服务器端的响应资源。Java语言是为网络而生的编程语言它把网络资源看成是一种文件它对网络资源的访问和对本地文件的访问一样方便。它把请求和响应封装为流。因此我们可以根据相应内容获得响应流之后从流中按字节读取数据。例如javanetURL类可以对相应的Web服务器发出请求并且获得响应文档。javanetURL类有一个默认的构造函数使用URL地址作为参数构造URL对象:URLpageURL=newURL(path)接着可以通过获得的URL对象来取得网络流进而像操作本地文件一样来操作网络资源:InputStreamstream=pageURLopenStream()在实际的项目中网络环境比较复杂因此只用javanet包中的API来模拟IE客户端的工作代码量非常大。需要处理HTTP返回的状态码设置HTTP代理处理HTTPS协议等工作。为了便于应用程序的开发实际开发时常常使用Apache的HTTP客户端开源项目HttpClient。它完全能够处理HTTP连接中的各种问题使用起来非常方便。只需在项目中引入HttpClientjar包就可以模拟IE来获取网页内容。例如:创建一个客户端类似于打开一个浏览器HttpClienthttpclient=newHttpClient()第章全面剖析网络爬虫创建一个get方法类似于在浏览器地址栏中输入一个地址GetMethodgetMethod=newGetMethod("http:wwwblablablacom")回车获得响应状态码intstatusCode=httpclientexecuteMethod(getMethod)查看命中情况可以获得的东西还有很多比如head、cookies等Systemoutprintln("response="getMethodgetResponseBodyAsString())释放getMethodreleaseConnection()上面的示例代码是使用HttpClient进行请求与响应的例子。第一行表示创建一个客户端相当于打开浏览器。第二行使用get方式对http:wwwblablablacom进行请求。第三行执行请求获取响应状态。第四行的getMethodgetResponseBodyAsString()方法能够以字符串方式获取返回的内容。这也是网页抓取所需要的内容。在这个示例中只是简单地把返回的内容打印出来而在实际项目中通常需要把返回的内容写入本地文件并保存。最后还要关闭网络连接以免造成资源消耗。这个例子是用get方式来访问Web资源。通常get请求方式把需要传递给服务器的参数作为URL的一部分传递给服务器。但是HTTP协议本身对URL字符串长度有所限制。因此不能传递过多的参数给服务器。为了避免这种问题通常情况下采用post方法进行HTTP请求HttpClient包对post方法也有很好的支持。例如:得到post方法PostMethodPostMethod=newPostMethod("http:wwwsaybotcompostme")使用数组来传递参数NameValuePairpostData=newNameValuePair设置参数postData=newNameValuePair("武器","枪")postData=newNameValuePair("什么枪","神枪")postMethodaddParameters(postData)回车获得响应状态码intstatusCode=httpclientexecuteMethod(getMethod)查看命中情况可以获得的东西还有很多比如head、cookies等Systemoutprintln("response="getMethodgetResponseBodyAsString())释放getMethodreleaseConnection()上面的例子说明了如何使用post方法来访问Web资源。与get方法不同post方法可以使用NameValuePair来设置参数因此可以设置“无限”多的参数。而get方法采用把参数写在URL里面的方式由于URL有长度限制因此传递参数的长度会有限制。有时我们执行爬虫程序的机器不能直接访问Web资源而是需要通过HTTP代理服务器去访问HttpClient对代理服务器也有很好的支持。如:创建HttpClient相当于打开一个代理HttpClienthttpClient=newHttpClient()设置代理服务器的IP地址和端口httpClientgetHostConfiguration()setProxy("",)告诉httpClient使用抢先认证否则你会收到“你没有资格”的恶果httpClientgetParams()setAuthenticationPreemptive(true)MyProxyCredentialsProvder返回代理的credential(usernamepassword)httpClientgetParams()setParameter(CredentialsProviderPROVIDER,newMyProxyCredentialsProvider())设置代理服务器的用户名和密码httpClientgetState()setProxyCredentials(newAuthScope("",AuthScopeANYPORT,AuthScopeANYREALM),newUsernamePasswordCredentials("username","password"))上面的例子详细解释了如何使用HttpClient设置代理服务器。如果你所在的局域网访问Web资源需要代理服务器的话你可以参照上面的代码设置。这一节我们介绍了使用HttpClient抓取网页的内容之后我们将给出一个详细的例子来说明如何获取网页。Java网页抓取示例在这一节中我们根据之前讲过的内容写一个实际的网页抓取的例子。这个例子把上一节讲的内容做了一定的总结代码如下:publicclassRetrivePage{privatestaticHttpClienthttpClient=newHttpClient()设置代理服务器static{设置代理服务器的IP地址和端口httpClientgetHostConfiguration()setProxy("",)}publicstaticbooleandownloadPage(Stringpath)throwsHttpException,IOException{InputStreaminput=OutputStreamoutput=得到post方法PostMethodpostMethod=newPostMethod(path)设置post方法的参数NameValuePairpostData=newNameValuePairpostData=newNameValuePair("name","lietu")postData=new第章全面剖析网络爬虫NameValuePair("password","*****")postMethodaddParameters(postData)执行返回状态码intstatusCode=httpClientexecuteMethod(postMethod)针对状态码进行处理(简单起见只处理返回值为的状态码)if(statusCode==HttpStatusSCOK){input=postMethodgetResponseBodyAsStream()得到文件名Stringfilename=pathsubstring(pathlastIndexOf(''))获得文件输出流output=newFileOutputStream(filename)输出到文件inttempByte=while((tempByte=inputread())>){outputwrite(tempByte)}关闭输入输出流if(input!=){inputclose()}if(output!=){outputclose()}returntrue}returnfalse}***测试代码*publicstaticvoidmain(Stringargs){抓取lietu首页输出try{RetrivePagedownloadPage("http:wwwlietucom")}catch(HttpExceptione){TODOAutogeneratedcatchblockeprintStackTrace()}catch(IOExceptione){TODOAutogeneratedcatchblockeprintStackTrace()}}}上面的例子是抓取猎兔搜索主页的示例。它是一个比较简单的网页抓取示例由于互联网的复杂性真正的网页抓取程序会考虑非常多的问题。比如资源名的问题资源类型的问题状态码的问题。而其中最重要的就是针对各种返回的状态码的处理。下一节将重点介绍处理状态码的问题。处理HTTP状态码上一节介绍HttpClient访问Web资源的时候涉及HTTP状态码。比如下面这条语句:intstatusCode=httpClientexecuteMethod(getMethod)回车获得响应状态码HTTP状态码表示HTTP协议所返回的响应的状态。比如客户端向服务器发送请求如果成功地获得请求的资源则返回的状态码为表示响应成功。如果请求的资源不存在则通常返回错误。HTTP状态码通常分为种类型分别以~五个数字开头由位整数组成。XX通常用作实验用途。这一节主要介绍XX、XX、XX、XX等常用的几种状态码如表所示。表HTTP常用状态码状态代码代码描述处理方式请求成功获得响应的内容进行处理请求完成结果是创建了新资源。新创建资源的URI可在响应的实体中得到爬虫中不会遇到请求被接受但处理尚未完成阻塞等待服务器端已经实现了请求但是没有返回新的信息。如果客户是用户代理则无须为此更新自身的文档视图丢弃该状态码不被HTTP的应用程序直接使用只是作为XX类型回应的默认解释。存在多个可用的被请求资源若程序中能够处理则进行进一步处理如果程序中不能处理则丢弃请求到的资源都会分配一个永久的URL这样就可以在将来通过该URL来访问此资源重定向到分配的URL请求到的资源在一个不同的URL处临时保存重定向到临时的URL请求的资源未更新丢弃非法请求丢弃未授权丢弃禁止丢弃没有找到丢弃XX回应代码以“”开头的状态码表示服务器端发现自己出现错误不能继续执行请求丢弃当返回的状态码为XX时表示应用服务器出现错误采用简单的丢弃处理就可以解决。第章全面剖析网络爬虫当返回值状态码为XX时通常进行转向以下是转向的代码片段读者可以和上一节的代码自行整合到一起:若需要转向则进行转向操作if((statusCode==HttpStatusSCMOVEDTEMPORARILY)||(statusCode==HttpStatusSCMOVEDPERMANENTLY)||(statusCode==HttpStatusSCSEEOTHER)||(statusCode==HttpStatusSCTEMPORARYREDIRECT)){读取新的URL地址Headerheader=postMethodgetResponseHeader("location")if(header!=){StringnewUrl=headergetValue()if(newUrl==||newUrlequals("")){newUrl=""使用post转向PostMethodredirect=newPostMethod(newUrl)发送请求做进一步处理……}}}当响应状态码为XX时根据表的描述我们只需要处理和两种状态码其他的返回值可以不做进一步处理。的返回状态码是成功状态码可以直接进行网页抓取例如:处理返回值为的状态码if(statusCode==HttpStatusSCOK){input=postMethodgetResponseBodyAsStream()得到文件名Stringfilename=pathsubstring(pathlastIndexOf(''))获得文件输出流output=newFileOutputStream(filename)输出到文件inttempByte=while((tempByte=inputread())>){outputwrite(tempByte)}}的响应状态码表示请求已经接受服务器再做进一步处理。宽度优先爬虫和带偏好的爬虫节介绍了如何获取单个网页内容。在实际项目中则使用爬虫程序遍历互联网把网络中相关的网页全部抓取过来这也体现了爬虫程序“爬”的概念。爬虫程序是如何遍历互联网把网页全部抓取下来的呢?互联网可以看成一个超级大的“图”而每个页面可以看作是一个“节点”。页面中的链接可以看成是图的“有向边”。因此能够通过图的遍历的方式对互联网这个超级大“图”进行访问。图的遍历通常可分为宽度优先遍历和深度优先遍历两种方式。但是深度优先遍历可能会在深度上过“深”地遍历或者陷入“黑洞”大多数爬虫都不采用这种方式。另一方面在爬取的时候有时候也不能完全按照宽度优先遍历的方式而是给待遍历的网页赋予一定的优先级根据这个优先级进行遍历这种方法称为带偏好的遍历。本小节会分别介绍宽度优先遍历和带偏好的遍历。图的宽度优先遍历下面先来看看图的宽度优先遍历过程。图的宽度优先遍历(BFS)算法是一个分层搜索的过程和树的层序遍历算法相同。在图中选中一个节点作为起始节点然后按照层次遍历的方式一层一层地进行访问。图的宽度优先遍历需要一个队列作为保存当前节点的子节点的数据结构。具体的算法如下所示:()顶点V入队列。()当队列非空时继续执行否则算法为空。()出队列获得队头节点V访问顶点V并标记V已经被访问。()查找顶点V的第一个邻接顶点col。()若V的邻接顶点col未被访问过则col进队列。()继续查找V的其他邻接顶点col转到步骤()若V的所有邻接顶点都已经被访问过则转到步骤()。下面我们以图示的方式介绍宽度优先遍历的过程如图所示。GBACDFEIH图宽度优先遍历过程第章全面剖析网络爬虫选择A作为种子节点则宽度优先遍历的过程如表所示。表宽度优先遍历过程操作队列中的元素初始空A入队列AA出队列空BCDEF入队列BCDEFB出队列CDEFC出队列DEFD出队列EFE出队列FH入队列FHF出队列HG入队列HGH出队列GI入队列GIG出队列II出队列空在表所示的遍历过程中出队列的节点顺序既是图的宽度优先遍历的访问顺序。由此可以看出图所示的宽度优先遍历的访问顺序为A>B>C>D>E>F>H>G>I本节讲述了宽度优先遍历的理论基础把互联网看成一个“超图”则对这张图也可以采用宽度优先遍历的方式进行访问。下面将着重讲解如何对互联网进行宽度优先遍历。宽度优先遍历互联网节介绍的宽度优先遍历是从一个种子节点开始的。而实际的爬虫项目是从一系列的种子链接开始的。所谓种子链接就好比宽度优先遍历中的种子节点(图中的A节点)一样。实际的爬虫项目中种子链接可以有多个而宽度优先遍历中的种子节点只有一个。比如可以指定wwwlietucom和wwwsinacom两个种子链接。如何定义一个链接的子节点?每个链接对应一个HTML页面或者其他文件(word、excel、pdf、jpg等)在这些文件中只有HTML页面有相应的“子节点”这些“子节点”就是HTML页面上对应的超链接。如wwwlietucom页面中(如图所示)“招聘”、“网址”、“更多”以及页面下方的“搜索产品”“技术文档”“成功案例”“猎兔新闻”“联系猎兔”“关于我们”ENGLISH等都是wwwlietucom的子节点。这些子节点本身又是一个链接。对于非HTML文档比如Excel文件等不能从中提取超链接因此可以看作是图的“终端”节点。就好像图中的B、C、D、I、G等节点一样。图猎兔搜索主页整个的宽度优先爬虫过程就是从一系列的种子节点开始把这些网页中的“子节点”(也就是超链接)提取出来放入队列中依次进行抓取。被处理过的链接需要放入一张表(通常称为Visited表)中。每次新处理一个链接之前需要查看这个链接是否已经存在于Visited表中。如果存在证明链接已经处理过跳过不做处理否则进行下一步处理。实际的过程如图所示。新解析出的URLTODO表Visited表初始URL地址解析URL图宽度优先爬虫过程如图所示初始的URL地址是爬虫系统中提供的种子URL(一般在系统的配置文件中指定)。当解析这些种子URL所表示的网页时会产生新的URL(比如从页面中的<ahref=“http:wwwadmincom”中提取出http:wwwadmincom这个链接)。然后进行以下工作:()把解析出的链接和Visited表中的链接进行比较若Visited表中不存在此链接表示其未被访问过。()把链接放入TODO表中。()处理完毕后再次从TODO表中取得一条链接直接放入Visited表中。()针对这个链接所表示的网页继续上述过程。如此循环往复。表显示了对图所示的页面的爬取过程。表网络爬取TODO表Visited表A空BCDEFACDEFA,BDEFA,B,C第章全面剖析网络爬虫续表TODO表Visited表EFA,B,C,DFHA,B,C,D,EHGA,B,C,D,E,FGIA,B,C,D,E,F,HIA,B,C,D,E,F,H,G空A,B,C,D,E,F,H,G,I宽度优先遍历是爬虫中使用最广泛的一种爬虫策略之所以使用宽度优先搜索策略主要原因有三点:重要的网页往往离种子比较近例如我们打开新闻网站的时候往往是最热门的新闻随着不断的深入冲浪所看到的网页的重要性越来越低。万维网的实际深度最多能达到层但到达某个网页总存在一条很短的路径。而宽度优先遍历会以最快的速度到达这个网页。宽度优先有利于多爬虫的合作抓取多爬虫合作通常先抓取站内链接抓取的封闭性很强。这一小节详细讲述了宽度优先遍历互联网的方法。下一节将给出一个详细的例子来说明如何实现这种方法。Java宽度优先爬虫示例本节使用Java实现一个简易的爬虫。其中用到了HttpClient和HtmlParser两个开源工具包。HttpClient的内容之前已经做过详细的阐述。有关HtmlParser的用法我们会在节给出详细的介绍。为了便于读者理解下面给出示例程序的结构如图所示。初始化URL队列判断条件新URL入队抽出网页中的URL下载URL指定的页面队头URL出队列退出程序URL队列为空或爬取到指定数量的网页图爬虫示例程序结构首先需要定义图中所描述的“URL队列”这里使用一个LinkedList来实现这个队列。QueueQueueQueueQueue类:***队列保存将要访问的URL*publicclassQueue{使用链表实现队列privateLinkedListqueue=newLinkedList()入队列publicvoidenQueue(Objectt){queueaddLast(t)}出队列publicObjectdeQueue(){returnqueueremoveFirst()}判断队列是否为空publicbooleanisQueueEmpty(){returnqueueisEmpty()}判断队列是否包含tpublicbooleancontians(Objectt){returnqueuecontains(t)}publicbooleanempty(){returnqueueisEmpty()}}除了URL队列之外在爬虫过程中还需要一个数据结构来记录已经访问过的URL。每当要访问一个URL的时候首先在这个数据结构中进行查找如果当前的URL已经存在则丢弃它。这个数据结构要有两个特点:结构中保存的URL不能重复。能够快速地查找(实际系统中URL的数目非常多因此要考虑查找性能)。针对以上两点我们选择HashSet作为存储结构。LinkQueueLinkQueueLinkQueueLinkQueue类:publicclassLinkQueue{已访问的url集合privatestaticSetvisitedUrl=newHashSet()待访问的url集合privatestaticQueueunVisitedUrl=newQueue()第章全面剖析网络爬虫获得URL队列publicstaticQueuegetUnVisitedUrl(){returnunVisitedUrl}添加到访问过的URL队列中publicstaticvoidaddVisitedUrl(Stringurl){visitedUrladd(url)}移除访问过的URLpublicstaticvoidremoveVisitedUrl(Stringurl){visitedUrlremove(url)}未访问的URL出队列publicstaticObjectunVisitedUrlDeQueue(){returnunVisitedUrldeQueue()}保证每个URL只被访问一次publicstaticvoidaddUnvisitedUrl(Stringurl){if(url!=!urltrim()equals("")!visitedUrlcontains(url)!unVisitedUrlcontians(url))unVisitedUrlenQueue(url)}获得已经访问的URL数目publicstaticintgetVisitedUrlNum(){returnvisitedUrlsize()}判断未访问的URL队列中是否为空publicstaticbooleanunVisitedUrlsEmpty(){returnunVisitedUrlempty()}}下面的代码详细说明了网页下载并处理的过程。和节讲述的内容相比它考虑了更多的方面。比如如何存储网页设置请求超时策略等。DownLoadFileDownLoadFileDownLoadFileDownLoadFile类:publicclassDownLoadFile{***根据URL和网页类型生成需要保存的网页的文件名去除URL中的非文件名字符*publicStringgetFileNameByUrl(Stringurl,StringcontentType){移除http:url=urlsubstring()texthtml类型if(contentTypeindexOf("html")!=){url=urlreplaceAll(":*|<>"","")"html"returnurl}如applicationpdf类型else{returnurlreplaceAll(":*|<>"","")""contentTypesubstring(contentTypelastIndexOf(""))}}***保存网页字节数组到本地文件filePath为要保存的文件的相对地址*privatevoidsaveToLocal(bytedata,StringfilePath){try{DataOutputStreamout=newDataOutputStream(newFileOutputStream(newFile(filePath)))for(inti=i<datalengthi)outwrite(datai)outflush()outclose()}catch(IOExceptione){eprintStackTrace()}}下载URL指向的网页publicStringdownloadFile(Stringurl){StringfilePath=生成HttpClinet对象并设置参数HttpClienthttpClient=newHttpClient()设置HTTP连接超时shttpClientgetHttpConnectionManager()getParams()setConnectionTimeout()生成GetMethod对象并设置参数GetMethodgetMethod=newGetMethod(url)设置get请求超时sgetMethodgetParams()setParameter(HttpMethodParamsSOTIMEOUT,)设置请求重试处理getMethodgetParams()setParameter(HttpMethodParamsRETRYHANDLER,newDefaultHttpMethodRetryHandler())执行HTTPGET请求try{intstatusCode=httpClientexecuteMethod(getMethod)判断访问的状态码if(statusCode!=HttpStatusSCOK){第章全面剖析网络爬虫Systemerrprintln("Methodfailed:"getMethodgetStatusLine())filePath=}处理HTTP响应内容byteresponseBody=getMethodgetResponseBody()读取为字节数组根据网页url生成保存时的文件名filePath="temp"getFileNameByUrl(url,getMethodgetResponseHeader("ContentType")getValue())saveToLocal(responseBody,filePath)}catch(HttpExceptione){发生致命的异常可能是协议不对或者返回的内容有问题Systemoutprintln("Pleasecheckyourprovidedhttpaddress!")eprintStackTrace()}catch(IOExceptione){发生网络异常eprintStackTrace()}finally{释放连接getMethodreleaseConnection()}returnfilePath}}接下来演示如何从获得的网页中提取URL。Java有一个非常实用的开源工具包HtmlParser它专门针对Html页面进行处理不仅能提取URL还能提取文本以及你想要的任何内容。关于它的有关内容会在第章详细介绍。好了让我们看看代码吧!HtmlParserToolHtmlParserToolHtmlParserToolHtmlParserTool类:publicclassHtmlParserTool{获取一个网站上的链接filter用来过滤链接publicstaticSet<String>extracLinks(Stringurl,LinkFilterfilter){Set<String>links=newHashSet<String>()try{Parserparser=newParser(url)parsersetEncoding("gb")过滤<frame>标签的filter用来提取frame标签里的src属性NodeFilterframeFilter=newNodeFilter(){publicbooleanaccept(Nodenode){if(nodegetText()startsWith("framesrc=")){returntrue}else{returnfalse}}OrFilter来设置过滤<a>标签和<frame>标签OrFilterlinkFilter=newOrFilter(newNodeClassFilter(LinkTagclass),frameFilter)得到所有经过过滤的标签NodeListlist=parserextractAllNodesThatMatch(linkFilter)for(inti=i<listsize()i){Nodetag=listelementAt(i)if(taginstanceofLinkTag)<a>标签{LinkTaglink=(LinkTag)tagStringlinkUrl=linkgetLink()URLif(filteraccept(linkUrl))linksadd(linkUrl)}else<frame>标签{提取frame里src属性的链接如<framesrc="testhtml">Stringframe=taggetText()intstart=frameindexOf("src=")frame=framesubstring(start)intend=frameindexOf("")if(end==)end=frameindexOf(">")StringframeUrl=framesubstring(,end)if(filteraccept(frameUrl))linksadd(frameUrl)}}}catch(ParserExceptione){eprintStackTrace()}returnlinks}}最后来看看宽度爬虫的主程序。MyCrawlerMyCrawlerMyCrawlerMyCrawler类:publicclassMyCrawler{***使用种子初始化URL队列*return*paramseeds种子URL*privatevoidinitCrawlerWithSeeds(Stringseeds){for(inti=i<seedslengthi)LinkQueueaddUnvisitedUrl(seedsi)}第章全面剖析网络爬虫***抓取过程*return*paramseeds*publicvoidcrawling(Stringseeds){定义过滤器提取以http:wwwlietucom开头的链接LinkFilterfilter=newLinkFilter(){publicbooleanaccept(Stringurl){if(urlstartsWith("http:wwwlietucom"))returntrueelsereturnfalse}}初始化URL队列initCrawlerWithSeeds(seeds)循环条件:待抓取的链接不空且抓取的网页不多于while(!LinkQueueunVisitedUrlsEmpty()LinkQueuegetVisitedUrlNum()<=){队头URL出队列StringvisitUrl=(String)LinkQueueunVisitedUrlDeQueue()if(visitUrl==)continueDownLoadFiledownLoader=newDownLoadFile()下载网页downLoaderdownloadFile(visitUrl)该URL放入已访问的URL中LinkQueueaddVisitedUrl(visitUrl)提取出下载网页中的URLSet<String>links=HtmlParserToolextracLinks(visitUrl,filter)新的未访问的URL入队for(Stringlink:links){LinkQueueaddUnvisitedUrl(link)}}}main方法入口publicstaticvoidmain(Stringargs){MyCrawlercrawler=newMyCrawler()crawlercrawling(newString{"http:wwwlietucom"})}}上面的主程序使用了一个LinkFilter接口并且实现为一个内部类。这个接口的目的是为了过滤提取出来的URL它使得程序中提取出来的URL只会和猎兔网站相关。而不会提取其他无关的网站。代码如下:publicinterfaceLinkFilter{publicbooleanaccept(Stringurl)}带偏好的爬虫有时在URL队列中选择需要抓取的URL时不一定按照队列“先进先出”的方式进行选择。而把重要的URL先从队列中“挑”出来进行抓取。这种策略也称作“页面选择”(PageSelection)。这可以使有限的网络资源照顾重要性高的网页。那么哪些网页是重要性高的网页呢?判断网页的重要性的因素很多主要有链接的欢迎度(知道链接的重要性了吧)、链接的重要度和平均链接深度、网站质量、历史权重等主要因素。链接的欢迎度主要是由反向链接(backlinks即指向当前URL的链接)的数量和质量决定的我们定义为IB(P)。链接的重要度是一个关于URL字符串的函数仅仅考察字符串本身比如认为“com”和“home”的URL重要度比“cc”和“map”高我们定义为IL(P)。平均链接深度根据上面所分析的宽度优先的原则计算出全站的平均链接深度然后认为距离种子站点越近的重要性越高。我们定义为ID(P)。如果我们定义网页的重要性为I(P)那么页面的重要度由下面的公式决定:I(P)=X*IB(P)Y*IL(P)()其中X和Y两个参数用来调整IB(P)和IL(P)所占比例的大小ID(P)由宽度优先的遍历规则保证因此不作为重要的指标函数。如何实现最佳优先爬虫呢最简单的方式可以使用优先级队列来实现TODO表并且把每个URL的重要性作为队列元素的优先级。这样每次选出来扩展的URL就是具有最高重要性的网页。有关优先级队列的介绍请参考节中的内容。例如假设图中节点的重要性为D>B>C>A>E>F>I>G>H则整个遍历过程如表所示。表

类似资料

该用户的其他资料

概率论习题课.ppt

李贤平《概率论基础》第三版课后答案2.pdf

练习题答案.pdf

李贤平-概率论答案.pdf

练习题.pdf

职业精品

精彩专题

结婚彩礼真有那么重要吗?

原创于西周而后沿袭至今的彩礼,虽然被一部分家长奉为圭臬,但越来越多的年轻人对结婚必须要彩礼不以为然。彩礼引发的社会矛盾越来越受到关注,结婚是自己的事,如人饮水冷暖自知,至于要不要彩礼或者要多少彩礼,因人而异,因财力而已,不可一概而论。

用户评论(1)

0/200
  • 10.69.3.32 2013-03-04 23:46:32

    这个是全本的 很好 值得看看 谢谢分享

上传我的资料

精选资料

热门资料排行换一换

  • 空港手记(首部揭秘航空港的职业生…

  • 《武林旧事 插图本》中华书局 2…

  • 赵汀阳等:学问中国,江西教育出版…

  • 《古今笑 插图本》中华书局 20…

  • 【心理建设】“拖延症”_形成原因…

  • Dante and Derrid…

  • 教育精选之《千家诗》.pdf

  • 高中英语标准词汇表3600.doc

  • 临床诊疗指南_血液学分册.PDF

  • 资料评价:

    / 352
    所需积分:0 立即下载

    意见
    反馈

    返回
    顶部