Day 16: Goose Extractor —— 好用的文章提取工具

今天的“30天学习30种新技术”的主题是如何使用Python进行文章提取。这几个月来,我对文章提取很感兴趣,因为我想写一个Prismatic克隆。Prismatic创建基于用户兴趣的新闻源。提取文章的主要内容、图片和其他元信息对大多数类似Prismatic的内容发现站点很有用。本文中,我们将学习如何使用Python的goose-extractor包来完成这个任务。我们首先介绍一些基础知识,然后使用Goose Extractor 的 API 来开发一个简单的Flask应用。

Goose Extractor是什么?

Goose Extractor是一个Python的开源文章提取库。可以用它提取文章的文本内容、图片、视频、元信息和标签。Goose本来是由Gravity.com编写的Java库,最近转向了scala。

Goose Extractor网站是这么介绍的:

Goose Extractor完全用Python重写了。目标是给定任意资讯文章或者任意文章类的网页,不仅提取出文章的主体,同时提取出所有元信息以及图片等信息。

为什么关心Goose Extractor

我决定学习Goose Extractor是因为:

  1. 我打算开发需要文章提取功能的应用。Goose Extractor基于NLTKBeautiful Soup,分别是文本处理和HTML解析的领导者。

  2. 我想了解如何用Python进行文章提取。

安装Goose Extractor

我们首先需要安装Python和virtualenv,本文使用的Python版本是2.7

然后使用如下命令安装:

mkdir myapp
cd myapp
virtualenv venv --python=python2.7
. venv/bin/activate
pip install goose-extractor

GitHub仓库

今天的示例程序的代码可从GitHub取得。

应用

示例应用运行在 OpenShift 上 http://gooseextractor-t20.rhcloud.com/ 用户可以提交链接,应用会显示标题,主要图片和正文的前200个字符。

我们将开发一个简单的REST API Flask应用。如果你不了解Flask,你可以看这篇我以前写的文章

安装Flask:

. venv/bin/activate
pip install flask

myapp目录下创建app.py,内容如下:

from flask import Flask, request, render_template,jsonify
from goose import Goose

app = Flask(__name__)

@app.route('/')
@app.route('/index')
def index():
    return render_template('index.html')

@app.route('/api/v1/extract')
def extract():
    url = request.args.get('url')
    g = Goose()
    article = g.extract(url=url)
    response = {'title' : article.title , 'text' : article.cleaned_text[:250],'image': article.top_image.src}
    return jsonify(response)

if __name__ == "__main__":
    app.run(debug=True)

解释下上面的代码:

  1. flask包导入了Flask类、request对象、jsonify函数和render_template函数。

  2. goose包导入Goose类。

  3. 定义了/index的路由。若用户向//index发送GET请求,会渲染index.html页面。

  4. 定义了/api/v1/extract路由。我们从请求对象中获取url,然后创建了一个Goose类的实例。接着提取文章。最后创建一个json对象并返回该对象。json对象中包括标题、文本和主要图片。

  5. 最后我们使用python app.py命令来启动开发服务器,以运行应用。我们把上面的代码复制到app.py文件中。我们同时通过Debug=True开启了调试,这样当意料之外的情况出现时,浏览器就可以提供一个交互式的调试器。开启调试的另一个好处是,改动文件 之后,服务会自动重新加载。我们可以让调试器在后台运行,然后继续在我们的应用上工作。这提供了高效的开发环境。

我们将在index.html中使用Twitter Bootstrap来添加样式。我们同时使用了jQuery,以便实现keyup事件触发REST调用。退格、制表符、回车、上、下、左、右不会触发REST调用。

<!DOCTYPE html>
<html>
<head>
    <title>Extract Title, Text, and Image from URL</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="static/css/bootstrap.css">
    <style type="text/css">
    body {
      padding-top:60px;
      padding-bottom: 60px;
    }
  </style>
</head>
<body>

<div class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">TextExtraction</a>
        </div>

    </div>
  </div>

