やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

NewsApiを使ってみた

 WebAPI。ニュースを取得する。JSONで返る。2019-09-16時点の調査。

成果物

情報源

 上記のように記せと言われたので書いておく。

手順

  1. NewsApiアカウントを取得する
  2. APIキーを調べる
  3. APIを調べる
  4. コードを書く
  5. 実行する

ニュースの取得

 NewsAPIにてニュース記事を取得できるらしい。ただ、結果のJSONを見てみると、本文をすべて取得できるわけではなさそう。URL先をみる必要がある。つまり、本文の全文はHTMLスクレイピングによって抽出せねばならない。それに関しては今回はやらない。

価格プラン

 もちろん無料の「開発者」プラン。

  • 15分遅れ
  • 1ヶ月前までの記事のみ
  • 500回リクエスト/1日
  • NewsAPI.orgの帰属表示(Powerd by News API

利用規約

SLA(サービスレベル契約)

各プランのサービスレベルを達成および維持しない場合、将来の月額サービス料金に対して25%のクレジットを受け取る資格があります。

毎月の稼働率%=(合計リクエスト試行-失敗したリクエスト)/合計リクエスト試行* 100

 たぶん価格プラン「企業」の場合に関係する。99.95%の稼働時間SLAと書いてあったから。無料プランの「開発者」はアップタイムSLAなしとあった。おそらく関係ないのだろう。

 だが、もしかすると将来「お前、以前こんなに何度も使ったよな? あのときの超過分25%を支払えよ」と言われるかもしれない。

  • 英語読めないし、文化や法律の違いなど、どんな理由で後出し難癖つけられるかわからない
  • リクエスト上限もいずれ改悪されて少なくなるかも
  • 時が経ち、忘れたアカウントをハックをされて勝手にリクエストされ、請求だけされるかも

 念のため1日1回くらいにしておこう。

スタートガイド

curl https://newsapi.org/v2/top-headlines -G \
    -d country=jp \
    -d apiKey=****

ドキュメント

認証

curl https://newsapi.org/v2/top-headlines -G \
    -d country=jp \
    -H 'X-Api-Key:****'
curl https://newsapi.org/v2/top-headlines -G \
    -d country=jp \
    -H 'Authorization: Bearer ****'

 apiKeyより上記のほうがセキュリティ高いので推奨。

エンドポイント

内容 エンドポイント
トップ /v2/top-headlines
すべて /v2/everything
ソース /v2/sources

トップの主な引数

 トップニュースを取得できれば良いだろう。主な引数は以下。

引数
country ja
categoly business entertainment general health science sports technology
source source indexcountry,categolyと併用不可。
pagesize デフォルト20。最大100今回はなぜか30件までしか取得できず
page ページ位置
q キーワード

コード

 ファイルがあるかぎり1日1回しか実行しない。

run.sh

get_news_api_key() { cat "${HOME}/root/work/record/pc/account/newsapikey"; }
request() {
    NEWS_API_KEY="${NEWS_API_KEY:-"`get_news_api_key`"}"
    curl https://newsapi.org/v2/top-headlines -G \
     -d country=jp \
     -d pageSize=100 \
     -H "X-Api-Key:${NEWS_API_KEY}"
}
# $1: NewsApi結果JSONファイルパス
is_run() { [ ! -f "$1" ] && echo 'true' || is_not_today "$1"; }
# $1: NewsApi結果JSONファイルパス
is_not_today() {
    # ファイルが存在し、更新日時が今日なら falseを返す
    updated="`date +"%Y-%m-%d" -r "$1"`"
    [ "$updated" = "`date +"%Y-%m-%d"`" ] && echo 'false' || { rename_file "$1"; echo 'true'; }
}
# $1: NewsApi結果JSONファイルパス
format_json() {
  local name="_`basename "$1"`"
  local dir="`dirname "$1"`"
  cat "$1" | python3 -c 'import sys,json;print(json.dumps(json.loads(sys.stdin.read()),indent=4,ensure_ascii=False))' > "${dir%/}/${name}"
}
# TodayNews.jsonファイルが既存だが更新日時が今日でないときYYYYmmdd.jsonにリネームする。
# $1: NewsApi結果JSONファイルパス
rename_file() {
  local today="`date +"%Y%m%d"`"
  local updated="`date +"%Y%m%d" -r "$1"`"
  [ "$updated" != "$today" ] && mv "$1" "${updated}.json"
}
run() {
  local TODAY_NEWS="${TODAY_NEWS:-TodayNews.json}"
  [ 'false' = "`is_run "${TODAY_NEWS}"`" ] && exit 1;
  echo "`request`" > "${TODAY_NEWS}"
  format_json "${TODAY_NEWS}"
  cat "${TODAY_NEWS}"
}
run
  • APIキー
    • APIキーはget_news_api_key()にあるとおり所定のファイルに保存してある
    • 変えたいときは環境変数に設定して実行する(NEWS_API_KEY=**** run.sh
  • 入出力ファイル
    • カレントディレクトリで実行する
    • 出力ファイル名のデフォルトはTodayNews.json
    • 変えたいときは環境変数に設定して実行する(TODAY_NEWS="some_file_name.json" run.sh
  • 整形ファイル
    • _TodayNews.jsonファイルはスペースや改行で見やすくなっている。確認用。
  • 過去ファイル
    • 以前のTodayNews.jsonファイルは変更日時に基づいてリネームされる

実行

 取得できたが、100件でなく30件しか取得できない……。以下では20件のみだったらしい。

 どうやらNewsApi側で制限しているようだ。/v2/top-headlinesは30件までしか取得でいないのだろう。100が上限と書いてあるのに。騙された。

 対して/v2/everythingなら100件取得できるらしい。本当かな。

問題

  • 30件までしか取得できない
  • ニュースのカテゴリが指定できていない
  • 今日のニュースだけでなく前日の分まで出る
  • 時間によっては過去に取得したものと重複する

 特に最後のが問題。取得した時間にかかわらず、重複なく取得したい。

 さらに以下のような根本的な問題もある。

  • いつかサービス終了する

 別のAPIを複数使うことでリスク分散したい。APIを切り替えれるような設計にしたい。その上で、同一インタフェースによりアクセスできるのが望ましい。

 これは大変そうだ。各社ばらばらのURLやパラメータやJSONなので。

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux