CSDN日报20170219——《程序员的沟通之痛》      【技术直播】揭开人工智能神秘的面纱        程序员1月书讯     云端应用征文大赛,秀绝招,赢无人机!
 

网络爬虫讲解(附java实现的实例)

标签: java网络爬虫stringexceptionurl搜索引擎
 53394人阅读 评论(5) 收藏 举报
 分类:

网络蜘蛛即Web Spider,是一个很形象的名字。把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛。网络蜘蛛是通过网页的链接地址来寻找网页,从 网站某一个页面(通常是首页)开始,读取网页的内容,找到在网页中的其它链接地址,然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止。如果把整个互联网当成一个网站,那么网络蜘蛛就可以用这个原理把互联网上所有的网页都抓取下来。

  对于搜索引擎来说,要抓取互联网上所有的网页几乎是不可能的,从目前公布的数据来看,容量最大的搜索引擎也不过是抓取了整个网页数量的百分之四十左右。这其中的原因一方面是抓取技术的瓶颈,无法遍历所有的网页,有许多网页无法从其它网页的链接中找到;另一个原因是存储技术和处理技术的问题,如果按照每个页面的平均大小为20K计算(包含图片),100亿网页的容量是100×2000G字节,即使能够存储,下载也存在问题(按照一台机器每秒下载 20K计算,需要340台机器不停的下载一年时间,才能把所有网页下载完毕)。同时,由于数据量太大,在提供搜索时也会有效率方面的影响。因此,许多搜索引擎的网络蜘蛛只是抓取那些重要的网页,而在抓取的时候评价重要性主要的依据是某个网页的链接深度。

  在抓取网页的时候,网络蜘蛛一般有两种策略:广度优先和深度优先。

   广度优先是指网络蜘蛛会先抓取起始网页中链接的所有网页,然后再选择其中的一个链接网页,继续抓取在此网页中链接的所有网页。这是最常用的方式,因为这个方法可以让网络蜘蛛并行处理,提高其抓取速度。深度优先是指网络蜘蛛会从起始页开始,一个链接一个链接跟踪下去,处理完这条线路之后再转入下一个起始页, 继续跟踪链接。这个方法有个优点是网络蜘蛛在设计的时候比较容易。两种策略的区别,下图的说明会更加明确。

  由于不可能抓取所有的网页,有些网络蜘蛛对一些不太重要的网站,设置了访问的层数。例如,在上图中,A为起始网页,属于0层,B、C、D、 E、F属于第1层,G、H属于第2层, I属于第3层。如果网络蜘蛛设置的访问层数为2的话,网页I是不会被访问到的。这也让有些网站上一部分网页能够在搜索引擎上搜索到,另外一部分不能被搜索到。对于网站设计者来说,扁平化的网站结构设计有助于搜索引擎抓取其更多的网页。

  网络蜘蛛在访问网站网页的时候,经常会遇到加密数据和网页权限的问题,有些网页是需要会员权限才能访问。当然,网站的所有者可以通过协议让网 络蜘蛛不去抓取(下小节会介绍),但对于一些出售报告的网站,他们希望搜索引擎能搜索到他们的报告,但又不能完全**的让搜索者查看,这样就需要给网络蜘 蛛提供相应的用户名和密码。网络蜘蛛可以通过所给的权限对这些网页进行网页抓取,从而提供搜索。而当搜索者点击查看该网页的时候,同样需要搜索者提供相应的权限验证。

 网站与网络蜘蛛

  网络蜘蛛需要抓取网页,不同于一般的访问,如果控制不好,则会引起网站服务器负担过重。去年4月,淘宝http://www.taobao.com)就因为雅虎搜索引擎的网络蜘蛛抓取其数据引起淘宝网服务器的不稳定。网站是否就无法和网络蜘蛛交流呢?其实不然,有多种方法可以让网站和网络蜘蛛进行交流。一方面让网站管理员了解网络蜘蛛都来自哪儿,做了些什么,另一方面也告诉网络蜘蛛哪些网页不应该抓取,哪 些网页应该更新。

  每个网络蜘蛛都有自己的名字,在抓取网页的时候,都会向网站标明自己的身份。网络蜘蛛在抓取网页的时候会发送一个请求,这个请求中就有一个字段为User-agent,用于标识此网络蜘蛛的身份。例如Google网络蜘蛛的标识为GoogleBot,Baidu网络蜘蛛的标识为BaiDuSpider, Yahoo网络蜘蛛的标识为Inktomi Slurp。如果在网站上有访问日志记录,网站管理员就能知道,哪些搜索引擎的网络蜘蛛过来过,什么时候过来的,以及读了多少数据等等。如果网站管理员发现某个蜘蛛有问题,就通过其标识来和其所有者联系。下面是博客中http://www.blogchina.com)2004年5月15日的搜索引擎访问日志:

  网络蜘蛛进入一个网站,一般会访问一个特殊的文本文件Robots.txt,这个文件一般放在网站服务器的根目录下,http://www.blogchina.com/robots.txt。网站管理员可以通过robots.txt来定义哪些目录网络蜘蛛不能访问,或者哪些目录对于某些特定的网络蜘蛛不能访问。例如有些网站的可执行文件目录和临时文件目录不希望被搜索引擎搜索到,那么网站管理员就可以把这些目录定义为拒绝访问目录。Robots.txt语法很简单,例如如果对目录没有任何限制,可以用以下两行来描述:
  User-agent: * 
  Disallow:

  当然,Robots.txt只是一个协议,如果网络蜘蛛的设计者不遵循这个协议,网站管理员也无法阻止网络蜘蛛对于某些页面的访问,但一般的网络蜘蛛都会遵循这些协议,而且网站管理员还可以通过其它方式来拒绝网络蜘蛛对某些网页的抓取。

  网络蜘蛛在下载网页的时候,会去识别网页的HTML代码,在其代码的部分,会有META标识。通过这些标识,可以告诉网络蜘蛛本网页是否需要被抓取,还可以告诉网络蜘蛛本网页中的链接是否需要被继续跟踪。例如:表示本网页不需要被抓取,但是网页内的链接需要被跟踪。

  现在一般的网站都希望搜索引擎能更全面的抓取自己网站的网页,因为这样可以让更多的访问者能通过搜索引擎找到此网站。为了让本网站的网页更全面被抓取到,网站管理员可以建立一个网站地图,即SiteMap。许多网络蜘蛛会把sitemap.htm文件作为一个网站网页爬取的入口,网站管理员可以把网站内部所有网页的链接放在这个文件里面,那么网络蜘蛛可以很方便的把整个网站抓取下来,避免遗漏某些网页,也会减小对网站服务器的负担。

  内容提取

  搜索引擎建立网页索引,处理的对象是文本文件。对于网络蜘蛛来说,抓取下来网页包括各种格式,包括html、图片、doc、pdf、多媒体、 动态网页及其它格式等。这些文件抓取下来后,需要把这些文件中的文本信息提取出来。准确提取这些文档的信息,一方面对搜索引擎的搜索准确性有重要作用,另一方面对于网络蜘蛛正确跟踪其它链接有一定影响。

  对于doc、pdf等文档,这种由专业厂商提供的软件生成的文档,厂商都会提供相应的文本提取接口。网络蜘蛛只需要调用这些插件的接口,就可以轻松的提取文档中的文本信息和文件其它相关的信息。

  HTML等文档不一样,HTML有一套自己的语法,通过不同的命令标识符来表示不同的字体、颜色、位置等版式,如:、、等,提取文本信息时需要把这些标识符都过滤掉。过滤标识符并非难事,因为这些标识符都有一定的规则,只要按照不同的标识符取得相应的信息即可。但在识别这些信息的时候,需要同步记录许多版式信息,例如文字的字体大小、是否是标题、是否是加粗显示、是否是页面的关键词等,这些信息有助于计算单词在网页中的重要程度。同时,对于 HTML网页来说,除了标题和正文以外,会有许多广告链接以及公共的频道链接,这些链接和文本正文一点关系也没有,在提取网页内容的时候,也需要过滤这些 无用的链接。例如某个网站有“产品介绍”频道,因为导航条在网站内每个网页都有,若不过滤导航条链接,在搜索“产品介绍”的时候,则网站内每个网页都会搜索到,无疑会带来大量垃圾信息。过滤这些无效链接需要统计大量的网页结构规律,抽取一些共性,统一过滤;对于一些重要而结果特殊的网站,还需要个别处理。这就需要网络蜘蛛的设计有一定的扩展性。

  对于多媒体、图片等文件,一般是通过链接的锚文本(即,链接文本)和相关的文件注释来判断这些文件的内容。例如有一个链接文字为“张曼玉照片 ”,其链接指向一张bmp格式的图片,那么网络蜘蛛就知道这张图片的内容是“张曼玉的照片”。这样,在搜索“张曼玉”和“照片”的时候都能让搜索引擎找到这张图片。另外,许多多媒体文件中有文件属性,考虑这些属性也可以更好的了解文件的内容。

  动态网页一直是网络蜘蛛面临的难题。所谓动态网页,是相对于静态网页而言,是由程序自动生成的页面,这样的好处是可以快速统一更改网页风格,也可以减少网页所占服务器的空间,但同样给网络蜘蛛的抓取带来一些麻烦。由于开发语言不断的增多,动态网页的类型也越来越多,如:asp、jsp、PHP 等。这些类型的网页对于网络蜘蛛来说,可能还稍微容易一些。网络蜘蛛比较难于处理的是一些脚本语言(如VBScript和JavaScript)生成的网页,如果要完善的处理好这些网页,网络蜘蛛需要有自己的脚本解释程序。对于许多数据是放在数据库的网站,需要通过本网站的数据库搜索才能获得信息,这些给网络蜘蛛的抓取带来很大的困难。对于这类网站,如果网站设计者希望这些数据能被搜索引擎搜索,则需要提供一种可以遍历整个数据库内容的方法。

  对于网页内容的提取,一直是网络蜘蛛中重要的技术。整个系统一般采用插件的形式,通过一个插件管理服务程序,遇到不同格式的网页采用不同的插件处理。这种方式的好处在于扩充性好,以后每发现一种新的类型,就可以把其处理方式做成一个插件补充到插件管理服务程序之中。

  更新周期

  由于网站的内容经常在变化,因此网络蜘蛛也需不断的更新其抓取网页的内容,这就需要网络蜘蛛按照一定的周期去扫描网站,查看哪些页面是需要更新的页面,哪些页面是新增页面,哪些页面是已经过期的死链接。

  搜索引擎的更新周期对搜索引擎搜索的查全率有很大影响。如果更新周期太长,则总会有一部分新生成的网页搜索不到;周期过短,技术实现会有一定难度,而且会对带宽、服务器的资源都有浪费。搜索引擎的网络蜘蛛并不是所有的网站都采用同一个周期进行更新,对于一些重要的更新量大的网站,更新的周期短,如有些新闻网站,几个小时就更新一次;相反对于一些不重要的网站,更新的周期就长,可能一两个月才更新一次。

  一般来说,网络蜘蛛在更新网站内容的时候,不用把网站网页重新抓取一遍,对于大部分的网页,只需要判断网页的属性(主要是日期),把得到的属性和上次抓取的属性相比较,如果一样则不用更新。


            Spider的实现细节

