- 浏览: 1653621 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (405)
- C/C++ (16)
- Linux (60)
- Algorithm (41)
- ACM (8)
- Ruby (39)
- Ruby on Rails (6)
- FP (2)
- Java SE (39)
- Java EE (6)
- Spring (11)
- Hibernate (1)
- Struts (1)
- Ajax (5)
- php (2)
- Data/Web Mining (20)
- Search Engine (19)
- NLP (2)
- Machine Learning (23)
- R (0)
- Database (10)
- Data Structure (6)
- Design Pattern (16)
- Hadoop (2)
- Browser (0)
- Firefox plugin/XPCOM (8)
- Eclise development (5)
- Architecture (1)
- Server (1)
- Cache (6)
- Code Generation (3)
- Open Source Tool (5)
- Develope Tools (5)
- 读书笔记 (7)
- 备忘 (4)
- 情感 (4)
- Others (20)
- python (0)
最新评论
-
532870393:
请问下,这本书是基于Hadoop1还是Hadoop2?
Hadoop in Action简单笔记(一) -
dongbiying:
不懂呀。。
十大常用数据结构 -
bing_it:
...
使用Spring MVC HandlerExceptionResolver处理异常 -
一别梦心:
按照上面的执行,文件确实是更新了,但是还是找不到kernel, ...
virtualbox 4.08安装虚机Ubuntu11.04增强功能失败解决方法 -
dsjt:
楼主spring 什么版本,我的3.1 ,xml中配置 < ...
使用Spring MVC HandlerExceptionResolver处理异常
今天我们来看看Nutch的源代码中的protocol-http插件,是如何抓取和下载web页面的。protocol-http就两个类HttpRespose和Http类,其中HttpRespose主要是向web服务器发请求来获取响应,从而下载页面。Http类则非常简单,其实可以说是HttpResponse的一个Facade,设置配置信息,然后创建HttpRespose。用户似乎只需要和Http类打交道就行了(我也没看全,所以只是猜测)。
我们来看看HttpResponse类:
看这个类的源码需要从构造函数
public HttpResponse(HttpBase http, URL url, CrawlDatum datum) throws ProtocolException, IOException开始
首先判断协议是否为http
if (!"http".equals(url.getProtocol())) throw new HttpException("Not an HTTP url:" + url);
获得路径,如果url.getFile()的为空直接返回”/”,否则返回url.getFile()
String path = "".equals(url.getFile()) ? "/" : url.getFile();
然后根据url获取到主机名和端口名。如果端口不存在,则端口默认为80,请求的地址将不包括端口号portString= "",否则获取到端口号,并得到portString
String host = url.getHost(); int port; String portString; if (url.getPort() == -1) { port= 80; portString= ""; } else { port= url.getPort(); portString= ":" + port; }
然后创建socket,并且设置连接超时的时间:
socket = new Socket(); // create the socket socket.setSoTimeout(http.getTimeout());
根据是否使用代理来得到socketHost和socketPort:
String sockHost = http.useProxy() ? http.getProxyHost() : host; int sockPort = http.useProxy() ? http.getProxyPort() : port;
创建InetSocketAddress,并且开始建立连接:
InetSocketAddress sockAddr= new InetSocketAddress(sockHost, sockPort); socket.connect(sockAddr, http.getTimeout());
获取输入流:
// make request OutputStream req = socket.getOutputStream();
以下代码用来向服务器发Get请求:
StringBuffer reqStr = new StringBuffer("GET "); if (http.useProxy()) { reqStr.append(url.getProtocol()+"://"+host+portString+path); } else { reqStr.append(path); } reqStr.append(" HTTP/1.0\r\n"); reqStr.append("Host: "); reqStr.append(host); reqStr.append(portString); reqStr.append("\r\n"); reqStr.append("Accept-Encoding: x-gzip, gzip\r\n"); String userAgent = http.getUserAgent(); if ((userAgent == null) || (userAgent.length() == 0)) { if (Http.LOG.isFatalEnabled()) { Http.LOG.fatal("User-agent is not set!"); } } else { reqStr.append("User-Agent: "); reqStr.append(userAgent); reqStr.append("\r\n"); } reqStr.append("\r\n"); byte[] reqBytes= reqStr.toString().getBytes(); req.write(reqBytes); req.flush();
接着来处理相应,获得输入流并且包装成PushbackInputStream来方便操作:
PushbackInputStream in = // process response new PushbackInputStream( new BufferedInputStream(socket.getInputStream(), Http.BUFFER_SIZE), Http.BUFFER_SIZE) ;
提取状态码和响应中的HTML的header:
boolean haveSeenNonContinueStatus= false; while (!haveSeenNonContinueStatus) { // parse status code line this.code = parseStatusLine(in, line); // parse headers parseHeaders(in, line); haveSeenNonContinueStatus= code != 100; // 100 is "Continue" }
接着读取内容:
readPlainContent(in);
获取内容的格式,如果是压缩的则处理压缩
String contentEncoding = getHeader(Response.CONTENT_ENCODING); if ("gzip".equals(contentEncoding) || "x-gzip".equals(contentEncoding)) { content = http.processGzipEncoded(content, url); } else { if (Http.LOG.isTraceEnabled()) { Http.LOG.trace("fetched " + content.length + " bytes from " + url); } }
整个过程结束。
下面我们来看看parseStatusLine parseHeaders readPlainContent以及readChunkedContent的过程。
private int parseStatusLine(PushbackInputStream in, StringBuffer line)
throws IOException, HttpException:
这个函数主要来提取响应得状态,例如200 OK这样的状态码:
请求的状态行一般格式(例如响应Ok的话) HTTP/1.1 200" 或 "HTTP/1.1 200 OK
int codeStart = line.indexOf(" "); int codeEnd = line.indexOf(" ", codeStart+1);
如果是第一种情况:
if (codeEnd == -1) codeEnd = line.length();
状态码结束(200)位置便是line.length()
否则状态码结束(200)位置就是line.indexOf(" ", codeStart+1);
接着开始提取状态码:
int code; try { code= Integer.parseInt(line.substring(codeStart+1, codeEnd)); } catch (NumberFormatException e) { throw new HttpException("bad status line '" + line + "': " + e.getMessage(), e); }
下面看看
private void parseHeaders(PushbackInputStream in, StringBuffer line) throws IOException, HttpException:
这个函数主要是将响应的headers加入我们已经建立的结构header的Metadata中。
一个循环读取headers:
一般HTTP response的header部分和内容部分会有一个空行,使用readLine如果是空行就会返回读取的字符数为0,具体readLine实现看完这个函数在仔细看:
while (readLine(in, line, true) != 0)
如果没有空行,那紧接着就是正文了,正文一般会以<!DOCTYPE、<HTML、<html开头。如果读到的一行中包含这个,那么header部分就读完了。
// handle HTTP responses with missing blank line after headers int pos; if ( ((pos= line.indexOf("<!DOCTYPE")) != -1) || ((pos= line.indexOf("<HTML")) != -1) || ((pos= line.indexOf("<html")) != -1) )
接着把多读的那部分压回流中,并设置那一行的长度为pos
in.unread(line.substring(pos).getBytes("UTF-8")); line.setLength(pos);
接着把对一行的处理委托给processHeaderLine(line)来处理:
try { //TODO: (CM) We don't know the header names here //since we're just handling them generically. It would //be nice to provide some sort of mapping function here //for the returned header names to the standard metadata //names in the ParseData class processHeaderLine(line); } catch (Exception e) { // fixme: e.printStackTrace(LogUtil.getErrorStream(Http.LOG)); } return; } processHeaderLine(line);
下面我们看看如何处理一行header的:
private void processHeaderLine(StringBuffer line)
throws IOException, HttpException
请求的头一般格式:
Cache-Control: private
Date: Fri, 14 Dec 2007 15:32:06 GMT
Content-Length: 7602
Content-Type: text/html
Server: Microsoft-IIS/6.0
这样我们就比较容易理解下面的代码了:
int colonIndex = line.indexOf(":"); // key is up to colon
如果没有”:”并且这行不是空行则抛出HttpException异常
if (colonIndex == -1) { int i; for (i= 0; i < line.length(); i++) if (!Character.isWhitespace(line.charAt(i))) break; if (i == line.length()) return; throw new HttpException("No colon in header:" + line); }
否则,可以可以提取出键-值对了:
key为0~colonIndex部分,然后过滤掉开始的空白字符,作为value部分。
最后放到headers中:
String key = line.substring(0, colonIndex); int valueStart = colonIndex+1; // skip whitespace while (valueStart < line.length()) { int c = line.charAt(valueStart); if (c != ' ' && c != '\t') break; valueStart++; } String value = line.substring(valueStart); headers.set(key, value);
下面我们看看用的比较多的辅助函数
private static int readLine(PushbackInputStream in, StringBuffer line,
boolean allowContinuedLine) throws IOException
代码的实现:
开始设置line的长度为0不断的读,直到c!=-1,对于每个c:
如果是\r并且下一个字符是\n则读入\r,如果是\n,并且如果line.length() > 0,也就是这行前面已经有非空白字符,并且还允许连续行,在读一个字符,如果是’ ’或者是\t说明此行仍未结束,读入该字符,一行结束,返回读取的实际长度。其他情况下直接往line追加所读的字符:
line.setLength(0); for (int c = in.read(); c != -1; c = in.read()) { switch (c) { case '\r': if (peek(in) == '\n') { in.read(); } case '\n': if (line.length() > 0) { // at EOL -- check for continued line if the current // (possibly continued) line wasn't blank if (allowContinuedLine) switch (peek(in)) { case ' ' : case '\t': // line is continued in.read(); continue; } } return line.length(); // else complete default : line.append((char)c); } } throw new EOFException(); }
接着看如何读取内容的,也就是
private void readPlainContent(InputStream in)
throws HttpException, IOException的实现:
首先从headers(在此之前已经读去了headers放到metadata中了)中获取响应的长度,
int contentLength = Integer.MAX_VALUE; // get content length String contentLengthString = headers.get(Response.CONTENT_LENGTH); if (contentLengthString != null) { contentLengthString = contentLengthString.trim(); try { contentLength = Integer.parseInt(contentLengthString); } catch (NumberFormatException e) { throw new HttpException("bad content length: "+contentLengthString); } }
如果大于http.getMaxContent()(这个值在配置文件中http.content.limit来配置),
则截取maxContent那么长的字段:
if (http.getMaxContent() >= 0 && contentLength > http.getMaxContent()) // limit download size contentLength = http.getMaxContent(); ByteArrayOutputStream out = new ByteArrayOutputStream(Http.BUFFER_SIZE); byte[] bytes = new byte[Http.BUFFER_SIZE]; int length = 0; // read content for (int i = in.read(bytes); i != -1; i = in.read(bytes)) { out.write(bytes, 0, i); length += i; if (length >= contentLength) break; } content = out.toByteArray(); }
今天就写到这了。
评论
3 楼
wind_bell
2008-06-25
楼主研究的应该是nutch0.7
2 楼
fuliang
2008-03-17
我是用svn直接checkout出来的源代码.
svn地址:http://svn.apache.org/repos/asf/lucene/nutch
直接下载的没有插件那部分的源代码.
svn地址:http://svn.apache.org/repos/asf/lucene/nutch
直接下载的没有插件那部分的源代码.
1 楼
sharong
2008-03-17
楼主研究的nutch是哪个版本啊,在nutch0.9里怎么找不到相应代码
发表评论
-
Lucene 索引格式
2013-06-25 20:11 0索引结构: 索引层次 ... -
计算广告学
2012-08-12 13:53 0计算广告学一: 1、核 ... -
《Lucene in Action》简单笔记
2011-12-22 09:19 0第一章 Meet Lucene -
Information Retrieval Resources
2011-04-07 16:40 1388Information Retrieval Resource ... -
使用Jsoup抽取数据
2011-03-20 19:22 4946Jsoup是一个Java的HTML解析器,提供了非常方便的抽取 ... -
常见文件类型识别
2010-09-22 20:09 11879根据文件的后缀名识别文件类型并不准确,可以使用文件的头信息进行 ... -
(zz)信息检索领域资料整理
2010-06-05 13:05 3171A Guide to Information Retrieva ... -
Introduce to Inforamtion Retrieval读书笔记(2)
2009-10-31 13:02 1935The term vocabulary and posting ... -
Introduce to Inforamtion Retrieval读书笔记(1)
2009-10-25 23:49 2052很好的一本书,介绍的非常全面,看了很久了,还没有看完,刚看完前 ... -
Query Log Mining notes
2009-10-02 18:08 1272Enhancing Efficiency of Search ... -
百度搜索的一些高级语法
2009-08-27 20:06 19321.title语法 就是在title ... -
Hadoop好书推荐:Hadoop The Definitive Guide
2009-08-16 22:49 3639第一本详细介绍Hadoop的书籍,从网上下来看了几章,作者是H ... -
Java开源搜索引擎[收藏]
2008-04-24 00:09 2903Egothor Egothor是一个用Java编写的开 ... -
分享一本斯坦福的信息检索的教材
2008-01-04 23:59 2463斯坦福的信息检索的教材,还没出版,先分享一下电子版原稿. 对于 ... -
分享一本搜索引擎的电子书
2007-12-29 19:42 2530还没有来得及看,但搜索引擎的书不是很好找,先放上,希望对大家能 ... -
分享一个Nutch入门学习的资料
2007-12-18 20:49 4266分享一个Nutch入门学习的资料,感觉写的还不错. -
搜索引擎Nutch源代码研究之一 网页抓取(4)
2007-12-17 22:37 8397今天来看看Nutch如何Parse网页的: Nutch使用了两 ... -
[转]MAP/REDUCE:Google和Nutch实现异同及其他
2007-12-15 19:21 2997设计要素 nutch包含以下几个部分: 辅助类 Log:记载运 ... -
Nutch源代码学习小小总结一下
2007-12-15 19:13 4468我现在看得源码主要是网页抓取部分,这部分相对比较容易。我首先定 ... -
搜索引擎Nutch源代码研究之一 网页抓取(3)
2007-12-15 16:39 4586今天我们看看Nutch网页抓取,所用的几种数据结构: 主要涉及 ...
相关推荐
从Apache官方网站下载Nutch的最新源代码,通常通过Git克隆仓库。解压后,进入Nutch的工作目录。 3. **配置Nutch** 打开`conf/nutch-site.xml`文件,这是Nutch的主要配置文件。以下是一些关键配置项: - `...
2. **Nutch源代码**:包括Nutch的爬虫模块、索引模块和搜索模块,可以帮助开发者学习如何配置和运行一个完整的网络爬虫,以及如何与Lucene集成进行全文检索。 3. **示例项目**:可能包含了一些示例应用,展示如何...
Nutch不仅仅是一个搜索引擎,它还包含了一个Web爬虫,能够抓取互联网上的网页,并对抓取的数据进行索引和处理。 Nutch的源代码包含了整个项目的完整实现,包括爬虫、索引器、搜索器以及相关的配置和文档。这对于...
Nutch 的源代码解析对于深入理解搜索引擎的工作原理以及自定义搜索引擎的实现非常有帮助。下面我们将详细探讨 Nutch 的注入(Injector)过程,这是整个爬取流程的第一步。 Injector 类在 Nutch 中的作用是将输入的 ...
总的来说,王学松的“Lucene+Nutch搜索引擎开发实例代码”是一份宝贵的教育资源,它可以帮助开发者快速入门搜索引擎开发,并深入了解这两个项目的内部工作机制。通过实践这些代码,不仅可以提升技术能力,还能为构建...
《lucene+nutch搜索引擎开发源码1》是一个包含开源搜索引擎项目Lucene和Nutch源代码的压缩包,主要针对搜索引擎开发的学习和实践。这个压缩包是书籍《lucene+nutch搜索引擎开发》的一部分,由于源码量较大,因此分为...
分布式搜索引擎Nutch开发详解 Nutch是一款开源的、基于Java实现的全文搜索引擎,它主要用于构建大规模的网络爬虫系统,并提供了对抓取的网页进行索引和搜索的功能。Nutch与Hadoop紧密集成,能够充分利用分布式计算...
《lucene+nutch开发自己的搜索引擎一书源代码》是一份专为初学者设计的资源,旨在教授如何利用Apache Lucene和Nutch构建自定义搜索引擎。Lucene是Java编写的一个高性能全文检索库,而Nutch则是一个开源的网络爬虫...
Nutch 1.5 是一个基于Java开发的开源搜索引擎项目,它主要负责网络抓取、索引和搜索等功能。这个源代码包包含了实现这些功能的所有模块和组件,为开发者提供了深入理解搜索引擎工作原理以及定制化搜索引擎的机会。接...
Nutch是Apache软件基金会的一个开源项目,主要用于构建网络搜索引擎。这个开发资料压缩包包含了与Nutch相关的源代码和可能的配置文件,可以帮助开发者深入了解和学习Nutch的工作原理以及如何进行定制化开发。以下是...
Lucene 是一个全文搜索引擎库,而 Nutch 是一个完整的网络爬虫项目,两者结合可以提供从网页抓取到索引、搜索的一站式解决方案。 在开发自定义搜索引擎的过程中,首先我们需要了解 **Lucene** 的基本原理。Lucene ...
1. **Java编程基础**:由于Nutch是用Java编写的,因此理解和修改Nutch源代码需要扎实的Java基础知识。 2. **搜索引擎原理**:理解搜索引擎的基本工作流程,包括爬虫、预处理、索引和查询处理。 3. **Hadoop和...
2. **Nutch**: Nutch是一个开放源代码的网络爬虫,主要用于抓取和索引网页内容。它基于Lucene,提供了完整的爬虫解决方案,包括网页抓取、预处理(如HTML解析、链接分析、去重等)、索引和搜索功能。Nutch的主要优势...
Nutch 是一个开源的搜索引擎项目,它提供了网络爬虫、索引和搜索的功能。在构建一个自定义的搜索引擎时,可能会遇到几个常见的问题,如搜索结果的关键词高亮、快照链接无效以及网页在预览时的变形。下面将详细讨论...
《Lucene+Nutch搜索引擎开发》是一本专注于搜索引擎技术的书籍,配套光盘资源为学习者提供了丰富的实践材料,尤其对于想要深入理解Nutch搜索引擎开发的读者来说,这是一份不可多得的学习资料。Nutch是基于Apache ...
总之,Nutch是一个强大的开源搜索引擎工具,它不仅适用于构建自己的搜索引擎,也是研究和学习搜索引擎技术的理想平台。通过熟悉其工作流程、分析源代码以及查阅相关文档,你将能够掌握搜索引擎的核心技术和实现细节...
Apache Nutch 是一款高度可扩展的开源全文搜索引擎框架,它为构建自定义的网络爬虫和搜索引擎提供了强大的工具集。Nutch 的设计目标是处理大量网页数据,进行高效的抓取、索引和搜索操作。在“apache-nutch-1.4-src....
- **配置 Nutch 创建索引**:下载 Nutch 的源代码并解压,然后通过 Maven 进行编译。配置 Nutch 的 `conf/nutch-site.xml` 文件以设置存储路径、抓取策略等参数。 - **安装 Tomcat**:Tomcat 用于运行 Nutch 的 UI...
在使用Nutch之前,你需要配置Nutch的运行环境,包括安装Java、设置Hadoop(如果需要分布式爬取)、下载和编译Nutch源代码。还需要配置Nutch的`conf/nutch-site.xml`文件,指定抓取策略、存储路径、爬虫范围等参数。 ...