<div id="main" class="container">
    <form class="form-horizontal" role="form" id="myform">
        <div class="form-group">
            <div class="col-lg-4">
                <input type="url" id="url" name="url"  class="form-control" placeholder="Url you want to parse" required>
            </div>
        </div>
        <div class="form-group">
            <input type="submit" value="Extract" id="submitUrl" class="btn btn-success">
        </div>
    </form>
</div>

<div id="loading" style="display:none;" class="container">
    <img src="/static/images/loader.gif" alt="Please wait.." />
</div>

<div id="result" class="container">

</div>

<script type="text/javascript" src="static/js/jquery.js"></script>
<script type="text/javascript">
    $("#myform").on("submit", function(event){
        $("#result").empty();
        event.preventDefault();
        $('#loading').show();
        var url = $("#url").val()
        $.get('/api/v1/extract?url='+url,function(result){
            $('#loading').hide(); 
            $("#result").append("<h4>"+result.title+"</h4>");
            $("#result").append("<img src='"+result.image+"' height='300' width='300'</img>");
            $("#result").append("<p class='lead'>"+result.text+"</p>");
    })


    });

</script>
</body>
</html>

你可以从github 仓库中复制js和css文件。

上面的HTML文件中,表单提交触发REST调用。当我们接受到回应后,将它附加到resultdiv中。

部署到云端

在我们部署应用到OpenShift之前,我们需要先设置一下:

  1. 注册一个OpenShift账号。注册是完全免费的,Red Hat给每个用户三枚免费的Gear,可以用Gear运行你的应用。在写作此文的时候,每个用户能免费使用总共 1.5 GB 内存和 3 GB 硬盘空间。

  2. 安装 rhc客户端工具rhc是ruby gem,因此你的机子上需要装有 ruby 1.8.7以上版本。 只需输入 sudo gem install rhc即可安装 rhc 。如果你已经安装过了,确保是最新版。运行sudo gem update rhc即可升级。关于配置rhc命令行工具的详细信息,请参考: https://openshift.redhat.com/community/developers/rhc-client-tools-install

  3. 使用 rhc 的 setup 命令配置你的 OpenShift 账号。这个命令会帮助你创建一个命名空间,同时将你的ssh公钥上传至 OpenShift 服务器。

设置之后,我们可以通过如下命令创建一个新的OpenShift应用。

rhc create-app day16demo python-2.7 --from-code https://github.com/shekhargulati/day16-goose-extractor-demo.git --timeout 180

这会为我们创建一个名为gear的应用容器,并自动配置相应的SELinux政策和cgroup设置。OpenShift同时会为我们创建一个私有的git仓库,并将其克隆到本地。最后,OpenShift会自动配置DNS。应用可以在如下地址访问 http://gooseextractor-t20.rhcloud.com/

好了,这就是今天的内容。请不断反馈。