a.  URL 的组织和管理考虑到系统自身的资源和时间有限,Spider程序应尽可能的对链接进行筛选,以保证获取信息的质量和效率。Spider程序对新URL 的选择往往与搜索引擎的类型、目标集合、能够处理信息的类型、资源的限制和是否支持Robots限制协议有关。

概括为以下几点:

访问过的和重复的URL排除

文件类型必须被系统处理,不能处理的URL排除

不在目标集合中的排除,被Rohots.txt限制的排除

URL排序也是减轻系统负担的重要手段之一。这就要求计算URL的重要性,如果评估新URI的重要性较高,则会冲掉旧的URL。无论任何情况下,对 Spider而言,首先访问目标集合中的重要站点都是意义和重要的。但是一个页面的重要性的准确评估只能在分析其内容之后进行。可以根据一个页面链接数量的多少来评估此页面是否重要;或者对URL 地址进行解析其中的内容例如以".com", ".edu",".cn"就较为重要一些,或者可以根据页而标题与当前的热点问题是否相近或相关来评定其页面的重要性。决定网站或页面的重要性的因素很多,也根据各个搜索引擎的侧重点不同而各异,最终的评估方法都依赖于该搜索引擎对于资源获取的要求来决定。影响Spider速度的一种重要因素是DNS查询,为此每个 Spider都要维护一个自己的DNS缓冲。这样每个链接都处于不同的状态,包括:DNS 查询、连接到主机、发送请求、得到响应。这些因素综合起来使得Spider变成一个非常复杂的系统。

b. Spider的遍历规则:页面的遍历主要有两种方式:深度遍历和广度遍历。深度遍历算法可以获得的信息较为集中,信息比较完整,但覆盖面就比较有限,广度遍历算法则刚好相反。

c. Spider实现中的主要问题:虽然Spider的功能很强,但也存在不少的问题:

(1)如果一组URL地址没有被组外URL所链接到,那么Spider就找不到它们。由于spider不能更新过快(因为网络带宽是有限的,更新过快就会影响其他用户的正常使用),难免有不能及时加入的新网站或新页面。

(2)spider程序在遍历Web时也存在危险,很可能遇到一个环链接而陷入死循环中。简单的避免方法就是忽略已访问过的URL,或限制网站的遍历深度。

(3) Spider程序时大型搜索引擎中很脆弱的部分,因为它与很多的Web报务器、不同的域名服务器打交道,而这些服务完全在系统的控制之外。由于网络上包含了大量的垃圾信息,Spider很可能会收取这些垃圾信息。一个页面出现问题也很可能引起Spider程序中止、崩溃或其他不可预料的行为。因此访问 Internet的Spider程序应该设计得非常强壮,充分考虑各种可能遇到的情况,让Spider在遇到各种情况时可以采取相应的处理行为,而不至于获得一些垃圾信息或者直接就对程序本身造成危害。

Spider构架

发现、搜集网页信息需要有高性能的“网络蜘蛛”程序〔Spider〕去自动地在互联网中搜索信息。一个典型的网络蜘蛛工作的方式:查看一个页面,并从中找到相关信息,然后它再从该页面的所有链接中出发,继续寻找相关的信息,以此类推。网络蜘蛛在搜索引擎整体结构中的位置如下图所示: 初始化时,网络蜘蛛一般指向一个URL ( Uniform ResourceLocator)池。在遍历Internet的过程中,按照深度优先或广度优先或其他启发式算法从URL池中取出若干URL进行处理,同时将未访问的 URL放入URL池中,这样处理直到URL池空为止。对Web文档的索引则根据文档的标题、首段落甚至整个页面内容进行,这取决于搜索服务的数据收集策略。

网络蜘蛛在漫游的过程中,根据页面的标题、头、链接等生成摘要放在索引数据库中。如果是全文搜索,还需要将整个页面的内容保存到本地数据库。网络蜘蛛为实现其快速地浏览整个互联网,通常在技术上采用抢先式多线程技术实现在网上搜索信息。通过抢先式多线程的使用,你能索引一个基于URL链接的 Web页面,启动一个新的线程跟随每个新的URL链接,索引一个新的URL起点。当然在服务器上所开的线程也不能无限膨胀,需要在服务器的正常运转和快速 收集网页之间找一个平衡点。

在整个搜索引擎工作过程中,整个蜘蛛的数据入口是URL地址,数据出口是Web页仓库。Spider程序发现URL链接以后,经过Stor处理模块,将我们所需要的网页数据存储在Web页仓库中,为以后的形成网页快照、网页分析提供基础数据。在Spider程序工作的过程中,发现新的链接,对该链接进行分析,形成新的搜索地址,作为下一次Spider程序的数据输入。这个过程的实现就是Spider程序的队列管理。

Spider程序的工作过程,简单来讲,就是不断发现新的链接,并对该链接对应的页面分析存储的工程。如下图所示,

一、索引器: 索引器的功能是理解搜索器所搜集的信息,从中抽取出索引项,用于表示文档以及生成文档库的索引表。索引项有客观索引项内容索引项两种: 客观项:与文档的语意内容无关,如作者名、URL、更新时间、编码、长度、链接流行度(Link Popularity)等等; 内容索引项:是用来反映文档内容的,如关键词及其权重、短语、词、字等等。内容索引项可以分为单索引项和多索引项(或称短语索引项)两种。单索引项对于英文来讲是英语单词,比较容易提取,因为单词之间有天然的分隔符(空格);对于中文等连续书写的语言,必须采用多索引项,进行词语的切分。索引器可以使用集中式索引算法或分布式索引算法。当数据量很大时,必须实现实时索引(Real-time Indexing),否则不能够跟上信息量急剧增加的速度。索引算法对索引器的性能(如大规模峰值查询时的响应速度)有很大的影响。一个搜索引擎的有效性 在很大程度取决于索引的质量。 由于汉文字符多,处理复杂,中文词的处理不容易。索引器中的中文分词技术: 一个分词系统=分词程序+分词词典(1)最大匹配法MM (2)反向最大匹配法RMM (1)最佳匹配法OM (1)双向扫描法[百度的分词就采用了双向扫描法] 系统关键是:分词精度和分词速度

