4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】NewsAPIを使ってクリスマスニュースを収集するアプリを作る

Last updated at Posted at 2020-11-28

はじめに

chrisapp.png
(初投稿です)
Railsでクリスマスに関連するニュースを集めるごくシンプルなアプリを作ります。

NewsAPIのキーを取得し、英語の公式ドキュメントを参照してみたものの、Ruby client libraryのサンプルコードの使い方が自分にはいまいち分からず、あれこれ調べた結果自分に合った方法を見つけたので記事を書いてみました。

環境

  • Ruby 2.6.5
  • Rails 6.0.3.4

NewsAPIとは

世界中のニュースソースからデータを集めて提供してくれるAPI。
3種類のエンドポイントURIが用意されており、

リクエストパラメータ内で欲しいニュースの国とカテゴリーを指定すると最新のニュースデータを返してくれる「Top headlines」/v2/top-headlines
50,000を超えるさまざまな情報源から数百万ものニュースデータを返してくれる「Everything」/v2/everything
ニュースの情報元の情報を取得する「Sources」/v2/sourcesがあります。

APIキーの取得

register.png
名前、メールアドレス、パスワード、個人か商用かを記入し、規約に同意することで登録出来ます。
登録を済ませたらアカウント画面にあるAPIキーを保存しましょう。
(APIキーはGitなどに映らないようcredentials.yml.encか環境変数内に格納しておきます)

リクエストパラメーター

APIキーの取得が完了したら次はリクエストパラメーターを使ってエンドポイントURIを作成します。

今回はEverythingを使用し、https://newsapi.org/v2/everything?の後にパラメーター名をいくつか指定し、「クリスマス」についての記事を人気順に並び替えた情報をリクエストします。

エンドポイントURIの種類によって使えるパラメータは違うようなので、下の表を参考にしてください。ちなみにいずれのエンドポイントURIでもAPIキーのパラメーターは必須です。

エンドポイントURI例
https://newsapi.org/v2/everything?q=%E3%82%AF%E3%83%AA%E3%82%B9%E3%83%9E%E3%82%B9&sortBy=popularity&apiKey=(取得したAPIキー)

Top headlines

パラメーター名 パラメーターの値
country どこの国の記事を取得するか
ISO 3166-1で定められたアルファベット2文字の国名コードを使う
日本ならjp (※sourcesと同時使用不可)
category 記事のカテゴリー
business entertainment general health science sports technologyの7つ (※sourcesと同時使用不可)
sources 記事の情報元などを指定する
文字列を使い、,(コンマ)で区切ることで複数の情報源を指定できる
(※country categoryと同時使用不可)
q 取得したいニュース記事についての任意の文字列または単語
pageSize 一度に取得したい記事の数を指定できる
初期値で20、最大値が100
page pageSizeでの指定数よりも多くの記事が出てきた場合はこれでページングをする
apiKey 取得したAPIキー (※必須)

Everything