原文 Day 16: Goose Extractor--An Article Extractor That Just Works
翻译 SegmentFault

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要了解GOOSE报文的格式和数据结构,以便能够正确地解析报文并提取数据。GOOSE报文是一种通用对象操作序列(GOOSE)的通信方式,用于在现场设备之间进行通信。 GOOSE报文由多个字段组成,其中包括源MAC地址、目的MAC地址、VLAN ID、GOOSE标记等。在解析报文时,需要使用Verilog实现一个解析器,该解析器可以识别报文的各个字段,并将它们存储在FIFO中。 以下是一个简单的Verilog代码示例,可用于解析GOOSE报文并将其存储在FIFO中: ``` module goose_parser ( input clk, // 输入时钟 input reset, // 复位信号 input [7:0] rx_data, // 接收到的数据 output reg [7:0] fifo_data, // FIFO 数据 output reg fifo_valid, // FIFO 有效信号 output reg [7:0] fifo_count // FIFO 计数器 ); // 定义报文字段的位宽和偏移量 parameter MAC_ADDR_WIDTH = 48; parameter VLAN_ID_WIDTH = 12; parameter GOOSE_FLAG_WIDTH = 1; parameter MAC_ADDR_OFFSET = 0; parameter VLAN_ID_OFFSET = MAC_ADDR_WIDTH; parameter GOOSE_FLAG_OFFSET = VLAN_ID_OFFSET + VLAN_ID_WIDTH; // 定义报文字段信号 reg [MAC_ADDR_WIDTH-1:0] src_mac_addr; reg [MAC_ADDR_WIDTH-1:0] dst_mac_addr; reg [VLAN_ID_WIDTH-1:0] vlan_id; reg [GOOSE_FLAG_WIDTH-1:0] goose_flag; // 定义解析状态 reg [2:0] state; // 定义FIFO reg [7:0] fifo[255:0]; reg [7:0] fifo_head; reg [7:0] fifo_tail; reg [7:0] fifo_count; // 定义接收缓冲区 reg [7:0] rx_buf[255:0]; reg [7:0] rx_head; reg [7:0] rx_tail; reg [7:0] rx_count; // 初始化解析状态和FIFO initial begin state = 0; fifo_head = 0; fifo_tail = 0; fifo_count = 0; end // 接收缓冲区读指针 always @(posedge clk) begin if (reset) begin rx_head <= 0; end else if (rx_count > 0) begin rx_head <= (rx_head + 1) % 256; end end // 接收缓冲区写指针 always @(posedge clk) begin if (reset) begin rx_tail <= 0; end else if (rx_count < 256) begin rx_tail <= (rx_tail + 1) % 256; end end // 接收缓冲区计数器 always @(posedge clk) begin if (reset) begin rx_count <= 0; end else if (rx_count < 256 && rx_data != 8'h00) begin rx_count <= rx_count + 1; end end // 接收缓冲区写入数据 always @(posedge clk) begin if (reset) begin rx_buf[0] <= 8'h00; end else if (rx_count < 256) begin rx_buf[rx_tail] <= rx_data; end end // 解析器状态机 always @(posedge clk) begin case (state) 0: begin if (rx_count >= 14) begin src_mac_addr <= {rx_buf[1], rx_buf[2], rx_buf[3], rx_buf[4], rx_buf[5], rx_buf[6]}; dst_mac_addr <= {rx_buf[7], rx_buf[8], rx_buf[9], rx_buf[10], rx_buf[11], rx_buf[12]}; vlan_id <= {rx_buf[15], rx_buf[16]}; goose_flag <= rx_buf[17][0]; state <= 1; end end 1: begin if (rx_count >= 18) begin fifo[fifo_head] <= rx_buf[18]; fifo_head <= (fifo_head + 1) % 256; fifo_count <= fifo_count + 1; state <= 0; end end endcase end // FIFO读指针 always @(posedge clk) begin if (reset) begin fifo_tail <= 0; end else if (fifo_count > 0 && fifo_valid) begin fifo_tail <= (fifo_tail + 1) % 256; end end // FIFO计数器 always @(posedge clk) begin if (reset) begin fifo_count <= 0; end else if (fifo_count > 0 && fifo_valid) begin fifo_count <= fifo_count - 1; end end // FIFO输出信号 always @(posedge clk) begin if (reset) begin fifo_data <= 8'h00; fifo_valid <= 0; end else if (fifo_count > 0) begin fifo_data <= fifo[fifo_tail]; fifo_valid <= 1; end else begin fifo_data <= 8'h00; fifo_valid <= 0; end end endmodule ``` 在以上代码中,首先定义了报文字段的位宽和偏移量,以便可以正确地识别各个字段。然后,定义了解析状态、FIFO和接收缓冲区,以及读写指针和计数器。接下来,使用Verilog编写了一个状态机,该状态机可以将接收到的数据解析为GOOSE报文,并将GOOSE数据存储在FIFO中。最后,定义了FIFO输出信号,该信号可以将FIFO中的数据输出到其他模块中。 需要注意的是,以上代码仅供参考,需要根据实际需求进行修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值