Day 18: BoilerPipe —— Java开发者的文章提取工具

编者注:我们发现了有趣的系列文章《30天学习30种新技术》,正在翻译,一天一篇更新,年终礼包。下面是第 18 天的内容。


今天我决定学习如何使用Java做网页链接的文本和图像提取。在大多数内容发现网站上(如Prismatic)这是一个非常常见的需求,今天就是学习如何使用一个名为boilerpipe的Java库来完成这个任务。

准备

  1. 基本的Java知识是必需的,安装最新的Java开发工具包(JDK ),可以是OpenJDK 7Oracle JDK 7

  2. 注册一个OpenShift帐户,它是完全免费的,可以分配给每个用户1.5 GB的内存和3 GB的磁盘空间。

  3. 安装RHC客户端工具,需要有ruby 1.8.7或更新的版本,如果已经有ruby gem,输入 sudo gem install rhc ,确保它是最新版本。要更新RHC的话,执行命令 sudo gem update rhc,如需其他协助安装RHC命令行工具,请参阅该页面: https://www.openshift.com/developers/rhc-client-tools-install

  4. 通过 rhc setup 命令设置您的OpenShift帐户,此命令将帮助你创建一个命名空间,并上传你的SSH keys到OpenShift服务器。


第1步:创建一个JBoss EAP的应用

首先从创建示例应用程序开始,把该应用称作 newsapp

$ rhc create-app newsapp jbosseap

然后可以使用如下命令:

$ rhc create-app newsapp jbosseap -g medium

这样会创建一个应用程序容器,设置好所有需要的SELinux政策和cgroup配置,OpenShift也将创建一个私人git仓库并克隆到本地。最后,OpenShift会给外界提供一个DNS,该应用程序将在http://newsapp-{domain-name}.rhcloud.com/ 下可以访问(将 domain-name 更换为自己的域名)。

第2步:添加Maven依赖

pom.xml 文件里添加如下依赖:

<dependency>
    <groupId>de.l3s.boilerpipe</groupId>
    <artifactId>boilerpipe</artifactId>
    <version>1.2.0</version>
</dependency>
<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.9.1</version>
</dependency>

<dependency>
    <groupId>net.sourceforge.nekohtml</groupId>
    <artifactId>nekohtml</artifactId>
    <version>1.9.13</version>
</dependency>

同时也需要加一个新的库:

<repository>
    <id>boilerpipe-m2-repo</id>
    <url>http://boilerpipe.googlecode.com/svn/repo/</url>
    <releases>
        <enabled>true</enabled>
    </releases>
    <snapshots>
        <enabled>false</enabled>
    </snapshots>
</repository>

通过更新 pom.xml 文件里的几个特性将Maven项目更新到Java 7:

<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>

现在就可以更新Maven项目了(右键单击>Maven>更新项目)。

第3步:启用CDI

使用CDI来进行依赖注入。CDI、上下文和依赖注入是一个Java EE 6规范,能够使依赖注入在Java EE 6的项目中。

src/main/webapp/WEB-INF 文件夹下建一个名为beans.xml中一个新的XML文件。更换beans.xml中的以下内容:

<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

</beans>

第4步:创建Boilerpipe内容提取服务

现在创建一个Boilerpipe内容提取服务的服务类,这个类会用一个url,从这个url中提取标题和文章内容。

import java.net.URL;
import java.util.Collections;
import java.util.List;

import com.newsapp.boilerpipe.image.Image;
import com.newsapp.boilerpipe.image.ImageExtractor;

import de.l3s.boilerpipe.BoilerpipeExtractor;
import de.l3s.boilerpipe.document.TextDocument;
import de.l3s.boilerpipe.extractors.ArticleExtractor;
import de.l3s.boilerpipe.extractors.CommonExtractors;
import de.l3s.boilerpipe.sax.BoilerpipeSAXInput;
import de.l3s.boilerpipe.sax.HTMLDocument;
import de.l3s.boilerpipe.sax.HTMLFetcher;

public class BoilerpipeContentExtractionService {

    public Content content(String url) {
        try {
            final HTMLDocument htmlDoc = HTMLFetcher.fetch(new URL(url));
            final TextDocument doc = new BoilerpipeSAXInput(htmlDoc.toInputSource()).getTextDocument();
            String title = doc.getTitle();

            String content = ArticleExtractor.INSTANCE.getText(doc);

            final BoilerpipeExtractor extractor = CommonExtractors.KEEP_EVERYTHING_EXTRACTOR;
            final ImageExtractor ie = ImageExtractor.INSTANCE;

            List<Image> images = ie.process(new URL(url), extractor);

            Collections.sort(images);
            String image = null;
            if (!images.isEmpty()) {
                image = images.get(0).getSrc();
            }

            return new Content(title, content.substring(0, 200), image);
        } catch (Exception e) {
            return null;
        }

    }
}

