JSOUP实现简单爬虫

标签: jsoup 爬虫 | 发表时间:2013-11-10 15:04 | 作者:
出处:http://www.iteye.com

转截请注明住处: fair-jm.iteye.com

 

额 有段时间不写文了

这个说是简单爬虫 其实连个爬虫也算不上吧 功能太精简了...

 

流程很简单: 输入几个初始的网页 然后通过JSOUP获取网页中的a标签的href的值

接着把新得到的地址放入任务队列中

 

实现中的worker是一个单线程的派发器 用于产生Parser

Parser用于完成网页的保存 网页的解析 以及入队列操作

 

内容很简单 也没有使用数据库

任务队列直接用了一个Queue

已完成地址和正在处理的地址的保存用了List

具体代码如下:

package com.cc.crawer.infrastructure;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Worker {

	//保存地址 这里保存在G盘的html文件夹内
	public static final String SAVED_FOLDER = "G:\\html\\";

	private BlockingQueue<String> taskQueue = new LinkedBlockingQueue<String>(
			10000); // 任务队列 最大100000
	private List<String> finished = Collections
			.synchronizedList(new ArrayList<String>()); // 存放已经完成处理的地址的列表
	private List<String> processing = Collections
			.synchronizedList(new ArrayList<String>()); // 存放正在处理中的地址的列表

	private ExecutorService savedExector = Executors.newFixedThreadPool(100); // 100个文件保存队列
	private ExecutorService parserExector = Executors.newFixedThreadPool(100); // 最大100的线程池
																				// 用来做解析工作

	private volatile boolean stop = false;

	public Worker() {
	}

	public void addStartAddress(String address) {
		try {
			taskQueue.put(address); // 使用阻塞的put方式
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 启动 这边是一个单线程的派发任务 内容很简单 不断地从任务队列里取值 判断是否处理过 没有的话就处理
	 */
	public void start() {
		while (!stop) {
			String task;
			try {
				task = taskQueue.take();
				if (filter(task)) { // 这边是过路任务的 过滤条件自己写
					continue;
				}
				// System.out.println("start():"+task);
				
				processing.add(task); // 正在处理的任务
				parserExector.execute(new Parser(task));
				

			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}
		// 立即关闭写和读的任务
		parserExector.shutdownNow();
		savedExector.shutdownNow();

	}

	public void stop() {
		stop = true;
	}

	/**
	 * 
	 * @param task 是否过滤的网址
	 * @return true 表示过滤     false 表示不过滤
	 */
	public boolean filter(String task) {

		
		if (finished.contains(task) || processing.contains(task)) {
			return true;
		}

		if (finished.contains(task + "/") || processing.contains(task + "/")) {
			return true;
		}
		
		
		if(task.contains("#")){
			String uri=task.substring(0,task.indexOf("#"));
			if (finished.contains(uri) || processing.contains(uri)) {
				return true;
			}
		}
		
		return false;
		

		// else {
		// int in = task.indexOf("?");
		// if (in > 0)
		// contains = finished.contains(task.substring(0, in));
		// }
	}

	/**
	 * 进行解析的工具
	 * 
	 * @author cc fair-jm
	 * 
	 */
	class Parser implements Runnable {

		private final String url;

		public Parser(String url) {
			if (!url.toLowerCase().startsWith("http")) {
				url = "http://" + url;
			}
			this.url = url;
		}

		@Override
		public void run() {
			try {
				Document doc = Jsoup.connect(url).get();
				String uri = doc.baseUri();

				try {
					savedExector.execute(new Saver(doc.html(), uri)); // 先进行存储
				} catch (RejectedExecutionException ex) { // 产生了这个异常说明保存线程池已经关掉了
															// 那么后续的工作就不要做了
															// 这边可以再保存一下状态
					return;
				}

				Elements es = doc.select("a[href]");
				for (Element e : es) {
					String href = e.attr("href");
					// System.out.println("worker run():"+href);

					if (href.length() > 1) {
						if (href.startsWith("/")) {
							href = doc + href;
							if(href.endsWith("/")){
								href=href.substring(0,href.length()-1);
							}
						}
						if (href.startsWith("http") && !filter(href)) {
							try {
								taskQueue.put(href); // 堵塞的放入
							} catch (java.lang.InterruptedException ex) {
								System.out.println(href + ":任务中止");
								return; // 后续的href也不再进行
							}
						}
					}

				}

				// System.out.println("parser:"+url+" 完成");
				finished.add(url); // 在这边说明这个url已经完成了

			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				processing.remove(url); // 把正在处理的任务移除掉(不管是否成功完成)
			}

		}
	}

	/**
	 * 用于文件保存的线程
	 * 
	 * @author cc fair-jm
	 * 
	 */
	class Saver implements Runnable {

		private final String content;
		private final String uri;
		private Random random = new Random(System.currentTimeMillis());

		public Saver(String content, String uri) {
			this.content = content;
			this.uri = uri;
		}

		@Override
		public void run() {

			String[] sps = uri.split("/");
			String host = sps.length > 2 ? sps[2].replaceAll("\\.", "_") : "";

			String fileName = new StringBuffer(SAVED_FOLDER).append(host)
					.append("_").append(TimeStamp.getTimeStamp()).append("_")
					.append(random.nextInt(1000)).append(".html").toString();
			FileOutputStream fos = null;
			try {
				fos = new FileOutputStream(new File(fileName), true);
				fos.write(content.getBytes());
				fos.flush();
				System.out.println("saver:" + uri + "写入完成");
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (fos != null) {
					try {
						fos.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}

	}
}

 使用如下:

package com.cc.crawer.main;

import java.util.concurrent.TimeUnit;

import com.cc.crawer.infrastructure.Worker;

public class Main {
 public static void main(String[] args) throws InterruptedException {
	 final Worker worker=new Worker();
	 worker.addStartAddress("www.baidu.com");
	 System.out.println("任务开始");
	 new Thread(new Runnable() {
		
		@Override
		public void run() {
			worker.start();
		}
	}).start();
	 TimeUnit.SECONDS.sleep(10);
	 worker.stop();
}
}

 

没做什么优化(也不太清楚该怎么优化)

运行10s 用家中的台式机只能产生200个左右的网页

运行如下:



 

 

 



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [jsoup 爬虫] 推荐:

JSOUP实现简单爬虫

- - ITeye博客
这个说是简单爬虫 其实连个爬虫也算不上吧 功能太精简了.... 流程很简单: 输入几个初始的网页 然后通过JSOUP获取网页中的a标签的href的值. 接着把新得到的地址放入任务队列中. 实现中的worker是一个单线程的派发器 用于产生Parser. Parser用于完成网页的保存 网页的解析 以及入队列操作.

【网络爬虫之JSOUP使用简介】解析一个body片断

- - CSDN博客编程语言推荐文章
假如你有一个HTML片断 (比如. 一个 div 包含一对 p 标签; 一个不完整的HTML文档) 想对它进行解析. 这个HTML片断可以是用户提交的一条评论或在一个CMS页面中编辑body部分. Jsoup.parseBodyFragment(String html)方法.. parseBodyFragment 方法创建一个空壳的文档,并插入解析过的HTML到 body元素中.

【网络爬虫之JSOUP使用简介】解析一个HTML字符串

- - CSDN博客编程语言推荐文章
来自用户输入,一个文件或一个网站的HTML字符串,你可能需要对它进行解析并取其内容,或校验其格式是否完整,或想修改它. jsonu能够帮你轻松解决这些问题. Jsoup.parse(String html) 方法或. Jsoup.parse(String html, String baseUri)示例代码:.

【网络爬虫之JSOUP使用简介】入门:解析和遍历一个HTML文档

- - CSDN博客互联网推荐文章
jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容. 它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据. 从一个URL,文件或字符串中解析HTML;. 使用DOM或CSS选择器来查找、取出数据;. 可操作HTML元素、属性、 文本;.

jsoup select 选择器

- - 编程语言 - ITeye博客
采用CSS或类似jquery 选择器(selector)语法来处理HTML文档中的数据. 利用方法: Element.select(String selector)和 Elements.select(String selector). Jsoup的元素支持类似CSS或(jquery)的选择器语法的查找匹配的元素,可实现功能强大且鲁棒性好的查询.

浅谈jsoup网页抓取技术

- - CSDN博客互联网推荐文章
        最近初步接触HTML的页面抓取技术,之前曾涉及较多的是XML解析,对于XML解析方法非常的多,使用dom4j是最方便的. HTML解析似乎用途会更多一些,对于HTML的页面解析却也不甚了解. 查了一些资料,了解到了jsoup页面解析技术,jsoup是一款java的HTML解析器,可以直接解析某个URL地址、HTML文本内容,它提供了一套非常省力的API,可通过DOM,CSS以及类似于jquery的操作方法来取出和操作数据.

使用JSoup解析HTML文件

- - Java译站
HTML是WEB的核心,互联网中你看到的所有页面都是HTML,不管它们是由JavaScript,JSP,PHP,ASP或者是别的什么WEB技术动态生成的. 你的浏览器会去解析HTML并替你去渲染它们. 不过如果你需要自己在Java程序中解析HTML文档并查找某些元素,标签,属性或者检查某个特定的元素是否存在的话,那又该如何呢.

网络爬虫

- - 四火的唠叨
文章系本人原创,转载请保持完整性并注明出自 《四火的唠叨》. 最近在写一个程序,去爬热门事件和热门关键词网站上的数据. 网络爬虫也叫做网络蜘蛛,是一种互联网机器人,把需要的网页撷取下来,组织成适当格式存储. 它是搜索引擎的重要组成部分,虽然从技术实现上来说,它的难度往往要小于对于得到的网页信息的处理.

使用 jsoup 对 HTML 文档进行解析和操作

- - 互联网旁观者
Java 程序在解析 HTML 文档时,相信大家都接触过 htmlparser 这个开源项目,我曾经在 IBM DW 上发表过两篇关于 htmlparser 的文章,分别是: 从 HTML 中攫取你所需的信息和 扩展 HTMLParser 对自定义标签的处理能力. 但现在我已经不再使用 htmlparser 了,原因是 htmlparser 很少更新,但最重要的是有了 jsoup.

jsoup使用选择器语法来查找元素

- - ITeye博客
jsoup elements对象支持类似于Jquery的选择器语法,来实现非常强大和灵活的查找功能. Element.select(String selector) 和. Elements.select(String selector) 方法实现:. 这个 select 方法在. Elements对象中都可以使用.