月度归档:2016年08月

Object Extract Mapping 与 网页 API

最近的项目需要访问一些外部的网页,比如百度、必应搜索等,有的只是要求把响应内容的文本提取出来,有的是要求做结构化解析的,比如百度的搜索结果,解析为一个结构化的列表,每个列表项有(标题、概要信息、详细信息的链接)。

开始时感觉是用爬虫去爬网页,然后做解析,但有个问题困扰着:比如要保存百度、必应的搜索结果到数据库,肯定只希望定义一个类来对应搜索结果的一条记录,然后写一套保存到数据库的代码。看了一些爬虫框架对于内容解析部分其实都只能自己写代码来解析网页,这样的话,如果要接搜狗就写一套解析网页的逻辑、接 360 也得写一套。。。。每接一个就得写一套。。。这不是我需要的生活。。。

怎么减少这些匹配代码?

后面看到 webmagic 的文档提到其基于注解实现的 Object/Extraction Mapping 功能,在类的字段上定义一个注解,表示这个字段用什么样的方式抽取,这样在爬虫有关的代码里就不会出现这些解析网页的逻辑。

Object Extract Mapping

如果我只需要解析百度的搜索结果,这是很好的方式,但我还要解析必应、搜狗等更多的搜索结果时就不行了。因此需要换一种方式来实现:把抽取方式的定义放到代码外面来

我就实现了一个基于 XML 的 Object-Extrac-Mapping (OEM) 小工具。

继续阅读

Quartz

1. 简介

Quartz 是个任务调度工具,就是定时执行指定的任务。

Quartz 提供了极为广泛的特性如持久化任务,集群和分布式任务等,用 Java 写成,与 Spring 集成方便,伸缩性,负载均衡,高可用性。

本文只关注基于数据库的 Quartz 集群,基于 Quartz 2.2.3 来说明。

2. 核心类

2.1. org.quartz.Job

任务接口,任务类代表要调度执行的业务逻辑实现,必须实现该接口。

如果任务不允许并发执行,则任务类必须添加注解 @DisallowConcurrentExecution 。

该接口只定义了一个方法:
void execute(JobExecutionContext context) throws JobExecutionException;

通过 context 可以访问配置给任务的数据 context.getJobDetail().getJobDataMap(),如果这个 JobDataMap 需要在修改后持久化到数据库里,则需要给任务类加上注解 @PersistJobDataAfterExecution 。Quartz 在下次调度执行这个任务时,会把持久化的数据反序列化成 JobDataMap 供应用使用。

不建议通过 Quartz 的这个机制持久化任何与业务有关的数据。因为业务数据应该由应用来存储,Quartz 只关注于调度执行。

2.2. org.quartz.JobDetail

任务在内存的表示。表示任务详细信息的接口,任务用调度器名称、任务名称和任务所归属的组名 来做唯一标识。

2.3. org.quartz.Trigger

触发器。用调度器名称、触发器名称和触发器所归属的组名 来做唯一标识。用于定义在什么情况、什么时间点执行任务。最常用的触发器类型就是基于 cron 表达式的。

2.4. org.quartz.spi.JobStore

数据存储抽象。该接口定义了 任务、触发器的存储、检索、更新 钩子,该接口还定义了任务执行完成后的回调方法。

Quartz 内建支持把任务、触发器等数据存储在JVM内存、文件、数据库,通过这个接口,就隔离了底层存储机制的差异。可以在配置文件里通过 org.quartz.jobStore.class 属性来指定该接口的实现,比如基于 Redis 做数据存储的实现。

继续阅读