上述代码执行以下操作:

  1. 首先在给定的url中读取文件
  2. 然后解析HTML文档并返回TextDocument
  3. 接下来从文本文件中提取标题
  4. 最后从文本中提取内容,返回一个应用的值对象的新实例(value object)

第5步:启用JAX-RS

为启用JAX-RS,建立一个扩展 javax.ws.rs.core.Application 的类,并通过如下所示的 javax.ws.rs.ApplicationPath 注释指定应用程序路径。

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/api/v1")
public class JaxrsInitializer extends Application{


}

第6步:创建ContentExtractionResource

创建ContentExtractionResource类,它会返回一个JSON内容对象。创建一个名为ContentExtractionResource的新类,并用如下所示的内容替换:

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

import com.newsapp.service.BoilerpipeContentExtractionService;
import com.newsapp.service.Content;

@Path("/content")
public class ContentExtractionResource {

    @Inject
    private BoilerpipeContentExtractionService boilerpipeContentExtractionService;

    @GET
    @Produces(value = MediaType.APPLICATION_JSON)
    public Content extractContent(@QueryParam("url") String url) {
        return boilerpipeContentExtractionService.content(url);
    }
}

部署到OpenShift

最后,更改部署到OpenShift

$ git add .
$ git commit -am "NewApp"
$ git push

在代码push和部署完成后,我们可以在 http://newsapp-{{domain-name}.rhcloud.com 查看正在运行的应用程序。我的示例应用程序展示如下。

img

今天就这些,欢迎反馈。


原文 Day 18: BoilerPipe--Article Extraction for Java Developers
翻译整理 SegmentFault


SegmentFault_行业快讯
第一时间为开发者提供行业相关的实时热点资讯

思否编辑部官方账号,欢迎私信投稿、提供线索、沟通反馈。

3.9k 声望
116.9k 粉丝
0 条评论
推荐阅读
SegmentFault 技术周刊 Vol.21 - 程序人生(二):2016 这一年
在第 18 期社区周刊《程序人生》1 中,我们汇总图灵访谈、SegmentFault 内部程序员访谈、社区开发者的编程之路和工具利器等,分享 2016 这一年里,社区开发者们的日常。其中提到“EAT SLEEP CODE REPEAT,google ...

SegmentFault思否13阅读 5.1k评论 7

Java 编译器 javac 及 Lombok 实现原理解析
javac 是 Java 代码的编译器12,初学 Java 的时候就应该接触过。本文整理一些 javac 相关的高级用法。Lombok 库,大家平常一直在使用,但可能并不知道实现原理解析,其实 Lombok 实现上依赖的是 Java 编译器的注...

nullwy10阅读 5.9k

与RabbitMQ有关的一些知识
工作中用过一段时间的Kafka,不过主要还是RabbitMQ用的多一些。今天主要来讲讲与RabbitMQ相关的一些知识。一些基本概念,以及实际使用场景及一些注意事项。

lpe2348阅读 1.8k

封面图
Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

王中阳Go5阅读 1.8k评论 2

封面图
Redis 发布订阅模式:原理拆解并实现一个消息队列
“65 哥,如果你交了个漂亮小姐姐做女朋友,你会通过什么方式将这个消息广而告之给你的微信好友?““那不得拍点女朋友的美照 + 亲密照弄一个九宫格图文消息在朋友圈发布大肆宣传,暴击单身狗。”像这种 65 哥通过朋...

码哥字节5阅读 1.1k

封面图
NB的Github项目,看到最后一个我惊呆了!
最近看到不少好玩的、实用的 Github 项目,就来给大家推荐一把。中国制霸生成器最近在朋友圈非常火的一个小网站,可以在线标记 居住、短居、游玩、出差、路过 标记后可生成图片进行社区分享,标记过的信息会记录...

艾小仙5阅读 1.5k评论 1

好好的系统,为什么要分库分表?
今天是《分库分表 ShardingSphere 原理与实战》系列的开篇文章,之前写过几篇关于分库分表的文章反响都还不错,到现在公众号:程序员小富后台不断的有人留言、咨询分库分表的问题,我也没想到大家对于分库分表的话...

程序员小富3阅读 1.5k

思否编辑部官方账号,欢迎私信投稿、提供线索、沟通反馈。

3.9k 声望
116.9k 粉丝
宣传栏