二、建立索引的方法: 为了加快检索速度,搜索引擎要对Snider程序搜集到的信,建立倒排索引。 (1)全文索引和部分索引有些搜索引擎对于信息库中的页面建立全文索引,有些只建立摘要部分索引或者每个段落前面部分的索引。还有些搜索引擎在建立索引时,要同时考虑超文本的不同标记所表示的含义,如粗体、大字体显示的东西往往比较重要。有些搜索引擎还在建立索引的过程中收集页面中的超链接。这些超链接反映了收集到的信息之间的空间结构。利用这些结果信息可以提高页面相关度判别时的准确度。(2)是否过滤无用词由于网页中存在这许多无用(无实际意义)单词,例如“啊”、“的”等。这此词往往不能明确表达该网页信息,所以有些搜索引擎保存一个无用词汇表,在建立索引时将不对这些词汇建立索引。 (3)是否使用Meta标记中的信息网页中的Meta标记用来标注一些非常显示性的信息。有些网页将页面的关键词等信息放在其中。便于在建立索引的过程中提高这些词汇的相关度。(4)是否对图像标记中的替换文本(ALT text)或页面中的注解建立索引由于现有的搜索引擎对图像的检索技术还不太成熟,大多数搜索引擎不支持图像的检索。在超文木的结构页面中,图像标记中往往存放着图像的替换信息。这些信息说明了该图像对应的图像的基本信息。(5)是否支持词干提取技术

三、建立索引的过程: 分析过程对文档进行索引并存储到存储桶中排序过程

Spider处理流程

当一个URL被加入到等待队列中时Spider程序就会开始运行。只要等待队列中有一个网页或Spider程序正在处理一个网页,Spider程序就会继续它的工作。当等待队列为空并且当前没有处理任何网页,Spider程序就会停止它的工作。

Spider程序实现初探

Spider 程序是从网上下载Web页面再对其进行处理,为了提高效率,很显然要采用多线程的方法,几个Spider线程同时并行工作,访问不同的链接。构造 Spider程序有两种方式。第一种是将它设计为递归程序,第二种是将它编写成非递归的程序。递归是在一个方法中调用它本身的程序设计技术。当需要重复做同样的基本仟务或在处理先前任务时可展现将来的任务信息时,递归是相当实用的。例如下面的代码:

void RecursiveSpider(String url) {

download URL……

parse URL……

while found each URL

call RecursiveSpider(found URL) ……

process the page just downloaded……

} 这段代码查看单独的一个Web页的任务放在一个RecursiveSpider方法中。在此,调用RecursiveSipder方法来访问URL。当它发现链接时,该方法调用它自己。递归方法在访问很少的网页时,可以使用。因为当一个递归程序运行时要把每次递归压入堆栈(堆栈是个程序结构,每次调用一个方法时,将返回地址存入其中)。如果递归程序要运行很多次,堆栈会变得非常大,它可能会耗尽整个堆栈内存而导致程序中止。递归还有个问题是多线程和递归是不兼容的,因为在这一过程中每一个线程都是自己的堆栈。当一个方法调用它自身时,它们需要使用同一个堆栈。这就是说递归的Spider程序不能使用多线程。 非递归程序不调用自身,而是采用队列的方法。队列就是排队,要得到程序的处理就必须在队列中排队等待。我们在构造造Spider时就采用该方式。使用非递归的方法时,给定Spider程序一个要访问的页面,它会将其加入到要访问的站点的队列中去。当Spider发现新的链接时,也会将它们加入到该队列中。 Spider程序会顺序处理队列中的每一个网页。实际在Spider程序中使用了四个队列;在Spider程序的构造过程中,有两种方法用于访问队列的管理。一种方法就是基于内存的队列管理。

第二种方法就是基于SQL的队列管理。基于SQL的队列和基于内存的队列都是有效的,在校园网上做实验的结果表明,在系统运行过程中间,如果 Spider 的访问任务随着网页数量增加,基于内存的Spider程序效率会下降。因而,选择基于SQL的队列管理方案来构造本Spider程序。

等待队列: 在这个队列中,URL等待被Spider程序处理。新发现的URL被加入到该处理队列:当Spider开始处理URL时,它们被传送到这一队列。当一个 URL被处理后它被移送到错误队列或完成队列: 错误队列: 如果下载某一页面时出现错误,它的URL将被加入该队列。该队列的URL不会再移动到其他队列。被列入该队列的URL将不再会被Spider程序处理。

完成队列: 如果页面的下载没有出现任何错误,则该页面将会被加入完成队列。加入该队列的URL不会再移动到其他队列。同一时刻一个URL只能在一个队列中。其实通俗的讲就是该URL处于什么状态,URL 状态的变化过程就是程序处理URL的过程。下图说明的一个URL状态的变化过程。 Spider程序会遇到三种连接:内部连接外部连接其他连接,一个示例Spider类:

 

Java代码 
import java.awt.*; 

import java.NET.*; 
import java.io.*; 
import java.lang.*; 
import java.util.*; 