パラメーター名 パラメーターの値
q 取得したい記事のタイトルや本文についての任意の文字列または単語
必ずURLエンコードをする
qInTitle 取得したい記事のタイトルについての任意の文字列または単語
必ずURLエンコードをする
sources 記事の情報元などを指定する
最大20字までの文字列を使い、,(コンマ)で区切ることで複数の情報源を指定できる
domains 取得したい記事のドメインを指定する
,(コンマ)で区切ることで複数のドメインを指定できる
excludeDomains 除外したい記事のドメインを指定する
,(コンマ)で区切ることで複数のドメインを指定できる
from 指定した日付の中で最も古い記事を表示する
ISO 8601の日付表記で記述する(例: 2020-11-27 2020-11-27T20:15:25
to 指定した日付の中で最も新しい記事を表示する
ISO 8601の日付表記で記述する(例: 2020-11-27 2020-11-27T20:15:25
language 記事の言語の指定
ISO-639-1で定められたアルファベット2文字の国別コードを使う
Top headlinesのcategoryで使用したISO 3166-1とは別だが
2020年11月現在、日本語(ja)は指定できない模様
sortBy 記事の並び替えを指定できる。
オプションはrelevancy(qの値により関連する順)popularity(人気順)publishedAt(投稿順)の3つ
初期値はpublishedAt
pageSize 一度に取得したい記事の数を指定できる
初期値で20、最大値が100
page 結果をページングする
apiKey 取得したAPIキー (※必須)

このうちqqInTitleは、""で囲うことで完全一致検索が出来たり、
必ず出現して欲しい文字列には先頭に+を付けたり、
逆に除外したい文字列には-を付けたりと、欲しい記事の情報に合わせてパラメータの値を工夫することが出来ます。

Sources

上2つのエンドポイントURIにあるsourcesパラメータの「どんな情報元があるか」を調べたい場合は、このSourcesのエンドポイントURIを使うか、国別情報元一覧で調べることが出来ます。

パラメーター名 パラメーターの値
category ニュース記事のカテゴリー
business entertainment general health science sports technologyの7つ
初期値では全てのカテゴリーが出る
langage 記事の言語
やはり日本語(ja)は使えない模様
country 特定の国の記事を指定する
日本はjp
apiKey 取得したAPIキー (※必須)

リクエストパラメーターの作成が終わったら、ブラウザのURL欄に入力し、アクセスしてみましょう。するとこのように大量のJSONデータ(レスポンスオブジェクト)が返却されます。

スクリーンショット 2020-11-28 14.43.16.png
(なぜかエンコード済みの日本語部分がデコードされてる)

レスポンスオブジェクト

画像のレスポンスオブジェクトを要約するこんな感じになります。

レスポンスオブジェクトの例(Everything)
{"status":"ok",
"totalResults":20,
"articles":[
  {"source":{"id":null,"name":"情報元名"},
   "author":"著者",
   "title":"記事タイトル",
   "description":"ニュース記事の本文",
   "url":"記事URL",
   "urlToImage":"記事の画像URL",
   "publishedAt":"記事の投稿日",
   "content":":記事の引用元URL"
  },
  {(中略)}
]
}

上のJSONデータの3行目の"articles"の値がハッシュ入りの配列として返却されているのが分かります。

ビューファイル内でニュースの見出しを作りたい場合は、繰り返し処理(eachメソッド)を使い
配列articlesの中から一つずつ記事のハッシュを取り出します。
<%= article["記事のハッシュのキー名"] %>と記述することで取得した記事についての任意の情報を表示できます。

以下がその配列キー名とその内容です。

Top headlines / Everything

キー名 内容
source 記事の情報元(idnameで指定する)
author 記事の著者
title 記事のタイトル
description 記事の本文
url 記事のURL
urlToImage 記事の画像URL
publishedAt 記事が投稿された日付と時刻(UTC/協定世界時での表示)
content 引用元や記事の内容(最初の200文字のみ表示)

Sources

キー名 内容
id 記事の情報元の識別子
name 情報元の名前(主にドメイン名)
description 情報元の情報
url サイトURL
category 情報元から推測されたニュースのカテゴリー
langage 記事の言語
country 記事の発信元の国、あるいはその国についての記事

アプリでの実装

通常通りにコントローラーとビューを作成します。モデルは必要ありません。

app/controllers/news_controller.rb
class NewsController < ApplicationController
  require "open-uri"
    def index
      api = Rails.application.credentials.news_api[:api_key]
      uri = "https://newsapi.org/v2/everything?q=%E3%82%AF%E3%83%AA%E3%82%B9%E3%83%9E%E3%82%B9&sortBy=popularity&apiKey=#{api}"
      article_serialized = open(uri).read
      @articles = JSON.parse(article_serialized)
    end
end

credentials.yml.encに格納されたAPIキーを取り出してURIに式展開で取り付けて、
それを変数化した後にopenメソッドでアクセスし、readメソッドでJSONを読み込みます。
parseメソッドでJSON形式の文字列をRubyの文字列に変換しています。

app/views/news/index.html.erb
<header>
  <h1>⭐️クリスマスニュース⭐️</h1>
  <p>Powered by <a href="https://newsapi.org">News API</a></p>
</header>
<hr>

<div class="articles">
  <% @articles["articles"].each do |article| %>
    <div class="article">
      <div class="title">
        <%= link_to article["title"], article["url"] %>
      </div>
      <div class="wrapper">
        <div class="date">
          <%= article["publishedAt"] %>
        </div>
        <div class="source">
          <%= article["source"]["name"]%>
        </div>
        <div class="image">
          <%= image_tag article["urlToImage"],:size =>'240x160' %>
        </div>
        <div class="content">
          <%= article["description"] %>
        </div >
      </div>
    </div>
  <% end %>
</div>

レスポンスオブジェクトとして返却された記事のハッシュの中には、さらに"source"キーの値として、もう一つ記事の情報元を示すハッシュが格納されてます。
なので、情報元についての表記をしたいときは<%= article["source"]["name"]%>と記述することで情報元のサイト名などを取り出すことが出来ます。

あとはCSSで装飾をして完成です。

app.gif

CSS(一応載せます)
app/assets/stylesheets/news/index.css

body {
  background-color: #588C73;
}

header {
  text-align: center;
}

hr{
  border: none;
  border-top: 2px dashed #ff5c00;
}

.articles {
  display: flex;
  flex-wrap: wrap;
}

.wrapper {
  padding: 5px;
}

.title {
  border-radius: 10px 10px 0 0;
  padding: 10px 5px 5px 5px;
  background-color: #a20a0a;
  height: 4.5em;
}

.title > a {
  color: #f2ae72;
  text-decoration: none;
}

.date {
  font-size: 0.8em;
  color: #588C73;
}

.source {
  font-size: 0.8em;
  color: #588C73;
}

.image {
  text-align: center;
  padding-top: 5px;
  padding-bottom: 5px;
}

.article {
  border-radius: 10px;
  width: 30%;
  margin: 20px 15px;
  color: #d96459;
  background-color: #f2e394;
  border: 1px solid #d96459;
}

.content {
  font-size: 0.9em;
}

備考

NewsAPIを使用した際は、帰属を示すために"Powered by News API"という文字列でhttps://newsapi.orgへのリンクを貼るよう規約内に指示があるので忘れずに記載しておきましょう。

まとめ

公式ドキュメントでは、NewsAPIのgemをインストールして記事を取得する方法が記されていましたが、どういうことかそのライブラリ自体が非公式だとされていました。
なので結局どうすればいいのか分からずあれこれ調べた結果このやり方に行き着きました。

この方法ならば新しいgemを追加する必要もなく、コントローラーにrequire "open-uri"を記述することでエンドポイントURIを開き、簡単にニュース記事を収集するアプリを作ることが出来ます。

参考

Documentation - News API
open uri - trying to use a news API with rails application - Stack Overflow

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?