- 浏览: 46650 次
最新评论
自己封装的爬虫基础类。
public interface TaskBaseInfo { /** * 返回任务的名称. * <br/> * 一般用作日志输出 * @return */ String taskName(); /** * 返回任务的唯一code * @return 在整个爬虫项目中不重复的Code值 */ String taskCode(); }
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.JedisCluster; public interface TaskStringCache { Logger logger = LoggerFactory.getLogger(TaskStringCache.class); String BASE_FILE_PATH = "/mfs/ShareFile/static/cms/crawler/cache/"; JedisCluster obtainJedisCluster(); String getCacheStr(String taskCode, String cacheKey); void setCacheStr(String taskCode, String cacheKey, int cacheSeconds, String cacheStr); default String obtainTargetFilePath(String taskCode, String cacheKey) { return BASE_FILE_PATH + taskCode + File.pathSeparator + cacheKey + ".properties"; } /** * 设置缓存的默认方法 * @param taskName 任务中文名,日志使用 * @param taskCode 任务code需保持唯一性 * @param cacheKey 缓存的key * @param cacheStr 缓存的值 */ default void defaultSetCacheStr(String taskName, String taskCode, String cacheKey, int cacheSeconds, String cacheStr) { JedisCluster jedisCluster = obtainJedisCluster(); jedisCluster.setex(cacheKey, cacheSeconds, cacheStr); String targetFilePath = obtainTargetFilePath(taskCode, cacheKey); save2FileAtomic(taskName, targetFilePath, cacheStr); } /** * 获取通过【设置缓存的默认方法】{@link #defaultSetCacheStr(String, String, String, String)}设置的缓存 * @param taskName 任务中文名,日志使用 * @param taskCode 任务code需保持唯一性 * @param cacheKey 缓存的key * @return */ default String defaultGetCacheStr(String taskName, String taskCode, String cacheKey) { JedisCluster jedisCluster = obtainJedisCluster(); String cacheStr = jedisCluster.get(cacheKey); if (StringUtils.isNotBlank(cacheStr)) { return cacheStr; } String targetFilePath = obtainTargetFilePath(taskCode, cacheKey); try { // 没利用到多少异步的优势,执行异步操作后马上获取结果还是会阻塞 cacheStr = readFile(targetFilePath).get(); } catch (InterruptedException | ExecutionException e) { logger.error("【" + taskName + "】 执行异步获取文件缓存内容时失败. taskCode=>" + "【" + taskCode + "】" + " cacheKey=>" + "【" + cacheKey + "】"); logger.error(e.getMessage()); } return cacheStr; } /** * 通过文件持久化爬取的游标Id,避免在数据增加字段 * 文件写入操作较慢,异步执行 * 原子操作,避免写入和读取的并发问题 * * @param filePath * @return */ default void save2FileAtomic(String taskName, String filePath, String content) { CompletableFuture.runAsync(() -> { File tmpFile = new File(filePath + ".tmp"); try { if (tmpFile.exists() == false) { tmpFile.getParentFile().mkdirs(); tmpFile.createNewFile(); } try (FileWriter fw = new FileWriter(tmpFile)) { fw.write(content); fw.flush(); } } catch (IOException e) { logger.error("【" + taskName + "】 => 写入缓存字符串到文件 => 【" + tmpFile + "】 时异常 \n" + e.getMessage()); logger.error("【" + taskName + "】 文件写入操作退出"); if (tmpFile.exists()) { tmpFile.delete(); } return; } if (tmpFile.exists() == false) { return; } // 此段注释针对windows系统在同一个文件系统内且是同一个盘符下已经有一个目标文件; // 下面的renameTo操作会失败,造成无限递归调用进而 【栈溢出】 异常 // 在Linux运行的情况下,可暂时先注释掉,测试没问题后上线 // 注释开始段 // File destFile = new File(filePath); // if (destFile.exists()) { // destFile.delete(); // } // 注释结束段 if (tmpFile.renameTo(new File(filePath))) { tmpFile.delete(); } else { logger.error("move fails filePath:" + filePath); tmpFile.delete(); this.save2FileAtomic(taskName, filePath, content); // 当在Linux某个发行版下测试时,renameTo操作出错的话,可不硬性要求原子操作, // 可将上面的原子操作注释掉,改为下面的操作 // save2File(filePath, content); } }); } // default void save2File(String filePath, String content) throws IOException { // // try (FileWriter fw = new FileWriter(new File(filePath))) { // // fw.write(content); // fw.flush(); // } // } /** * 异步读取文件内容 * * @param filePath * @return * @throws IOException * @throws FileNotFoundException */ default CompletableFuture<String> readFile(String filePath) { return CompletableFuture.supplyAsync(() -> { StringBuilder strb = new StringBuilder(); try (FileInputStream fis = new FileInputStream(filePath); BufferedReader inReader = new BufferedReader(new InputStreamReader(fis));) { String line = StringUtils.EMPTY; while ((line = inReader.readLine()) != null) { strb.append(line); } } catch (IOException e) { logger.error(e.getMessage()); return StringUtils.EMPTY; } return strb.toString(); }); } }
public interface BasicTask { void run(); }
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import com.xxx.zx.crawler.basic.BasicTask; public abstract class BaseCrawlerTask implements TaskBaseInfo, TaskStringCache, BasicTask, ApplicationContextAware { protected final Logger logger = LoggerFactory.getLogger(getClass()); protected static ApplicationContext ac; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { ac = applicationContext; } public synchronized static <T> T getBean(Class<T> beanClass) { return ac.getBean(beanClass); } public synchronized static Object getBean(String beanName) { return ac.getBean(beanName); } @Override public String getCacheStr(String taskCode, String cacheKey) { return defaultGetCacheStr(taskName(), taskCode, cacheKey); } @Override public void setCacheStr(String taskCode, String cacheKey, int cacheSeconds, String cacheStr) { defaultSetCacheStr(taskName(), taskCode, cacheKey, cacheSeconds, cacheStr); } }
发表评论
-
简单的压测模拟
2018-05-11 19:52 670import java.time.Duration; i ... -
Java的驼峰与下划线的属性对象互相转换
2018-05-11 19:50 8421import com.xxxx.util.consta ... -
Elastic Search搜索实例
2019-06-16 18:30 636要从现在的公司离职了。记录一下自己针对我们的自己需求所做的搜索 ... -
针对基于Redis Cluster的接口数据缓存删除实现
2018-03-26 10:35 1238首先定义个工具interface,基于Java 8的实现. 主 ... -
简单ELK配合logback搭建日志监控中心
2018-03-20 17:30 1340今天得闲就自己搭了个ELK示例,过程挺简单的。 Elas ... -
spring的基于java的项目配置示例2
2018-03-20 17:32 847import com.xxx.support.config ... -
HttpClient实例
2018-03-16 08:15 657import java.io.IOException; ... -
spring的基于java的项目配置示例1
2018-03-16 08:26 937spring的基于java的项目配置示例。 impor ... -
基于spring data的Elastic Search的配置示例
2018-03-15 17:41 912基于spring data的Elastic Search的配置 ... -
方便jedis cluster操作的工具类
2018-03-15 17:37 3013由于redis的集群 redis cluster不支持keys ... -
基于AOP的ajax的referrer判断
2018-03-15 17:23 1561网页中ajax请求的referrer的值是当前域名。(其实这个 ... -
Java Timestamp从MySQL数据库取出的字符串转换为LocalDateTime
2016-01-26 16:08 9927最新在工作中使用了Java 8的LocalDate ... -
reviewC指针
2014-03-02 22:05 372由于要考试,有C的考核内容。所以今天把C拉出来又看了下,其实基 ... -
Python2.X内置函数学习
2013-12-19 21:52 11641.apply()函数 学过Python的都知道P ... -
学习Python中遇到的问题
2013-09-04 23:26 719最近学习Python中。 先上代码: # -*- codi ...
相关推荐
本资源"Python爬虫基础类库源码示例.zip"包含了一系列的Python爬虫基础类库的源码实例,旨在帮助初学者更好地理解和运用这些库。以下是关于Python爬虫常用库的详细介绍以及实战应用。 1. **BeautifulSoup** ...
根据提供的文件信息,这份python爬虫基础课件主要涵盖了网络爬虫的概念、原理、基本流程以及实现数据抓取和处理的关键技术点。 首先,网络爬虫是自动获取网页内容的程序,常用于搜索引擎、数据采集等场景。网络爬虫...
这个“爬虫基础知识和软件准备”视频教程将引导你进入爬虫的世界,帮助你理解爬虫的概念,以及在开发爬虫前如何正确配置和搭建工作环境。 首先,我们需要理解爬虫的基本概念。爬虫,又称为网络蜘蛛或网页抓取工具,...
案例分析:在提供的压缩包"11-爬虫开发阶段-爬虫基础-MongoDB数据库-爬虫Scrapy框架和案例"中,可能包含实际的Scrapy项目代码和MongoDB使用示例。这些案例可以帮助你更深入地理解如何将Scrapy与MongoDB集成,包括...
**网络爬虫基础** 网络爬虫,又称为网页蜘蛛或数据抓取程序,是一种自动浏览互联网并抓取信息的程序。在Python编程语言中,学习网络爬虫可以帮助我们有效地从网上获取大量数据,进行数据分析或者建立自己的信息库。...
总的来说,这个"机票爬虫工具类"项目涉及到网络爬虫的基础知识和实践技巧,通过合理的设计和实现,我们可以高效地获取到埃塞俄比亚和卡塔尔的机票信息,为数据分析、市场研究等工作提供数据支持。
在实际使用HttpHelper类时,开发者需要结合C#的基础知识,如字符串处理、正则表达式、XML或JSON解析等,来处理获取的响应数据,并根据需要解析出目标信息。同时,理解HTTP协议的基本原理,如请求头、状态码、编码...
它通常会封装HttpClient或WebClient等.NET Framework提供的基础网络通信类,以提供更简洁的API,方便开发者快速构建爬虫项目。 1. **HTTP请求基础**:在爬虫开发中,我们首先需要理解HTTP协议的基本概念,如GET和...
【基础版爬虫源码】是一个适合初学者的爬虫程序示例,它提供了一个简单的起点,让学习者能够理解并实践网页数据抓取的基本原理和步骤。爬虫是计算机科学领域的一种技术,用于自动地从互联网上搜集信息,它是大数据...
在本压缩包“一些爬虫基础和python基础随手记练习.rar”中,包含的是关于Python编程语言的基础知识以及网络爬虫技术的学习资料。Python是一种高级、通用的编程语言,因其简洁明了的语法而受到广大程序员的喜爱,尤其...
Python爬虫基础知识与源码分析 在信息技术领域,Python爬虫是数据挖掘和网络信息获取的重要工具。Python语言因其简洁明了的语法和丰富的库支持,成为开发爬虫的首选语言。本篇将深入探讨Python爬虫的基础知识,并...
总结来说,本"爬虫基础教程"将带你走进Python爬虫的世界,通过学习和实践,你可以掌握网页抓取、数据解析、反爬策略、数据存储等核心技能,为后续的数据分析和挖掘打下坚实基础。不论你是对数据充满热情的学生,还是...
通过学习和理解这个项目,初学者可以了解到网络爬虫的基本构建块,并为进一步的爬虫开发打下基础。同时,对于有经验的开发者,这样的项目可以作为进一步优化和扩展的起点,例如实现分布式爬虫以提高抓取效率,或者...
### 爬虫基础知识、爬虫实例与反爬机制详解 在网络世界中,爬虫作为一项重要的技术手段,既是强大的信息搜集工具,也是对网站运营者的挑战。爬虫技术可以帮助我们从海量的互联网数据中提取有价值的信息,但也可能...
Python爬虫基础知识是入门网络数据抓取的重要领域,它涵盖了Python编程语言的基础、网络请求、HTML解析、数据存储等多个方面。下面将详细讲解这些关键知识点。 首先,Python是一种广泛使用的高级编程语言,因其简洁...
**一、网络爬虫基础** 1. **网络爬虫概念**:网络爬虫(Web Crawler)是按照预定规则自动抓取互联网信息的程序或脚本。它能遍历网页,抓取其中的数据,形成结构化的数据集合。 2. **分类**:通用网络爬虫(全网爬虫...
### C#网络爬虫技术详解 ...无论是初学者还是有一定基础的学习者,都应该注重理论与实践相结合,在实践中不断优化自己的爬虫系统。同时,需要注意遵守法律法规及网站政策,尊重数据所有权,合理合法地进行数据抓取。
1. **Python编程基础**:学习Python的基本语法、变量类型、控制流、函数和类等,这是编写爬虫程序的基础。 2. **网络请求与HTTP协议**:了解HTTP请求方法(GET、POST等)和响应状态码,以及如何使用Python的...
本套视频教程适合想掌握爬虫技术的学习者,以企业主流版本Python 3.7来讲解,内容包括:Python基础、Urllib、解析(xpath、jsonpath、beautiful)、requests、selenium、Scrapy框架等。针对零基础的同学可以从头学起...