class node{ 
private Object data; 
private node next; 
private node prev; 
public node(Object o){ 
data = o; 
prev = next = null; 

public String toString(){ 
if(next!=null)return data.toString() + "\n"+ next.toString(); 
return data.toString(); 

public node getNext(){return next;} 
public void setNext(node n){next = n;} 
public node getPrev(){return prev;} 
public void setPrev(node n){prev = n;} 
public Object getData(){return data;} 


class linkedlist{ 
node head; 
node tail; 
public linkedlist(){ 
tail = head = null; 

public String toString(){ 
if(head==null)return "Empty list"; 
return head.toString(); 

public void insert(Object o){ 
if(tail==null){ 
head = tail = new node(o); 
}else{ 
node nn = new node(o); 
tail.setNext(nn); 
tail=nn; 


public boolean contains(Object o){ 
for(node n = head;n!=null;n=n.getNext()){ 
if(o.equals(n.getData()))return true; 

return false; 

public Object pop(){ 
if(head==null)return null; 
Object ret = head.getData(); 
head = head.getNext(); 
if(head==null)tail = null; 
return ret; 

public boolean isEmpty(){ 
return head==null; 




class list{ 
protected node tail; 
protected node ptr; 
private boolean stop; 
public list(){ 
ptr=tail=null; 
stop=false; 

public boolean isEmpty(){return tail==null;} 
public void reset(){ 
stop=false; 
ptr=tail; 

public String toString(){ 
if(tail==null)return "Empty list"; 
String ret=""; 
for(node n =tail.getNext();n!=tail;n=n.getNext())ret+=n.getData().toString()+"\n";
ret+=tail.getData().toString(); 
return ret; 

public Object get(){ 
if(ptr==null)return null; 
ptr = ptr.getNext(); 
if(ptr==tail.getNext()){ 
if(stop)return null; 
stop=true; 
return tail.getNext().getData(); 

return ptr.getData(); 

public void insert(Object o, boolean attail){ 
node nn = new node(o); 
if(tail==null){ 
nn.setNext(nn); 
   nn.setPrev(nn); 
   ptr=tail=nn; 
   return; 

if(attail){ 
tail.getNext().setPrev(nn); 
   nn.setNext(tail.getNext()); 
   tail.setNext(nn); 
   nn.setPrev(tail); 
   tail=nn; 
}else{ 
   nn.setNext(tail.getNext()); 
   nn.setPrev(tail); 
   tail.setNext(nn); 
   nn.getNext().setPrev(nn); 


public void insert(Object o){} 

   
class stack extends list{ 
public stack(){super();} 
public void insert(Object o){insert(o, false);} 

class queue extends list{ 
public queue(){super();} 
public void insert(Object o){insert(o, true);} 
public String peek(){ 
   if(tail==null)return ""; 
   return tail.getNext().getData().toString(); 

public Object pop(){ 
if(tail==null)return null; 
Object ret = tail.getNext().getData(); 
if(tail.getNext()==tail){ 
   tail=ptr=null; 
}else{ 
   if(tail.getNext()==ptr)ptr=ptr.getNext(); 
   tail.setNext(tail.getNext().getNext()); 

return ret; 


   
   
class hashtable{ 
   private Vector table; 
   private int size; 
   public hashtable(){ 
size = 991; 
table = new Vector(); 
for(int i=0;i<size;i++){ 
   table.add(new linkedlist()); 

   } 
   public void insert(Object o){ 
int index = o.hashCode(); 
index = index % size; 
if(index<0)index+=size; 
linkedlist ol = (linkedlist)table.get(index); 
ol.insert(o); 
   } 
   public boolean contains(Object o){ 
int index = o.hashCode(); 
index = index % size; 
if(index<0)index+=size; 
return ((linkedlist)(table.get(index))).contains(o); 
   } 
   public String toString(){ 
String ret =""; 
for(int i=0;i<size;i++){ 
   if(!((linkedlist)(table.get(i))).isEmpty()){ 
ret+="\n"; 
ret+=table.get(i).toString(); 
   } 

return ret; 
   } 

   
class spider implements Runnable{ 
public queue todo; 
public stack done; 
public stack errors; 
public stack omittions; 
private hashtable allsites; 
private String last=""; 
   int maxsites; 
   int visitedsites; 
   int TIMEOUT; 
   String base; 
   String []badEndings2 = {"ps", "gz"}; 
   String []badEndings3 = {"pdf", "txt","zip", "jpg", "mpg", "gif","mov", "tut", "req", "abs","swf", "tex", "dvi", "bin","exe", "rpm"};
   String []badEndings4 = {"jpeg", "mpeg"}; 
   
   public spider(String starturl, int max, String b){ 
TIMEOUT = 5000; 
base = b; 
allsites = new hashtable(); 
todo = new queue(); 
done = new stack(); 
errors = new stack(); 
omittions = new stack(); 
try{ 
   URL u = new URL(starturl); 
   todo.insert(u); 
}catch(Exception e){ 
   System.out.println(e); 
   errors.insert("bad starting url "+starturl+","+e.toString()); 

maxsites = max; 
visitedsites = 0; 
   } 
   
   /* 
   * how many millisec to wait for each page 
   */ 
   public void setTimer(int amount){ 
TIMEOUT = amount; 
   } 
   
   /* 
   * strips the '#' anchor off a url 
   */ 
   private URL stripRef(URL u){ 
try{ 
   return new URL(u.getProtocol(), u.getHost(), u.getPort(),u.getFile()); 
}catch(Exception e){return u;} 
   } 
   
   /* 
   * adds a url for future processing 
   */ 
   public void addSite(URL toadd){ 
if(null!=toadd.getRef())toadd = stripRef(toadd); 
if(!allsites.contains(toadd)){ 
   allsites.insert(toadd); 
   if(!toadd.toString().startsWith(base)){ 
omittions.insert("foreign URL: "+toadd.toString()); 
return; 
   } 
   if(!toadd.toString().startsWith("http") &&!toadd.toString().startsWith("HTTP")){
omittions.insert("ignoring URL: "+toadd.toString()); 
return; 
   } 
   
   String s = toadd.getFile(); 
   String last=""; 
   String []comp={}; 
   if(s.charAt(s.length()-3)=='.'){ 
last = s.substring(s.length()-2); 
comp = badEndings2; 
   }else if(s.charAt(s.length()-4)=='.'){ 
last = s.substring(s.length()-3); 
comp = badEndings3; 
   }else if(s.charAt(s.length()-5)=='.'){ 
last = s.substring(s.length()-4); 
comp = badEndings4; 
   } 
   for(int i=0;i<comp.length;i++){ 
if(last.equalsIgnoreCase(comp[i])){//loop through all bad extensions 
     omittions.insert("ignoring URL:"+toadd.toString()); 
     return; 

   } 
     
   todo.insert(toadd); 

   } 
   
   /* 
   * true if there are pending urls and the maximum hasn't beenreached 
   */ 
   public boolean hasMore(){ 
return !todo.isEmpty() && visitedsites<maxsites; 
   } 
   
   /* 
   * returns the next site, works like enumeration, will return newvalues each time
   */ 
   private URL getNextSite(){ 
last = todo.peek(); 
visitedsites++; 
return (URL)todo.pop(); 
   } 
   
   /* 
   * Just to see what we are doing now... 
   */ 
   public String getCurrent(){ 
return last; 
   } 
   
   /* 
   * process the next site 
   */ 
   public void doNextSite(){ 
URL current = getNextSite(); 
if(current==null)return; 
try{ 
   //System.err.println("Processing #"+visitedsites+":"+current); 
   parse(current); 
   done.insert(current); 

catch(Exception e){ 
   errors.insert("Bad site: "+current.toString()+","+e.toString()); 

   } 
   
   public void run(){ 
while(hasMore())doNextSite(); 
   } 
   
   /* 
   * to print out the internal data structures 
   */ 
   public String toString(){return getCompleted()+getErrors();} 
   private String getErrors(){ 
if(errors.isEmpty())return "No errors\n"; 
else return "Errors:\n"+errors.toString()+"\nEnd oferrors\n"; 
   } 
   private String getCompleted(){ 
return "Completed Sites:\n"+done.toString()+"\nEnd of completedsites\n"; 
   } 
   
   /* 
   * Parses a web page at (site) and adds all the urls it sees 
   */ 
   private void parse(URL site) throws Exception{ 
String source=getText(site); 
String title=getTitle(source); 
if(title.indexOf("404")!=-1 || 
   title.indexOf("Error")!=-1 || 
   title.indexOf("Not Found")!=-1){ 
   throw new Exception (("404, Not Found: "+site)); 

int loc, beg; 
boolean hasLT=false; 
boolean hasSp=false; 
boolean hasF=false; 
boolean hasR=false; 
boolean hasA=false; 
boolean hasM=false; 
boolean hasE=false; 
for(loc=0;loc<source.length();loc++){ 
   char c = source.charAt(loc); 
   if(!hasLT){ 
hasLT = (c=='<'); 
   } 
   
   //search for "<a " 
   else if(hasLT && !hasA && !hasF){ 
if(c=='a' || c=='A')hasA=true; 
else if(c=='f' || c=='F')hasF=true; 
else hasLT=false; 
   }else if(hasLT && hasA && !hasF &&!hasSp){ 
if(c==' ' || c=='\t' || c=='\n')hasSp=true; 
else hasLT = hasA = false; 
   } 
   
   //search for "<frame " 
   else if(hasLT && hasF && !hasA && !hasR){ 
if(c=='r' || c=='R')hasR=true; 
else hasLT = hasF = false; 
   }else if(hasLT && hasF && hasR && !hasA){ 
if(c=='a' || c=='A')hasA=true; 
else hasLT = hasF = hasR = false; 
   }else if(hasLT && hasF && hasR && hasA&& !hasM){ 
if(c=='m' || c=='M')hasM=true; 
else hasLT = hasF = hasR = hasA = false; 
   }else if(hasLT && hasF && hasR && hasA&& hasM && !hasE){ 
if(c=='e' || c=='E')hasE=true; 
else hasLT = hasF = hasR = hasA = hasM = false; 
   }else if(hasLT && hasF && hasR && hasA&& hasM && hasE && !hasSp){ 
if(c==' ' || c=='\t' || c=='\n')hasSp=true; 
else hasLT = hasF = hasR = hasA = hasM = hasE = false; 
   } 
     
   //found "<frame " 
   else if(hasLT && hasF && hasR && hasA&& hasM && hasE && hasSp){ 
hasLT = hasF = hasR = hasA = hasM = hasE = hasSp = false; 
beg = loc; 
loc = source.indexOf(">", loc); 
if(loc==-1){ 
     errors.insert("malformed frame at"+site.toString()); 
     loc = beg; 

else{ 
     try{ 
   parseFrame(site, source.substring(beg, loc)); 
     } 
     catch(Exception e){ 
   errors.insert("while parsing "+site.toString()+",error parsing frame: "+e.toString());
     } 

   } 
   
   //found "<a " 
   else if(hasLT && hasA && hasSp && !hasF){ 
hasLT = hasA = hasSp = false; 
beg = loc; 
loc = source.indexOf(">", loc); 
if(loc==-1){ 
     errors.insert("malformed linked at"+site.toString()); 
     loc = beg; 

else{ 
     try{ 
   parseLink(site, source.substring(beg, loc)); 
     } 
     catch(Exception e){ 
   errors.insert("while parsing "+site.toString()+",error parsing link: "+e.toString());
     } 

   } 

   } 
     
   /* 
   * parses a frame 
   */ 
   private void parseFrame(URL at_page, String s) throws Exception{ 
int beg=s.indexOf("src"); 
if(beg==-1)beg=s.indexOf("SRC"); 
if(beg==-1)return;//doesn't have a src, ignore 
beg = s.indexOf("=", beg); 
if(beg==-1)throw new Exception("while parsing"+at_page.toString()+", bad frame, missing \'=\' after src:"+s);
int start = beg; 
for(;beg<s.length();beg++){ 
   if(s.charAt(beg)=='\'')break; 
   if(s.charAt(beg)=='\"')break; 

int end=beg+1; 
for(;end<s.length();end++){ 
   if(s.charAt(beg)==s.charAt(end))break; 

beg++; 
if(beg>=end){//missing quotes... just take the first token after"src=" 
   for(beg=start+1;beg<s.length() && (s.charAt(beg)=='');beg++){} 
   for(end=beg+1;end<s.length() && (s.charAt(beg)!=' ')&& (s.charAt(beg)!='>');end++){}

   
if(beg>=end){ 
   errors.insert("while parsing "+at_page.toString()+",bad frame: "+s); 
   return; 

   
String linkto=s.substring(beg,end); 
if(linkto.startsWith("mailto:")||linkto.startsWith("Mailto:"))return;
if(linkto.startsWith("javascript:")||linkto.startsWith("Javascript:"))return;
if(linkto.startsWith("news:")||linkto.startsWith("Javascript:"))return;
try{ 
   addSite(new URL(at_page, linkto)); 
   return; 
}catch(Exception e1){} 
try{ 
   addSite(new URL(linkto)); 
   return; 
}catch(Exception e2){} 
try{ 
   URL cp = new URL(at_page.toString()+"/index.html"); 
   System.out.println("attemping to use "+cp); 
   addSite(new URL(cp, linkto)); 
   return; 
}catch(Exception e3){} 
errors.insert("while parsing "+at_page.toString()+", bad frame:"+linkto+", formed from: "+s);
   } 
   
   /* 
   * given a link at a URL, will parse it and add it to the list ofsites to do 
   */ 
   private void parseLink(URL at_page, String s) throws Exception{ 
//System.out.println("parsing link "+s); 
int beg=s.indexOf("href"); 
if(beg==-1)beg=s.indexOf("HREF"); 
if(beg==-1)return;//doesn't have a href, must be an anchor 
beg = s.indexOf("=", beg); 
if(beg==-1)throw new Exception("while parsing"+at_page.toString()+", bad link, missing \'=\' after href:"+s);
int start = beg; 
for(;beg<s.length();beg++){ 
   if(s.charAt(beg)=='\'')break; 
   if(s.charAt(beg)=='\"')break; 

int end=beg+1; 
for(;end<s.length();end++){ 
   if(s.charAt(beg)==s.charAt(end))break; 

beg++; 
if(beg>=end){//missing quotes... just take the first token after"href=" 
   for(beg=start+1;beg<s.length() && (s.charAt(beg)=='');beg++){} 
   for(end=beg+1;end<s.length() && (s.charAt(beg)!=' ')&& (s.charAt(beg)!='>');end++){}

   
if(beg>=end){ 
   errors.insert("while parsing"+at_page.toString()+", bad href: "+s); 
   return; 

   
String linkto=s.substring(beg,end); 
if(linkto.startsWith("mailto:")||linkto.startsWith("Mailto:"))return;
if(linkto.startsWith("javascript:")||linkto.startsWith("Javascript:"))return;
if(linkto.startsWith("news:")||linkto.startsWith("Javascript:"))return;
   
try{ 
   addSite(new URL(at_page, linkto)); 
   return; 
}catch(Exception e1){} 
try{ 
   addSite(new URL(linkto)); 
   return; 
}catch(Exception e2){} 
try{ 
   addSite(new URL(newURL(at_page.toString()+"/index.html"), linkto)); 
   return; 
}catch(Exception e3){} 
errors.insert("while parsing "+at_page.toString()+", bad link:"+linkto+", formed from: "+s);
   } 
   
   /* 
   * gets the title of a web page with content s 
   */ 
   private String getTitle(String s){ 
try{ 
   int beg=s.indexOf("<title>"); 
   if(beg==-1)beg=s.indexOf("<TITLE>"); 
   int end=s.indexOf("</title>"); 
   if(end==-1)end=s.indexOf("</TITLE>"); 
   return s.substring(beg,end); 

catch(Exception e){return "";} 
   } 
   
   /* 
   * gets the text of a web page, times out after 10s 
   */ 
   private String getText(URL site) throws Exception 
   { 
urlReader u = new urlReader(site); 
Thread t = new Thread(u); 
t.setDaemon(true); 
t.start(); 
t.join(TIMEOUT); 
String ret = u.poll(); 
if(ret==null){ 
throw new Exception("connection timed out"); 
}else if(ret.equals("Not html")){ 
throw new Exception("Not an HTML document"); 

return ret; 
   } 
   
   /* 
   * returns how many sites have been visited so far 
   */ 
   public int Visited(){return visitedsites;} 

   
class urlReader implements Runnable{ 
   URL site; 
   String s; 
   public urlReader(URL u){ 
site = u; 
s=null; 
   } 
   public void run(){ 
try{ 
   String ret=new String(); 
   URLConnection u = site.openConnection(); 
   String type = u.getContentType(); 
   if(type.indexOf("text")==-1 &&   
     type.indexOf("txt")==-1&&   
     type.indexOf("HTM")==-1&&   
     type.indexOf("htm")==-1){ 
//System.err.println("bad content type "+type+" at site"+site); 
System.out.println("bad content type "+type+" at site"+site); 
ret = "Not html"; 
return; 
   } 
   InputStream in = u.getInputStream(); 
   BufferedInputStream bufIn = new BufferedInputStream(in); 
   int data; 
   while(true){ 
data = bufIn.read(); 
// Check for EOF 
if (data == -1) break; 
else ret+= ( (char) data); 
   } 
   s = ret; 
}catch(Exception e){s=null;} 
   } 
   public String poll(){return s;} 

   
public class spidergui extends Frame{ 
   
private spider s; 
private Color txtColor; 
private Color errColor; 
private Color topColor; 
private Color numColor; 
private Color curColor; 
   
public spidergui(spider spi, String title){ 
super(title); 
curColor = new Color(40, 40, 200); 
txtColor = new Color(0, 0, 0); 
errColor = new Color(255, 0, 0); 
topColor = new Color(40, 40, 100); 
numColor = new Color(50, 150, 50); 
s=spi; 
setBounds(0, 0, 800, 600); 
show(); 
toFront(); 
repaint(); 

public void endShow(){ 
System.out.println(s); 
hide(); 
dispose(); 

public void paint(Graphics g){ 
super.paint(g); 
s.todo.reset(); 
s.done.reset(); 
s.errors.reset(); 
s.omittions.reset(); 
String txt; 
Object o; 
g.setColor(curColor); 
g.setFont(new Font("arial", Font.PLAIN, 18)); 
String cur = s.getCurrent(); 
if(cur.length()>80)g.drawString( 
   cur.substring(0, 40)+ 
   " . . . "+ 
   cur.substring(cur.length()-30, cur.length()), 
50, 50); 
else g.drawString(cur, 50, 50); 
   
g.setColor(numColor); 
g.setFont(new Font("arial", Font.BOLD, 24)); 
g.drawString(Integer.toString(s.Visited()), 350, 80); 
   
g.setFont(new Font("arial", Font.PLAIN, 14)); 
g.setColor(topColor); 
g.drawString("To Do:", 100, 80); 
g.drawString("Completed:", 500, 80); 
g.drawString("Ignored:", 500, 250); 
g.drawString("Errors:", 100, 420); 
   
g.setColor(txtColor); 
g.setFont(new Font("arial", Font.PLAIN, 12)); 
for(int i=0;i<23 && (o=s.todo.get())!=null;i++){ 
txt = Integer.toString(i+1) + ": "+o.toString(); 
if(txt.length()>65)g.drawString( 
   txt.substring(0, 38) + 
   " . . . " + 
   txt.substring(txt.length()-18, txt.length()), 
20, 100+13*i); 
else g.drawString(txt, 20, 100+13*i); 

for(int i=0;i<10 && (o=s.done.get())!=null;i++){ 
txt = Integer.toString(i+1) + ": "+o.toString(); 
if(txt.length()>60)g.drawString(txt.substring(0, 57)+"...", 400,100+13*i); 
else g.drawString(txt, 400, 100+13*i); 

for(int i=0;i<10 && (o=s.omittions.get())!=null;i++){ 
txt = Integer.toString(i+1) + ": "+o.toString(); 
if(txt.length()>60)g.drawString(txt.substring(0, 57)+"...", 400,270+13*i); 
else g.drawString(txt, 400, 270+13*i); 

g.setColor(errColor); 
for(int i=0;i<10 && (o=s.errors.get())!=null;i++){ 
txt = Integer.toString(i+1) + ": "+o.toString(); 
g.drawString(txt, 20, 440+13*i); 

   

public void run(){ 
repaint(); 
while(s.hasMore()){ 
repaint(); 
s.doNextSite(); 

repaint(); 

   
public static void main(String []args){ 
int max = 5; 
String site=""; 
String base=""; 
int time=0; 
for(int i=0;i<args.length;i++){ 
   if(args[i].startsWith("-max=")){ 
max=Integer.parseInt(args[i].substring(5,args[i].length())); 
   } 
   else if(args[i].startsWith("-time=")){ 
time=Integer.parseInt(args[i].substring(6,args[i].length())); 
   } 
   else if(args[i].startsWith("-init=")){ 
site=args[i].substring(6,args[i].length()); 
   } 
   else if(args[i].startsWith("-base=")){ 
base=args[i].substring(6,args[i].length()); 
   } 
   elseif(args[i].startsWith("-help")||args[i].startsWith("-?")){ 
System.out.println("additional command line switches:"); 
System.out.println("-max=N     : to limit to N sites,default 5"); 
System.out.println("-init=URL   : to set the initial site,REQUIRED"); 
System.out.println("-base=URL   : only follow url's that startwith this"); 
System.out.println("        default \"\" (matches all URLs)"); 
System.out.println("-time=N   : how many millisec to wait foreach page"); 
System.out.println("        default 5000 (5 seconds)"); 
System.exit(0); 
   } 
   else System.err.println("unrecognized switch:"+args[i]+", continuing"); 

if(site==""){ 
   System.err.println("No initial site parameter!"); 
   System.err.println("Use -init=<site> switch to set, or-help for more info."); 
   System.exit(1); 

   
spider spi=new spider(site, max, base); 
   
if(time>0)spi.setTimer(time); 
   
spidergui s = new spidergui(spi, "Spider: "+site); 
s.run(); 
System.out.println(spi); 

}

 

 

 

另一个实现:

这是一个web搜索的基本程序,从命令行输入搜索条件(起始的URL、处理url的最大数、要搜索的字符串), 
它就会逐个对Internet上的URL进行实时搜索,查找并输出匹配搜索条件的页面。 这个程序的原型来自《java编程艺术》, 
为了更好的分析,站长去掉了其中的GUI部分,并稍作修改以适用jdk1.5。以这个程序为基础,可以写出在互联网上搜索 
诸如图像、邮件、网页下载之类的“爬虫”。 
先请看程序运行的过程:


D:\java>javac SearchCrawler.java(编译)

D:\java>java   SearchCrawler http://127.0.0.1:8080/zz3zcwbwebhome/index.jsp20 java

Start searching... 
result: 
searchString=java 
http://127.0.0.1:8080/zz3zcwbwebhome/index.jsp
http://127.0.0.1:8080/zz3zcwbwebhome/reply.jsp
http://127.0.0.1:8080/zz3zcwbwebhome/learn.jsp
http://127.0.0.1:8080/zz3zcwbwebhome/download.jsp
http://127.0.0.1:8080/zz3zcwbwebhome/article.jsp
http://127.0.0.1:8080/zz3zcwbwebhome/myexample/jlGUIOverview.htm
http://127.0.0.1:8080/zz3zcwbwebhome/myexample/Proxooldoc/index.html
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=301
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=297
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=291
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=286
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=285
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=284
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=276
http://127.0.0.1:8080/zz3zcwbwebhome/view.jsp?id=272  

又如: 
D:\java>java    SearchCrawler http://www.sina.com20 java
Start searching... 
result: 
searchString=java 
http://sina.com 
http://redirect.sina.com/WWW/sinaCN/www.sina.com.cnclass=a2
http://redirect.sina.com/WWW/sinaCN/www.sina.com.cnclass=a8
http://redirect.sina.com/WWW/sinaHK/www.sina.com.hkclass=a2
http://redirect.sina.com/WWW/sinaTW/www.sina.com.twclass=a8
http://redirect.sina.com/WWW/sinaUS/home.sina.comclass=a8
http://redirect.sina.com/WWW/smsCN/sms.sina.com.cn/class=a2
http://redirect.sina.com/WWW/smsCN/sms.sina.com.cn/class=a3
http://redirect.sina.com/WWW/sinaNet/www.sina.net/class=a3


D:\java> 
下面是这个程序的源码 
Java代码 
import java.util.*; 
import java.Net.*; 
import java.io.*; 
import java.util.regex.*; 

// 搜索Web爬行者 
public class SearchCrawler implements Runnable{ 
   
/* disallowListCache缓存robot不允许搜索的URL。 Robot协议在Web站点的根目录下设置一个robots.txt文件, 
*规定站点上的哪些页面是限制搜索的。 搜索程序应该在搜索过程中跳过这些区域,下面是robots.txt的一个例子: 
# robots.txt for http://somehost.com/ 
   User-agent: * 
   Disallow: /cgi-bin/ 
   Disallow: /registration # /Disallow robots on registration page 
   Disallow: /login 
*/ 


private HashMap< String,ArrayList< String>> disallowListCache = newHashMap< String,ArrayList< String>>();  
ArrayList< String> errorList= new ArrayList< String>();//错误信息   
ArrayList< String> result=new ArrayList< String>(); //搜索到的结果   
String startUrl;//开始搜索的起点 
int maxUrl;//最大处理的url数 
String searchString;//要搜索的字符串(英文) 
boolean caseSensitive=false;//是否区分大小写 
boolean limitHost=false;//是否在限制的主机内搜索 
    
public SearchCrawler(String startUrl,int maxUrl,String searchString){ 
   this.startUrl=startUrl; 
   this.maxUrl=maxUrl; 
   this.searchString=searchString; 


   public ArrayList< String> getResult(){ 
       return result; 
   } 

public void run(){//启动搜索线程 
        
       crawl(startUrl,maxUrl,searchString,limitHost,caseSensitive); 

     

    //检测URL格式 
private URL verifyUrl(String url) { 
    // 只处理HTTP URLs. 
    if (!url.toLowerCase().startsWith("http://")) 
      return null; 

    URL verifiedUrl = null; 
    try { 
      verifiedUrl = new URL(url); 
    } catch (Exception e) { 
      return null; 
    } 

    return verifiedUrl; 


// 检测robot是否允许访问给出的URL. 
private boolean isRobotAllowed(URL urlToCheck) {   
    String host = urlToCheck.getHost().toLowerCase();//获取给出RUL的主机   
    //System.out.println("主机="+host);

    // 获取主机不允许搜索的URL缓存   
    ArrayList< String> disallowList=disallowListCache.get(host);   

    // 如果还没有缓存,下载并缓存。   
    if (disallowList == null) {   
      disallowList = new ArrayList<String>();   
      try {   
        URL robotsFileUrl =newURL("http://" + host + "/robots.txt");   
        BufferedReader reader =newBufferedReader(new InputStreamReader(robotsFileUrl.openStream()));  

        // 读robot文件,创建不允许访问的路径列表。   
        String line;   
        while ((line = reader.readLine()) !=null) {   
          if(line.indexOf("Disallow:") == 0) {//是否包含"Disallow:"  
            StringdisallowPath =line.substring("Disallow:".length());//获取不允许访问路径  

            // 检查是否有注释。   
            intcommentIndex = disallowPath.indexOf("#");   
            if(commentIndex != - 1) {   
             disallowPath =disallowPath.substring(0, commentIndex);//去掉注释   
           }   
              
            disallowPath= disallowPath.trim();   
           disallowList.add(disallowPath);   
           }   
         }   

        // 缓存此主机不允许访问的路径。   
        disallowListCache.put(host,disallowList);   
      } catch (Exception e) {   
             return true; //web站点根目录下没有robots.txt文件,返回真 
      }   
    }   

       
     String file = urlToCheck.getFile();   
     //System.out.println("文件getFile()="+file);
     for (int i = 0; i < disallowList.size(); i++){   
       String disallow =disallowList.get(i);   
       if (file.startsWith(disallow)){   
         return false;   
       }   
     }   
   
     return true;   
   }   
   
   
   
    
   private String downloadPage(URL pageUrl) { 
      try { 
         // Open connection to URL forreading. 
         BufferedReader reader = 
           newBufferedReader(new InputStreamReader(pageUrl.openStream())); 
   
         // Read page into buffer. 
         String line; 
         StringBuffer pageBuffer = newStringBuffer(); 
         while ((line =reader.readLine()) != null) { 
          pageBuffer.append(line); 
         } 
           
         return pageBuffer.toString(); 
      } catch (Exception e) { 
      } 
   
      return null; 
   } 
   
   // 从URL中去掉"www"
   private String removeWwwFromUrl(String url) { 
     int index = url.indexOf("://www."); 
     if (index != -1) { 
       return url.substring(0, index + 3) + 
         url.substring(index + 7); 
     } 
   
     return (url); 
   } 
   
   // 解析页面并找出链接 
   private ArrayList< String> retrieveLinks(URL pageUrl, StringpageContents, HashSet crawledList,
     boolean limitHost) 
   { 
     // 用正则表达式编译链接的匹配模式。 
Pattern p=    Pattern.compile("<a\\s+href\\s*=\\s*\"?(.*?)[\"|>]",Pattern.CASE_INSENSITIVE);
     Matcher m = p.matcher(pageContents); 
   
       
     ArrayList< String> linkList = new ArrayList<String>(); 
     while (m.find()) { 
       String link = m.group(1).trim(); 
         
       if (link.length() < 1) { 
         continue; 
       } 
   
       // 跳过链到本页面内链接。 
       if (link.charAt(0) == '#') { 
         continue; 
       } 
   
         
       if (link.indexOf("mailto:") !=-1) { 
         continue; 
       } 
        
       if(link.toLowerCase().indexOf("javascript") != -1) { 
         continue; 
       } 
   
       if (link.indexOf("://") == -1){ 
         if (link.charAt(0) == '/') {//处理绝对地    
           link ="http://" + pageUrl.getHost()+":"+pageUrl.getPort()+ link; 
         } else{           
           String file =pageUrl.getFile(); 
           if(file.indexOf('/') == -1) {//处理相对地址 
             link ="http://" + pageUrl.getHost()+":"+pageUrl.getPort() +"/" + link;
           } else { 
             Stringpath =file.substring(0, file.lastIndexOf('/') + 1); 
             link ="http://" + pageUrl.getHost() +":"+pageUrl.getPort()+ path+ link;
           } 
         } 
       } 
   
       int index = link.indexOf('#'); 
       if (index != -1) { 
         link = link.substring(0,index); 
       } 
   
       link = removeWwwFromUrl(link); 
   
       URL verifiedLink = verifyUrl(link); 
       if (verifiedLink == null) { 
         continue; 
       } 
   
       /* 如果限定主机,排除那些不合条件的URL*/ 
       if (limitHost && 
          !pageUrl.getHost().toLowerCase().equals( 
            verifiedLink.getHost().toLowerCase())) 
       { 
         continue; 
       } 
   
       // 跳过那些已经处理的链接. 
       if (crawledList.contains(link)) { 
         continue; 
       } 
   
        linkList.add(link); 
     } 
   
    return (linkList); 
   } 
   
// 搜索下载Web页面的内容,判断在该页面内有没有指定的搜索字符串 
   
   private boolean searchStringMatches(String pageContents, StringsearchString, boolean caseSensitive){
        String searchContents =pageContents;   
        if (!caseSensitive) {//如果不区分大小写 
           searchContents =pageContents.toLowerCase(); 
        } 
   
       
     Pattern p = Pattern.compile("[\\s]+"); 
     String[] terms = p.split(searchString); 
     for (int i = 0; i < terms.length; i++) { 
       if (caseSensitive) { 
         if(searchContents.indexOf(terms[i]) == -1) { 
           return false; 
         } 
       } else { 
         if(searchContents.indexOf(terms[i].toLowerCase()) == -1) { 
           return false; 
         } 
       }     } 
   
     return true; 
   } 
   
     
   //执行实际的搜索操作 
   public ArrayList< String> crawl(String startUrl, intmaxUrls, String searchString,boolean limithost,boolean caseSensitive )
   {   
       
    System.out.println("searchString="+searchString); 
     HashSet< String> crawledList = new HashSet<String>(); 
     LinkedHashSet< String> toCrawlList = newLinkedHashSet< String>(); 
   
      if (maxUrls < 1) { 
         errorList.add("InvalidMax URLs value."); 
        System.out.println("Invalid Max URLs value."); 
       } 
     
       
     if (searchString.length() < 1) { 
       errorList.add("Missing SearchString."); 
       System.out.println("Missing searchString"); 
     } 
   
       
     if (errorList.size() > 0) { 
       System.out.println("err!!!"); 
       return errorList; 
       } 
   
       
     // 从开始URL中移出www 
     startUrl = removeWwwFromUrl(startUrl); 
   
       
     toCrawlList.add(startUrl); 
     while (toCrawlList.size() > 0) { 
         
       if (maxUrls != -1) { 
         if (crawledList.size() ==maxUrls) { 
           break; 
         } 
       } 
   
       // Get URL at bottom of the list. 
       String url =toCrawlList.iterator().next(); 
   
       // Remove URL from the to crawl list. 
       toCrawlList.remove(url); 
   
       // Convert string url to URL object. 
       URL verifiedUrl = verifyUrl(url); 
   
       // Skip URL if robots are not allowed toaccess it. 
       if (!isRobotAllowed(verifiedUrl)) { 
         continue; 
       } 
   
       
       // 增加已处理的URL到crawledList 
       crawledList.add(url); 
       String pageContents =downloadPage(verifiedUrl); 
   
         
       if (pageContents != null &&pageContents.length() > 0){ 
         // 从页面中获取有效的链接 
         ArrayList< String> links=retrieveLinks(verifiedUrl, pageContents, crawledList,limitHost);
        
         toCrawlList.addAll(links); 
   
         if(searchStringMatches(pageContents, searchString,caseSensitive)) 
         { 
           result.add(url); 
          System.out.println(url); 
         } 
      } 
   
       
     } 
    return result; 
   } 
   
   // 主函数 
   public static void main(String[] args) { 
      if(args.length!=3){ 
         System.out.println("Usage:javaSearchCrawler startUrl maxUrl searchString");
         return; 
      } 
     int max=Integer.parseInt(args[1]); 
     SearchCrawler crawler = newSearchCrawler(args[0],max,args[2]); 
     Thread search=new Thread(crawler); 
     System.out.println("Start searching..."); 
     System.out.println("result:"); 
     search.start(); 
      
   } 
}

 

7
3

我的同类文章

  • Sogou的语料库的问题2013-04-16
  • 使用继续完善前人写的文章:使用ICTCLAS JAVA版(ictclas4j)进行中文分词2013-04-11
  • httpClient应用2011-11-04
  • 关于Heritrix的Extractor中文乱码2013-04-13
  • eclipse中配置heritrix的过程----heritrix-1.14.42013-03-06

参考知识库

img

JavaScript知识库

img

PHP知识库

img

.NET知识库

img

Java SE知识库

img

MySQL知识库

img

Java EE知识库

img

Java 知识库

img

jQuery知识库

img

算法与数据结构知识库

img

AngularJS知识库

猜你在找
ArcGIS for javascript 项目实战(环境监测系统)
ArcGIS for JavaScript
Java Swing、JDBC开发桌面级应用
Java分布式架构:EJB+消息中间件+CORBA高级
深入浅出Java的反射
java抓取java网络爬虫实例项目jnc
基于PythonPyQuery实现的一个网络爬虫实例
Java网络爬虫讲解
java---网络爬虫讲解
java访问站点 并实现简易网络爬虫
关闭
查看评论
4楼 P_HXT 2016-04-26 00:51发表 [回复]
你的第一个爬虫JAVA代码是不完全缺少Runnable和Frame两个类,编译这个spider这个类出现错误。
Re: lmhua369 2016-10-13 09:28发表 [回复]
回复P_HXT:Runnable是接口。。Frame改成JFrame
3楼 eson_15 2016-04-21 12:12发表 [回复]
不错
2楼 qq_30862263 2016-03-18 16:49发表 [回复]
请问下,您第二段代码是在什么环境下运行的,我用的是(MyEclipse10)
1楼 魅影银狐 2013-05-30 11:11发表 [回复]
对于一些脚本语言(如VBScript和javascript)生成的网页,您有深入的研究么?请问您是使用哪个JS引擎呢,又是怎样实现脚本解析的机制的呢?谢谢解答~
发表评论
  • 用 户 名:
  • qq_36948778
  • 评论内容:
  • 插入代码
  •   
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
核心技术类目
全部主题 Hadoop AWS 移动游戏 Java Android iOS Swift 智能硬件 Docker OpenStackVPN Spark ERP IE10 Eclipse CRM JavaScript 数据库 Ubuntu NFC WAP jQueryBI HTML5 Spring Apache .NET API HTML SDK IIS Fedora XML LBS UnitySplashtop UML components Windows Mobile Rails QEMU KDE Cassandra CloudStackFTC coremail OPhone CouchBase 云计算 iOS6 Rackspace Web App SpringSide MaemoCompuware 大数据 aptech Perl Tornado Ruby Hibernate ThinkPHP HBase Pure SolrAngular Cloud Foundry Redis Scala Django Bootstrap
  • 个人资料
  •  
    luojinping
     
    • 访问:126155次
    • 积分:1117
    • 等级: 
    • 排名:千里之外
    • 原创:14篇
    • 转载:24篇
    • 译文:0篇
    • 评论:31条
  • 文章分类
  • C++(9)
  • 算法(13)
  • 细节(1)
  • Linux(3)
  • 规划(1)
  • Java(2)
  • 主题爬虫(6)
  • 文章存档
    • 2013年04月(3)
    • 2013年03月(1)
    • 2012年07月(1)
    • 2012年06月(1)
    • 2012年05月(6)
      展开
  • 阅读排行
  • 网络爬虫讲解(附java实现的实例)(53307)
  • 硬盘安装CentOS6.2详解(8666)
  • 0-1背包问题的递归实现与非递归实现(7004)
  • 使用继续完善前人写的文章:使用ICTCLAS JAVA版(ictclas4j)进行中文分词(4745)
  • 最小生成树的prim算法贪心正确性的证明(4129)
  • vss服务器突然连接不上了,提示说does not contain a valid sourcesafe database(srcsafe.ini)(3962)
  • VS2008 安装失败(“Web 创作组件”无法)(3856)
  • STL容器的效率比较(3520)
  • java的所谓一次编译,到处运行(3487)
  • POJ1753——Flip Game(2790)
  • 评论排行
  • 使用继续完善前人写的文章:使用ICTCLAS JAVA版(ictclas4j)进行中文分词(7)
  • VS2008 安装失败(“Web 创作组件”无法)(6)
  • 0-1背包问题的递归实现与非递归实现(5)
  • 网络爬虫讲解(附java实现的实例)(5)
  • POJ1753——Flip Game(2)
  • 硬盘安装CentOS6.2详解(2)
  • POJ-1150(求排列数P(n,m)中最后一个非0的数字)(1)
  • 递归与非递归的比较(1)
  • Java中Runnable和Thread的区别(1)
  • 最小生成树的prim算法贪心正确性的证明(1)
  • 推荐文章
    • * Android-多列表的项目(Rxjava+Rtrofit+Recyclerview+Glide+Adapter封装)之(一)项目架构
    • * 为什么Go语言在中国格外的"火"
    • * Node.js websocket 使用 socket.io库实现实时聊天室
    • * CSDN日报20170219——《程序员的沟通之痛》
    • * iOS狂暴之路---视图控制器(UIViewController)使用详解
  • 最新评论
  • 网络爬虫讲解(附java实现的实例)

    lmhua369: @P_HXT:Runnable是接口。。Frame改成JFrame

  • 0-1背包问题的递归实现与非递归实现

    taoxiuxia: 当输入很大时也能够实现吗?比如说下面这个。输入: 背包容量 物品件数 物...

  • 网络爬虫讲解(附java实现的实例)

    P_HXT: 你的第一个爬虫JAVA代码是不完全缺少Runnable和Frame两个类,编译这个spider这个类...

  • 网络爬虫讲解(附java实现的实例)

    eson_15: 不错

  • 网络爬虫讲解(附java实现的实例)

    qq_30862263: 请问下,您第二段代码是在什么环境下运行的,我用的是(MyEclipse10)

  • Java中Runnable和Thread的区别

    慧强杨: 应该是三种

  • 使用继续完善前人写的文章:使用ICTCLAS JAVA版(ictclas4j)进行中文分词

    qq_26507137: @yangyang_1991good:分词的结果中不需要进行词性的标注打开.../src/org/i...

  • 使用继续完善前人写的文章:使用ICTCLAS JAVA版(ictclas4j)进行中文分词

    大号小白兔: 感谢博主分享

  • 使用继续完善前人写的文章:使用ICTCLAS JAVA版(ictclas4j)进行中文分词

    yangyang_1991good: 你好,我也是用的这个版本的分词系统,我想去掉分词词性标注,但是一直没有找到,你能告诉我是在哪里吗?

  • 使用继续完善前人写的文章:使用ICTCLAS JAVA版(ictclas4j)进行中文分词

    yangyang_1991good: 你好,我用的也是这个版本的,我想去掉分词词性标注,一直没有找到在哪个包里,你能告诉我吗?

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 从头开始之JSP+Servlet

    前言 本篇包括 Mac 下的 Eclipse 环境搭建&#xff0c;配置 Tomcat 服务器&#xff0c;一个简单的登录页面Demo&#xff0c;包括后台到数据库的一系列逻辑&#xff0c;以及使用到了这几天刚学的 AngularJS 做的页面。 因为 AngularJS4 版本太新了&#xff0c;中文官网没有足够…...

    2024/4/20 19:35:35
  2. 双眼皮手术过程

    ...

    2024/4/20 19:35:34
  3. vue入门

    1. Vue.js 1.1. Vue.js是什么? 1). 作用: 动态构建用户界面 2). 特点:* 遵循MVVM模式* 编码简洁, 体积小, 运行效率高, 移动/PC端开发* 它本身只关注UI, 可以轻松引入vue插件和其它第三库开发项目 3). 与其它框架的关联:* 借鉴angular的模板和数据绑定技术* 借鉴react的组件…...

    2024/4/30 18:04:33
  4. 内双怎么贴双眼皮是割还是埋线

    ...

    2024/4/30 18:12:37
  5. 割双眼皮要花多少钱

    ...

    2024/4/20 19:35:41
  6. 使用Spring Boot和Gradle创建AngularJS项目

    Spring Boot 是由 Pivotal 团队提供的全新框架&#xff0c;其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。 本文主要是记录使用 Spring Boot 和 Gradle 创建项目的过程&am…...

    2024/4/30 11:48:59
  7. 单眼皮变双眼皮方法

    ...

    2024/4/26 16:01:07
  8. AngularJS介绍

    AngularJS介绍–AngularJS的前世今生 AngularJS是什么 在Web开发领域&#xff0c;我们一般使用HTML作为前端页面元素的声明式语言&#xff0c;使用CSS技术作为展示样式的描述语言&#xff0c;JavaScript作为业务处理交互的命令式语言。当我们构建非常复杂的Web应用时&#xff0…...

    2024/4/30 18:31:05
  9. 深圳割做双眼皮哪家好

    ...

    2024/4/30 17:55:47
  10. Spring Boot gradle

    最近有写一个电子订单商务网站&#xff0c;使用JAVA8,SPRING,ANGULARJS对项目使用的技术和大家分享。 第一次写博客&#xff0c;哪有不对需要改正的请联系改正。 因为是项目是我给别人做的无法提供源码见谅&#xff0c;我尽最大努力让大家能看懂。 首先从项目的构建开始&#x…...

    2024/4/30 6:59:40
  11. 韩式双眼皮多少钱

    ...

    2024/4/20 5:58:11
  12. 双眼皮微创

    ...

    2024/4/20 19:36:07
  13. angular-cli 无法启动项目

    2019独角兽企业重金招聘Python工程师标准>>> 全局安装的angular-cli 和项目安装的angular-cli版本一致&#xff0c;才可以使用ng serve 否则只能用npm strat启动 转载于:https://my.oschina.net/u/3261598/blog/1551505...

    2024/4/30 18:13:56
  14. 整容双眼皮多少钱

    ...

    2024/4/25 5:58:34
  15. Angular(一)——使用angular-cli创建新项目

    1&#xff0c;安装 cnpm install -g angular/cli 2&#xff0c;创建 ng new ng-project 3&#xff0c;安装依赖 cd ng-project cnpm install 4&#xff0c;启动 ng serve --open 5&#xff0c;更名 我尝试改变项目名称&#xff0c;把package.json里的name改掉&#xff0c;又把文…...

    2024/4/20 4:12:30
  16. 单眼皮自然变韩式微创双眼皮多少钱

    ...

    2024/4/30 17:47:57
  17. angular-cli 安装与使用

    安装Angular CLI 1.首先确认安装了node.js和npm // 显示当前node和npm版本 $ node -v $ npm -v // node 版本高于6.9.3 npm版本高于3.0.0 2.全局安装typescript&#xff08;可选&#xff09; $ npm install -g typescript // 新建项目的时候会自动安装typescript(非全局)所以…...

    2024/4/20 19:35:59
  18. 如何下载Angular-Cli并下载运行项目

    1、安装angular/cli npm install -g angular/cli2、创建项目 ng new hum3、切换路径 cd hum4、运行项目 ng serve --open5、查看项目http://localhost:4200/...

    2024/4/20 19:36:05
  19. 切割割双眼皮一般多少钱

    ...

    2024/4/20 19:36:05
  20. Angular-cli 搭建项目

    一、首先需要安装node和npm 查看你的node以及npm版本&#xff1a; node -v 查看node版本 npm -v 查看npm版本 要求所有版本都是最新的&#xff0c;不然可能会出错。 设置淘宝镜像&#xff0c;这样下载东西就是从国内网站下载了&#xff0c;网速更快 npm configset registry htt…...

    2024/4/20 19:36:03

最新文章

  1. 4月水过去了,以此文警醒自己(

    4月没写文章&#xff0c;可恶...

    2024/4/30 19:03:00
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. Vue通过自定义指令实现元素平滑上升的动画效果(可以自定义动画时间、动画效果、动画速度等等)。

    1、演示 2、介绍 这个指令不是原生自带的&#xff0c;需要手动去书写&#xff0c;但是这辈子只需要编写这一次就好了&#xff0c;后边可以反复利用。 3、关键API IntersectionObserver IntersectionObserver 是一个用于监测元素是否进入或离开视口&#xff08;viewport&#x…...

    2024/4/30 3:06:26
  4. K8S容器空间不足问题分析和解决

    如上图&#xff0c;今天测试环境的K8S平台出现了一个问题&#xff0c;其中的一个容器报错&#xff1a;Free disk space below threshold. Available: 3223552 bytes (threshold: 10485760B)&#xff0c;意思服务器硬盘空间不够了。这个问题怎么产生的&#xff0c;又怎么解决的呢…...

    2024/4/30 17:15:32
  5. 【C++】类和对象①(什么是面向对象 | 类的定义 | 类的访问限定符及封装 | 类的作用域和实例化 | 类对象的存储方式 | this指针)

    目录 前言 什么是面向对象&#xff1f; 类的定义 类的访问限定符及封装 访问限定符 封装 类的作用域 类的实例化 类对象的存储方式 this指针 结语 前言 最早的C版本&#xff08;C with classes&#xff09;中&#xff0c;最先加上的就是类的机制&#xff0c;它构成…...

    2024/4/30 2:14:48
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/29 23:16:47
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/30 18:14:14
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/30 18:21:48
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/30 9:43:22
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57