转截请注明出处: 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个左右的网页
运行如下:
相关推荐
基于jsoup实现爬虫和IKAnalyzer分词器,自己学习时编写的一个简单的例子,以智联招聘,和boss直聘为目标
该资源包含了一个利用jsoup实现的网页爬虫的下案例,简单易懂。
jsoup编写的简单爬虫,实现P站每日热门大图爬取,目前支持png和jpg格式大图爬取,多图的只能爬取第一张
自己搞Java爬虫的时候整理得jar包希望能够帮助到猿们
今天我们使用Jsoup来实现一个简单的爬虫程序。 Jsoup拥有十分方便的api来处理html文档,比如参考了DOM对象的文档遍历方法,参考了CSS选择器的用法等等,因此我们可以使用Jsoup快速地掌握爬取页面数据的技巧。 ...
java 实现简单爬虫,爬取图片。 根据爬取页面内容,使用jsoup解析html页面,获取需要的路径,进行循环下载。 博客:https://blog.csdn.net/qq_37902949/article/details/81257065
Android Studio 爬虫 之 简单实现使用 jsoup/okhttp3 爬取购物商品信息的案例demo 1、okhttp3 获得网页的 html 内容 2、jsoup 解析 html 的内容,获取需要的部分信息
Java使用HtmlParser抓取网页数据并解析
框架,它提供简单灵活的API,只需少量代码即可实现一个爬虫。webmagic采用完全模块化的设计,功能覆盖整个爬虫的生命周期(链接提取、页面下载、内容抽取、持久化),支持多线程抓取,分布式抓取,并支持自动重试、...
使用java开发的游戏项目源码,可用于毕业设计、课程设计、练手学习等
100多行实现的csdn博客访问量自动刷新程序,原理很简单通过jsoup爬虫框架,获取对于的链接,spring的RestTemplete发送http请求 引入的依赖 <!-- https://mvnrepository.com/artifact/org.jsoup/jsoup --> ...
简单的java爬虫实现,使用 httpclient 、jsoup 、线程池等技术爬取了nba官网的nba球员数据,打包前刚刚重新调试代码,可以直接运行
最近在学习搜索方面的东西,需要了解网络爬虫方面的知识,虽然有很多开源的强大的爬虫,但本着学习的态度,想到之前在做资讯站的时候需要用到爬虫来获取一些文章,今天刚好有空就研究了一下.在网上看到了一个demo,...
Gecco整合了jsoup、httpclient、fastjson、spring、htmlunit、redission等优秀框架,让您只需要配置一些jquery风格的选择器就能很快的写出一个爬虫。Gecco框架有优秀的可扩展性,框架基于开闭原则进行设计,对修改...
一个gecco爬虫框架,简单易用,使用jquery风格的选择器抽取元素 支持爬取规则的动态配置和加载 支持页面中的异步ajax请求 支持页面中的javascript变量抽取 利用Redis实现分布式抓取,参考gecco-redis 支持结合Spring...
主要特征:简单易用,使用 jquery 风格的选择器抽取元素支持爬取规则的动态配置和加载支持页面中的异步 ajax 请求支持页面中的 javascript 变量抽取利用 Redis 实现分布式抓取,参考gecco-redis支持结合 Spring 开发...
本项目旨在通过使用JAVA语言实现一个基于目标网页特征(网页内容特征和URL正则特征)和广度优先搜索策略的多线程聚焦爬虫程序框架。通过使用此框架可以简单、高效地完成具备个性化需求的爬虫程序的开发定制。 ###...
项目主页国外:国内:特点Java开发(学习java的良方)易理解(中文注释,多样例代码)易用性(最短一行代码就可以开始爬虫)代码少(已经默认实现了大部分功能)基于Jsoup(个性化解析网页方便)高度扩展性(热插拔...