`

JSOUP实现简单爬虫

 
阅读更多

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

 

额 有段时间不写文了

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

 

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

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

 

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

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

 

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

任务队列直接用了一个Queue

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

具体代码如下:

package com.cc.crawler.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.crawler.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个左右的网页

运行如下:



 

 

 

  • 大小: 70.9 KB
  • 大小: 42.2 KB
0
1
分享到:
评论
5 楼 fair_jm 2013-11-11  
hk_one 写道
TimeStamp not found.


it is just a simple tool  ,you can write yourself.
4 楼 fair_jm 2013-11-11  
hk_one 写道
is crawler,not crawer.

thx~~~
3 楼 hk_one 2013-11-11  
"fos.write(content.getBytes());" best written ""fos.write(content.getBytes("UTF-8"));
2 楼 hk_one 2013-11-11  
TimeStamp not found.
1 楼 hk_one 2013-11-11  
is crawler,not crawer.

相关推荐

    jsoup实现网络爬虫

    **JSoup实现网络爬虫详解** 网络爬虫是获取大量网页数据的重要工具,而Java作为广泛应用的编程语言,提供了丰富的库来支持网络爬虫的开发。JSoup是其中一个优秀的库,专为处理真实世界的HTML而设计。本篇将详细介绍...

    Android实战——jsoup实现网络爬虫,糗事百科项目的起步

    本篇文章将聚焦于如何利用jsoup库在Android平台上实现一个简单的网络爬虫,以起步一个名为“糗事百科”的项目。 Jsoup是一个Java库,设计用于处理实际世界的HTML。它提供了方便的API来解析、查找和修改HTML文档。在...

    基于jsoup的SpringBoot爬虫demo

    这个"基于jsoup的SpringBoot爬虫demo"项目旨在展示如何整合这两者来实现一个简单的网页数据抓取服务。 **jsoup库详解** jsoup是一个用于处理实际世界HTML的Java库。它提供了非常方便的API,用于提取和操作数据,...

    jsoup多线程爬虫

    下面是一个简单的多线程jsoup爬虫框架示例: ```java import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import java.util.ArrayList; import java.util.List; import java.util.concurrent....

    jsoup1.8.1抓取爬虫工具

    **jsoup1.8.1抓取爬虫工具** jsoup是Java领域中一款非常流行的HTML解析库,它主要用于处理实际世界中的HTML,提供了一种干净、简单的API来提取和...通过深入学习和实践,你可以利用jsoup实现各种复杂的网页抓取任务。

    java+idea+jsoup 爬虫

    Java + IntelliJ IDEA + Jsoup 爬虫是一个高效且便捷的网页抓取解决方案。Jsoup 是一个用于处理实际世界HTML的Java库,它提供了非常方便的API,用于提取和操作数据,使用DOM、CSS以及类似于jQuery的方法。在这个项目...

    基于jsoup实现爬虫和IKAnalyzer分词器

    **基于jsoup实现爬虫** jsoup是一款Java库,它提供了非常方便的API,用于处理实际世界中的HTML。它的核心功能包括抓取网页、解析HTML以及提取和操作数据。jsoup模仿了DOM API,但设计得更加简洁和高效。在这个项目...

    Android_Jsoup网页爬虫案例

    **Android Jsoup网页爬虫案例** Jsoup是一个Java库,设计用于处理真实世界的HTML,它提供了非常方便的API,用于提取和操作数据,使用DOM、CSS以及类似于jQuery的方法。在Android开发中,我们有时需要从网页上抓取...

    jsoup包实现的小爬虫

    利用JSoup构建一个简单的小爬虫,通常包括以下步骤: 1. **连接网页**:使用`Jsoup.connect()`方法连接到目标URL。 2. **解析HTML**:调用`get()`方法获取`Document`对象。 3. **选取数据**:使用CSS选择器选取需要...

    Jsoup爬虫简单案例

    在本文中,我们将深入探讨如何使用Jsoup进行简单的网页爬虫操作。 首先,Jsoup的主要功能包括HTML解析、DOM遍历以及选择器查询。通过解析HTML,我们可以获取到网页中的结构化信息,比如段落、标题、链接等。DOM遍历...

    jsoup网页爬虫小案例

    在这个案例中,我们将探讨如何使用Java的Jsoup库来实现一个简单的网页爬虫。Jsoup是一个强大的库,专为处理真实世界的HTML而设计,它提供了非常方便的方法来解析、查找和修改HTML文档。这个案例主要针对初级到中级的...

    jsoup+httpclient j简单爬虫

    **JSoup + HttpClient 简单爬虫** 在信息技术领域,数据抓取,或称“爬虫”,是一种自动化获取网页信息的技术。JavaScript Object Notation (JSON) Soup 和 HttpClient 是两个在Java开发中常用于实现爬虫功能的库。...

    spring boot+java +jsoup+ 爬虫

    Spring Boot + Java + Jsoup 爬虫是一个常见的技术组合,用于构建高效、简洁的网络爬虫项目。本文将深入探讨这些技术如何协同工作,以及如何利用它们来抓取和处理网页上的图片资源。 首先,Spring Boot 是一个由...

    jsoup爬虫学习之爬取博客(包含jsoup jar包)

    通常,一个简单的`jsoup`爬虫会包括以下几个步骤: 1. **连接网页**:使用`Jsoup.connect(url).get()`方法连接到指定的网页,并获取HTML内容。 2. **解析HTML**:使用`Jsoup.parse()`方法将HTML内容转换为`Document...

    Android+jsoup Java爬虫做的一个 阅读app。(有源代码,随手写的 可能代码有点乱)

    总结起来,这个项目展示了如何结合Android和Jsoup来构建一个简单的阅读应用,涉及到了网络爬虫技术、UI设计、数据存储、异步处理等多个关键知识点。对于想学习Android开发和网络爬虫的人来说,这是一个很好的实践...

    jsoup网络爬虫

    使用jsoup作为核心的网络爬虫框架,可以有效地实现定制化的数据抓取需求,提高开发效率,并能应对各种复杂的网页结构。 总的来说,jsoup是一个功能强大的HTML解析库,它简化了网络爬虫的开发,使得开发者能够快速地...

    爬虫实例(jsoup).zip

    【标题】"爬虫实例(jsoup).zip" 提供了一个基于jsoup的Java爬虫项目的实例,这旨在帮助初学者快速掌握网页抓取的基本技能。Jsoup是一个强大的库,专门用于解析HTML,使得处理网页数据变得更为简洁。在这个实例中,...

    HttpClient ,jsoup和 HtmlParser ,htmllexer实现简易爬虫用到的jar包

    这些库为构建简单的Java爬虫提供了必要的工具和功能。 HttpClient是Apache基金会的一个开源项目,提供了用于执行HTTP请求的强大工具集。它支持HTTP/1.1协议,并且可以处理各种复杂的HTTP场景,如多部分上传、重定向...

    jsoup爬虫中文api

    ### Jsoup爬虫技术及其API应用 #### 一、Jsoup简介 Jsoup是一款用于Java的应用程序接口(API),主要用于从HTML文档中提取和操作数据。它提供了强大的功能,包括解析HTML文档、清洗用户输入的数据、从网站抓取数据等...

    java爬虫jsoup包

    **Java爬虫与Jsoup详解** Jsoup是一款强大的开源库,专为Java设计,用于解析HTML文档并提取结构化数据。这个库的核心功能是通过DOM(文档对象模型)、CSS选择器以及类似jQuery的操作方式,使得在Java中处理HTML变得...

Global site tag (gtag.js) - Google Analytics