`
brunoplum
  • 浏览: 14456 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

基于Spindle的增强HTTP Spider

阅读更多
   构建于lucene之上的可用的Java开源Spider少之又少,spindle长期没有更新且功能不够完善,故而自己参考其源代码重新编写了一个可扩展的WebCrawler,本着开源共享,共同进步的想法发布于此,期冀得到大家的批评指正,有任何意见及建议均可Email联系我 (kaninebruno@hotmail.com)
   以下代码基于lucene-2.3.1,htmlparser-1.6,je-analysis-1.5.3,以及自己修改过的cpdetector-1.0.5;
下载地址分别为
htmlparser:http://sourceforge.net/project/showfiles.php?group_id=24399
je-analysis:http://www.jesoft.cn/je-analysis-1.5.3.jar
lucene就不用说了,cpdetector-1.0.5见附件.
(应部分网友要求,把所用到的工具打包成一个spider.rar,方便下载测试)
spindle的官方站点:http://www.bitmechanic.com/projects/spindle/
主类SiteCapturer代码如下:
package com.huizhi.kanine.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashSet;

import jeasy.analysis.MMAnalyzer;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.DateTools;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;
import org.htmlparser.Parser;
import org.htmlparser.PrototypicalNodeFactory;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.tags.BaseHrefTag;
import org.htmlparser.tags.FrameTag;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.tags.MetaTag;
import org.htmlparser.util.EncodingChangeException;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

/**
 * @author 张波 
 * E-mail:kaninebruno@hotmail.com 
 * Created On : 2008-03-30
 * Updated On : 2008-04-06
 */

public class SiteCapturer implements Runnable {

	/* 基准(初始)URL */
	protected URL baseURL = null;

	/* 索引文件或抓取页面的存放位置 */
	protected String indexDir = null;

	/**
	 * 待解析的URL地址集合,所有新检测到的链接均存放于此;
	 * 解析时按照先入先出(First-In First-Out)法则线性取出
	 */
	protected ArrayList URLs = new ArrayList();

	/* 已索引的URL地址集合,避免链接的重复抓取 */
	protected HashSet indexedURLs = new HashSet();

	protected Parser parser = new Parser();;

	/* 程序运行线程数,默认2个线程 */
	protected int threads = 2;

	/* 存储于磁盘的IndexWriter */
	protected IndexWriter FSDWriter;

	/* 存储于内存的IndexWriter */
	protected IndexWriter RAMWriter;

	protected IndexSearcher indexSearcher;

	protected RAMDirectory ramDirectory = new RAMDirectory();

	/* 筛选页面内容的分词器 */
	protected Analyzer luceneAnalyzer = new MMAnalyzer();

	/* 解析页面时的字符编码 */
	protected String charset;

	/* 基准端口 */
	protected int basePort;

	/* 基准主机 */
	protected String baseHost;
	
	/* 是否索引,默认true */
	protected boolean justIndex = true;

	/* 是否保存,默认false */
	protected boolean justCopy = false;

	/* 检测索引中是否存在当前URL信息,避免重复抓取 */
	protected boolean isRepeatedCheck = false;

	/* 索引操作的写入线程锁 */
	public static final Object indexLock = new Object();

	public static Logger logger = Logger
			.getLogger(SiteCapturer.class.getName());

	public SiteCapturer() {
		PrototypicalNodeFactory factory = new PrototypicalNodeFactory();
		factory.registerTag(new LocalLinkTag());
		factory.registerTag(new LocalFrameTag());
		factory.registerTag(new LocalBaseHrefTag());
		parser.setNodeFactory(factory);
	}

	/**
	 * 程序入口,在此初始化mPages、IndexWriter
	 * 通过协调各线程间的活动完成website的抓取工作
	 * 任务完成后将所有的索引片段合并为一个以优化检索
	 */
	public void capture() {

		URLs.clear();
		URLs.add(getBaseURL());

		int responseCode = 0;
		String contentType = "";

		PropertyConfigurator.configure("/log4j.properties");
		
		try {
			HttpURLConnection uc = (HttpURLConnection) baseURL.openConnection();
			responseCode = uc.getResponseCode();
			contentType = uc.getContentType();
		} catch (MalformedURLException mue) {
			logger.error("Invalid URL : " + getBaseURL());
		} catch (UnknownHostException uhe) {
			logger.error("UnknowHost : " + getBaseURL());
		} catch (SocketException se) {
			logger.error("Socket Error : " + se.getMessage() + " "
					+ getBaseURL());
		} catch (IOException ie) {
			logger.error("IOException : " + ie);
		}
		
		if (responseCode == HttpURLConnection.HTTP_OK
				&& contentType.startsWith("text/html")) {
			
			charset = ParserUtils.autoDetectCharset(baseURL);

			basePort = baseURL.getPort();
			baseHost = baseURL.getHost();
			if (charset.equals("windows-1252"))
				charset = "GBK";
			
			/* 存放索引文件的位置 */
			File indexDirectory = new File(indexDir);
			/* 标记是否重新建立索引,true为重新建立索引 */
			boolean flag = true;
			if (!indexDirectory.exists()) {
				/* 如果文件夹不存在则创建 */
				indexDirectory.mkdir();
			} else if (IndexReader.indexExists(indexDirectory)) {
				/* 如果已存在索引,则追加索引 */
				flag = false;
				File lockfile = new File(indexDirectory + File.separator
						+ "write.lock");
				if (lockfile.exists())
					lockfile.delete();
			}
			try {
				if (justIndex) {
					FSDWriter = new IndexWriter(indexDirectory, luceneAnalyzer,
							flag);
					RAMWriter = new IndexWriter(ramDirectory, luceneAnalyzer,
							true);
					if (isRepeatedCheck) {
						IndexReader indexReader = IndexReader.open(indexDir);
						indexSearcher = new IndexSearcher(indexReader);
					}
				}
				long start = System.currentTimeMillis();
				ArrayList threadList = new ArrayList();
				for (int i = 0; i < threads; i++) {
					Thread t = new Thread(this, "K-9 Spider Thread #" + (i + 1));
					t.start();
					threadList.add(t);
				}
				while (threadList.size() > 0) {
					Thread child = (Thread) threadList.remove(0);
					try {
						child.join();
					} catch (InterruptedException ie) {
						logger.error("InterruptedException : " + ie);
					}
				}
				long elapsed = System.currentTimeMillis() - start;
				if (justIndex) {
					RAMWriter.close();
					FSDWriter.addIndexes(new Directory[] { ramDirectory });
					FSDWriter.optimize();
					FSDWriter.close();
				}
				logger.info("Finished in " + (elapsed / 1000) + " seconds");
				logger.info("The Count of the Links Captured is "
						+ indexedURLs.size());
			} catch (CorruptIndexException cie) {
				logger.error("CorruptIndexException : " + cie);
			} catch (LockObtainFailedException lofe) {
				logger.error("LockObtainFailedException : " + lofe);
			} catch (IOException ie) {
				logger.error("IOException : " + ie);
			}
		}
	}

	public void run() {
		String url;
		while ((url = dequeueURL()) != null) {
			if (justIndex)
				process(url);
		}
		threads--;
	}

	/**
	 * 判断提取到的链接是否符合解析条件;标准为Port及Host与基准URL相同且类型为text/html或text/plain
	 */
	public boolean isToBeCaptured(String url) {
		boolean flag = false;

		HttpURLConnection uc = null;
		int responseCode = 0;
		String contentType = "";
		String host = "";
		int port = 0;
		
		try {
			URL source = new URL(url);
			String protocol = source.getProtocol();
			if (protocol != null && protocol.equals("http")) {
				host = source.getHost();
				port = source.getPort();
				uc = (HttpURLConnection) source.openConnection();
				uc.setConnectTimeout(8000);
				responseCode = uc.getResponseCode();
				contentType = uc.getContentType();
			}
		} catch (MalformedURLException mue) {
			logger.error("Invalid URL : " + url);
		} catch (UnknownHostException uhe) {
			logger.error("UnknowHost : " + url);
		} catch (SocketException se) {
			logger.error("Socket Error : " + se.getMessage() + " " + url);
		} catch (SocketTimeoutException ste) {
			logger.error("Socket Connection Time Out : " + url);
		} catch (FileNotFoundException fnfe) {
			logger.error("broken link " + url + " ignored");
		} catch (IOException ie) {
			logger.error("IOException : " + ie);
		}
		if (port == basePort
				&& responseCode == HttpURLConnection.HTTP_OK
				&& host.equals(baseHost)
				&& (contentType.startsWith("text/html") || contentType
						.startsWith("text/plain")))
			flag = true;
		return flag;
	}

	/* 从URL队列mPages里取出单个的URL */
	public synchronized String dequeueURL() {
		while (true)
			if (URLs.size() > 0) {
				String url = (String) URLs.remove(0);
				indexedURLs.add(url);
				if (isToBeCaptured(url)) {
					NodeList list;
					try {
						int bookmark = URLs.size();
						/* 获取页面所有节点 */
						parser.setURL(url);
						try {
							list = new NodeList();
							for (NodeIterator e = parser.elements(); e
									.hasMoreNodes();)
								list.add(e.nextNode());
						} catch (EncodingChangeException ece) {
							/* 解码出错的异常处理 */
							parser.reset();
							list = new NodeList();
							for (NodeIterator e = parser.elements(); e
									.hasMoreNodes();)
								list.add(e.nextNode());
						}
						/* 抓取静态页面 */
						if (-1 == url.indexOf("?") && justCopy)
							copy(url, list);
						/**
						 * 依据 http://www.robotstxt.org/wc/meta-user.html 处理
						 * Robots <META> tag
						 */
						NodeList robots = list
								.extractAllNodesThatMatch(
										new AndFilter(new NodeClassFilter(
												MetaTag.class),
												new HasAttributeFilter("name",
														"robots")), true);
						if (0 != robots.size()) {
							MetaTag robot = (MetaTag) robots.elementAt(0);
							String content = robot.getAttribute("content")
									.toLowerCase();
							if ((-1 != content.indexOf("none"))
									|| (-1 != content.indexOf("nofollow")))
								for (int i = bookmark; i < URLs.size(); i++)
									URLs.remove(i);
						}
					} catch (ParserException pe) {
						logger.error("ParserException : " + pe);
					}
					return url;
				}
			} else {
				threads--;
				if (threads > 0) {
					try {
						wait();
						threads++;
					} catch (InterruptedException ie) {
						logger.error("InterruptedException : " + ie);
					}
				} else {
					notifyAll();
					return null;
				}
			}
	}

	/**
	 * 处理单独的URL地址,解析页面并加入到lucene索引中;通过自动探测页面编码保证抓取工作的顺利执行
	 */
	protected void process(String url) {

		String result[];
		String content = null;
		String title = null;

		/* 此项操作较耗性能,故默认不予检测 */
		if (isRepeatedCheck) {
			try {
				TermQuery query = new TermQuery(new Term("url", url));
				Hits hits = indexSearcher.search(query);
				if (hits.length() > 0) {
					logger.info("The URL : " + url
							+ " has already been captured");
				} else {
					result = ParserUtils.parseHtml(url, charset);
					content = result[0];
					title = result[1];
				}
			} catch (IOException ie) {
				logger.error("IOException : " + ie);
			}
		} else {
			result = ParserUtils.parseHtml(url, charset);
			content = result[0];
			title = result[1];
		}

		if (content != null && content.trim().length() > 0) {

			Document document = new Document();
			document.add(new Field("content", content, Field.Store.YES,
					Field.Index.TOKENIZED,
					Field.TermVector.WITH_POSITIONS_OFFSETS));
			document.add(new Field("url", url, Field.Store.YES,
					Field.Index.UN_TOKENIZED));
			document.add(new Field("title", title, Field.Store.YES,
					Field.Index.TOKENIZED,
					Field.TermVector.WITH_POSITIONS_OFFSETS));
			document.add(new Field("date", DateTools.timeToString(System
					.currentTimeMillis(), DateTools.Resolution.DAY),
					Field.Store.YES, Field.Index.UN_TOKENIZED));

			synchronized (indexLock) {
				try {
					RAMWriter.addDocument(document);
					/**
					 * 当存放索引的内存使用大于指定值时将其写入硬盘;采用此方法的目的是通过内存缓冲避免频繁的
					 * IO操作,提高索引创建性能;合并索引时一定要调用被合并一方的IndexWriter的close()方法
					 */
					if (RAMWriter.ramSizeInBytes() > 512 * 1024) {
						RAMWriter.close();
						FSDWriter.addIndexes(new Directory[] { ramDirectory });
						RAMWriter = new IndexWriter(ramDirectory,
								luceneAnalyzer, true);
					}
					logger.info("Indexed link : " + url);
				} catch (CorruptIndexException cie) {
					logger.error("CorruptIndexException : " + cie);
				} catch (IOException ie) {
					logger.error("IOException : " + ie);
				}
			}
		}
	}
	
	/* 将URL链接转换为本地目录的形式 */
	protected String makeLocalLink(String link, String current) {
		
		String localLink;

		if (link.equals(getBaseURL()))
			localLink = "index.html";
		else if (link.startsWith(getBaseURL())
				&& (link.length() > getBaseURL().length())) {
			localLink = link.substring(getBaseURL().length() + 1);
			if (-1 == localLink.indexOf("."))
				localLink += "/" + "index.html";
		} else
			localLink = link;

		if ((null != current) && link.startsWith(getBaseURL())
				&& (current.length() > getBaseURL().length())) {
			current = current.substring(getBaseURL().length() + 1);
			int i = 0, j;
			while (-1 != (j = current.indexOf('/', i))) {
				localLink = "../" + localLink;
				i = j + 1;
			}
		}
		return localLink;
	}
	
	/* 将页面按结构层次保存到本地硬盘 */
	protected void copy(String url, NodeList list) {

		File file = new File(indexDir, makeLocalLink(url, ""));
		File dir = file.getParentFile();

		if (!dir.exists())
			dir.mkdirs();
		else if (!dir.isDirectory()) {
			dir = new File(dir.getParentFile(), dir.getName() + ".content");
			if (!dir.exists())
				dir.mkdirs();
			file = new File(dir, file.getName());
		}
		try {
			PrintWriter out = new PrintWriter(new OutputStreamWriter(
					new FileOutputStream(file), charset));
			for (int i = 0; i < list.size(); i++)
				out.print(list.elementAt(i).toHtml());
			out.close();
			logger.info("Captured link : " + url);
		} catch (FileNotFoundException fnfe) {
			logger.error("FileNotFoundException : " + fnfe);
		} catch (UnsupportedEncodingException uee) {
			logger.error("UnsupportedEncodingException : " + uee);
		}
	}
	
	/**
	 * Link tag that rewrites the HREF.
	 * The HREF is changed to a local target if it matches the source.
	 */
	class LocalLinkTag extends LinkTag {
		public void doSemanticAction() {
			String link = getLink();
			if (link.endsWith("/"))
				link = link.substring(0, link.length() - 1);
			int pos = link.indexOf("#");
			if (pos != -1)
				link = link.substring(0, pos);
			/* 将链接加入到处理队列中 */
			if (!(indexedURLs.contains(link) || URLs.contains(link)))
				URLs.add(link);
			setLink(link);
		}
	}

	/**
	 * Frame tag that rewrites the SRC URLs. The SRC URLs are mapped to local
	 * targets if they match the source.
	 */
	class LocalFrameTag extends FrameTag {
		public void doSemanticAction() {
			String link = getFrameLocation();
			if (link.endsWith("/"))
				link = link.substring(0, link.length() - 1);
			int pos = link.indexOf("#");
			if (pos != -1)
				link = link.substring(0, pos);
			/* 将链接加入到处理队列中 */
			if (!(indexedURLs.contains(link) || URLs.contains(link)))
				URLs.add(link);
			setFrameLocation(link);
		}
	}

	/**
	 * Base tag that doesn't show. The toHtml() method is overridden to return
	 * an empty string, effectively shutting off the base reference.
	 */
	class LocalBaseHrefTag extends BaseHrefTag {
		public String toHtml() {
			return ("");
		}
	}

	public static void main(String[] args) {

		SiteCapturer worker = new SiteCapturer();

		if (args.length < 6) {
			System.out
					.println("Usage: -u <start url> -d <index dir> -t <threads> [-r] [-c] [-i]");
			return;
		}

		for (int i = 0; i < args.length; i++) {
			if (args[i].equals("-u"))
				worker.setBaseURL(args[++i]);
			else if (args[i].equals("-d"))
				worker.setIndexDir(args[++i]);
			else if (args[i].equals("-t"))
				worker.setThreads(Integer.parseInt(args[++i]));
			else if (args[i].equals("-r"))
				worker.setIsRepeatedCheck(true);
			else if (args[i].equals("-c"))
				worker.setJustCopy(true);
			else if (args[i].equals("-i"))
				worker.setJustIndex(false);
		}
		if (worker.getThreads() < 1)
			throw new IllegalArgumentException("Invalid number of threads: "
					+ worker.getThreads());

		worker.capture();
		System.exit(0);
	}

	public String getBaseURL() {
		return baseURL.toString();
	}

	public void setBaseURL(String source) {
		if (source.endsWith("/"))
			source = source.substring(0, source.length() - 1);
		try {
			baseURL = new URL(source);
		} catch (MalformedURLException e) {
			logger.error("Invalid URL : " + getBaseURL());
		}
	}

	public void setIndexDir(String indexDirectory) {
		indexDir = indexDirectory;
	}

	public int getThreads() {
		return threads;
	}

	public void setThreads(int threadCount) {
		threads = threadCount;
	}

	public void setIsRepeatedCheck(boolean check) {
		isRepeatedCheck = check;
	}
	
	public void setJustIndex(boolean justIndex) {
		this.justIndex = justIndex;
	}

	public void setJustCopy(boolean justCopy) {
		this.justCopy = justCopy;
	}
}

工具类ParserUtils代码如下:
package com.huizhi.kanine.util;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.Charset;

import org.htmlparser.Parser;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.HtmlPage;

import cpdetector.io.ASCIIDetector;
import cpdetector.io.CodepageDetectorProxy;
import cpdetector.io.JChardetFacade;
import cpdetector.io.ParsingDetector;
import cpdetector.io.UnicodeDetector;

public class ParserUtils {

	/* StringBuffer的缓冲区大小 */
	public static int TRANSFER_SIZE = 4096;

	/* 当前平台的行分隔符 */
	public static String lineSep = System.getProperty("line.separator");

	/* 自动探测页面编码,避免中文乱码的出现 */
	public static String autoDetectCharset(URL url) {

		CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();
		/**
		 * ParsingDetector可用于检查HTML、XML等文件或字符流的编码
		 * 构造方法中的参数用于指示是否显示探测过程的详细信息
		 * 为false则不显示
		 */
		detector.add(new ParsingDetector(false));
		detector.add(JChardetFacade.getInstance());
		detector.add(ASCIIDetector.getInstance());
		detector.add(UnicodeDetector.getInstance());

		Charset charset = null;
		try {
			charset = detector.detectCodepage(url);
		} catch (MalformedURLException mue) {
			mue.printStackTrace();
		} catch (IOException ie) {
			ie.printStackTrace();
		}
		if (charset == null)
			charset = Charset.defaultCharset();
		return charset.name();
	}

	/* 按照指定编码解析标准的html页面,为建立索引做准备*/
	public static String[] parseHtml(String url, String charset) {

		String result[] = null;
		String content = null;

		try {
			URL source = new URL(url);
			InputStream in = source.openStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					in, charset));
			String line = new String();
			StringBuffer temp = new StringBuffer(TRANSFER_SIZE);
			while ((line = reader.readLine()) != null) {
				temp.append(line);
				temp.append(lineSep);
			}
			reader.close();
			in.close();
			content = temp.toString();
		} catch (UnsupportedEncodingException uee) {
			uee.printStackTrace();
		} catch (MalformedURLException mue) {
			System.err.println("Invalid URL : " + url);
		} catch (UnknownHostException uhe) {
			System.err.println("UnknowHost : " + url);
		} catch (SocketException se) {
			System.err.println("Socket Error : " + se.getMessage() + " " + url);
		} catch (SocketTimeoutException ste) {
			System.err.println("Socket Connection Time Out : " + url);
		} catch (FileNotFoundException fnfe) {
			System.err.println("broken link "
					+ ((FileNotFoundException) fnfe.getCause()).getMessage()
					+ " ignored");
		} catch (IOException ie) {
			ie.printStackTrace();
		}

		if (content != null) {
			Parser myParser = Parser.createParser(content, charset);
			HtmlPage visitor = new HtmlPage(myParser);
			try {
				myParser.visitAllNodesWith(visitor);
				String body = null;
				String title = "Untitled";
				if (visitor.getBody() != null) {
					NodeList nodelist = visitor.getBody();
					body = nodelist.asString().trim();
				}
				if (visitor.getTitle() != null)
					title = visitor.getTitle();
				result = new String[] { body, title };
			} catch (ParserException pe) {
				pe.printStackTrace();
			}
		}
		return result;
	}
}

程序运行可选择控制台或新建一JSP页面,加入以下代码即可
(另,示例代码中log4j的配置文件须放在项目所在磁盘的根目录下;可在capture()
方法的PropertyConfigurator.configure("/log4j.properties")处自由修改)
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ page import="com.huizhi.kanine.util.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Lucene</title>
</head>
<body>
<%
	SiteCapturer worker= new SiteCapturer();
	worker.setBaseURL("http://www.blabla.cn");
	worker.setIndexDir("c:\\luceneIndex");
	//worker.setIsRepeatedCheck(true);//可选,检测链接是否和索引重复
	//worker.setJustCopy(true);//可选,将链接保存到本地
	worker.setThreads(20);
	worker.capture();
%>
</body>
</html>
分享到:
评论
11 楼 yangpi2008 2009-01-13  
如何从索引中读出内容呢,我怎么读不到哦5555555555555
是不是方法不对哦

import java.io.IOException; 

import org.apache.lucene.analysis.Analyzer; 
import org.apache.lucene.analysis.standard.StandardAnalyzer; 
import org.apache.lucene.queryParser.ParseException; 
import org.apache.lucene.queryParser.QueryParser; 
import org.apache.lucene.search.Hits; 
import org.apache.lucene.search.IndexSearcher; 
import org.apache.lucene.search.Query; 
 
public class TestQuery { 
    public static void main(String[] args) throws IOException, ParseException { 
        Hits hits = null; 
        String queryString = "茶馆"; 
        Query query = null; 
        IndexSearcher searcher = new IndexSearcher("C:\\luceneIndex"); 
 
        Analyzer analyzer = new StandardAnalyzer(); 
        try { 
            QueryParser qp = new QueryParser("content", analyzer); 
            query = qp.parse(queryString); 
        } catch (ParseException e) { 
        } 
        if (searcher != null) { 
            hits = searcher.search(query); 
            if (hits.length() > 0) { 
                System.out.println("找到:" + hits.length() + " 个结果!"); 
            } 
        } 
    } 
 
}
10 楼 bruce_luo 2008-06-19  
长期关注。。。。学习中。。。
9 楼 akululu 2008-04-07  
长期关注,并测试。。希望楼主不断更新!
8 楼 brunoplum 2008-04-06  
今天把进一步完善的版本放上来,主要变动是添加了将页面抓取保存到本地的功能,另外加入了日志记录,修正了解析url时一处不妥的地方;欢迎测试!
7 楼 chencang 2008-04-02  
lib.rar我下不下来 
6 楼 chencang 2008-04-02  
楼主辛苦了,期待很久了。
我也在学习这方面的内容,我要仔细拜读下
5 楼 sovolee 2008-04-02  
(1)不能抓获https协议的网站;
(2)缺少异常日志;
(3)SiteCapturer类过长,不方便作业,不符合“建筑美”。
4 楼 sovolee 2008-04-01  
很好,期待很久了。
3 楼 D04540214 2008-03-31  
我来做庄啦
2 楼 brunoplum 2008-03-31  
关于性能,在用spindle的时候即使是只有几十个页面的简单站点都会在抓取完成后进入线程的死锁,我的这个改版不会出现这样的情况,而且加入了很多处理异常的操作,尽可能地保证了页面解析与建立索引的速度及准确性
1 楼 betafox 2008-03-31  
楼主辛苦了啊,能否把它的优点和性能测试一起放上来?

相关推荐

    Spindle Drive.pdf

    根据提供的文件内容,以下是关于Spindle Drive的详细知识点: 1. Spindle Drive的定义与用途: Spindle Drive(主轴驱动装置)是一种被maxonmotor设计成完整系统的易配置主轴驱动装置。主轴驱动装置主要用于传输...

    FANUC伺服电机AC SPINDLE β参数说明书.pdf

    【FANUC伺服电机AC SPINDLE β参数说明书】提供了关于FANUC公司生产的交流主轴电机β系列的详细参数设定指南。这份说明书包含了重要的安全警告、注意事项和补充信息,旨在确保操作人员的安全和机床的正常运行。 ...

    Tapestry spindle插件下载

    **Tapestry Spindle插件详解** Tapestry Spindle是一款专门为MyEclipse集成环境设计的插件,它使得在MyEclipse 10.7这样的版本中能够方便地开发和调试Apache Tapestry应用程序。Tapestry是一个强大的Java Web框架,...

    Automated sleep spindle detection with mixed EEGfeatures.pdf

    本文介绍了一种基于深度神经网络(DNN)的自动化睡眠纺锤波检测方法,该方法通过混合微尺度(深层)特征与宏尺度(熵)特征来提高检测准确性。睡眠纺锤波是一种特殊的爆发性脑波,在记忆巩固、皮层发育等睡眠相关的...

    Particular behavior of spindle thermal deformation by thermal

    ### 主轴热变形的特殊行为:热弯曲 #### 摘要 在精密加工中,由热引起的误差会降低加工精度。为此,大量的研究聚焦于机床中的这些误差补偿方法。然而,在启动或停止主轴旋转后的过渡期,主轴热变形的行为变得非常...

    javaeye月刊2008年4月 总第2期.pdf

    11. **基于Spindle的增强HTTP Spider** Spindle是一个HTTP客户端库,用于构建爬虫应用。文章可能介绍了如何利用Spindle进行高效的数据抓取和分析。 12. **Swing Explorer 1.0发布** Swing Explorer是一款用于...

    spindle3d

    斐济是一个基于ImageJ的开源软件,广泛用于生物医学图像分析,提供丰富的图像处理和分析功能。 2. 在已安装的斐济环境中,打开“更新”菜单,找到“Manage update sites”选项。 3. 在弹出的“Update Sites”窗口中...

    spindle-codegen-binary_2.10-1.8.2.zip

    Codegen Binary模块则专注于生成可执行的二进制文件,这些文件通常包含了基于模板的代码生成逻辑。 Gestalt,正如描述中所提到的,是一个用于Java JVM的配置框架,其核心在于使用Groovy语言编写配置。Groovy是一种...

    YASA(Yet Another Spindle Algorithm):一个Python包,用于分析多导睡眠图的睡眠记录

    YASA(又一个主轴算法)是 Python 中的一个命令行睡眠分析工具箱。...Python 编辑器:YASA 最适合与基于 Web 的交互式用户界面Jupyter Lab配合使用。 一些睡眠脑电图数据和可选的睡眠分期文件(催眠图)。

    Web日志分析查询Spindle.zip

    Spindle 是来自Adobe研究院的开源项目,是构建在 Spark 上的Web日志分析查询。通过 Spray 实现的多线程 HTTP 接口来输出查询结果。查询是通过加载来自 Apache Parquet 的 HDFS 柱状存储格式。

    spindle:基于Spanner的分布式锁定库

    主轴基于的分布式锁定库。它使用Spanner对的支持和来实现其锁定机制。用法目前,需要使用以下DDL预先创建表( locktable只是一个示例): CREATE TABLE locktable ( name STRING(MAX) NOT NULL , heartbeat ...

    SPINdle-开源

    SPINdle是一种逻辑推理器,可用于以有效方式计算可废除逻辑理论的结果。 当前的实现涵盖了基本的可废止逻辑和模态可废止逻辑。

    [Automotive Testing]Simplified Wheel Spindle Bearing Testing with LabWindows-CVI

    本文将基于给定文件的标题、描述、标签以及部分内容,深入探讨如何利用LabWindows-CVI简化轮毂轴承的测试过程。 ### 轮毂轴承测试的重要性 轮毂轴承作为汽车的关键部件之一,其质量直接影响到车辆的行驶安全与稳定...

    Hilbert–Huang transform (WPD–HHT) for spindle bearings condition monitoring

    希尔伯特黄变换论文,结合了小波包变换 An approach based on wavelet packet decomposition and Hilbert–Huang transform (WPD–HHT) for spindle bearings condition monitoring

    NX二次开发UF-PATH-create-spindle-on 函数介绍

    NX二次开发UF_PATH_create_spindle_on 函数介绍,Ufun提供了一系列丰富的 API 函数,可以帮助用户实现自动化、定制化和扩展 NX 软件的功能。无论您是从事机械设计、制造、模具设计、逆向工程、CAE 分析等领域的专业...

    Spindle, An Eclipse Plugin for Tapestry-开源

    以Eclipse IDE插件的形式提供对Tapestry:Java Web Components的IDE支持。 Tapestry是一个Apache顶级项目。 主轴仅支持Tapestry的版本3

    A New Spindle Current Regulation Algorithm for the CNC End

    它基于一个一阶系统模型,该模型具有时间延迟特性,能够根据实际负载变化迅速调整主轴的电流输出。这种方法允许系统根据加工条件的变化快速响应,确保在不同工况下都能保持稳定的加工质量。 ### 3. 微调控制 微调...

    电子政务-基于压电致动器的非均匀分布预紧力可控高速主轴.zip

    可控高速主轴(Controllable High-Speed Spindle)是机械设备的关键部件,尤其在电子政务相关的数据处理中心、云计算服务器等领域,高速主轴的需求日益增长。这种主轴不仅要求有高的转速,还必须具备良好的动态特性...

    spinning-asuwada:Spindle是一个PHP MYSQL工具,用于基于史学数据玩协作式网络讲故事的游戏

    主轴(A田模式) Spindle是一个PHP MYSQL应用程序,用于根据历史数据玩协作性的网络故事讲述游戏。 它最初是由Tabea Hirzel博士在研究的过程中作为原型... 玩此游戏的方式不同,所有方式都包含在Spindle的不同版本中。

Global site tag (gtag.js) - Google Analytics