DB内にある最新より新しいニュースだけを取り込む。
成果物
コード
# $1: JSONテキスト, $2: JSONパス json_extract() { sqlite3 :memory: 'select json_extract(readfile('\'"$1"\''), '\'"$2"\'');'; } make_insert_stmt() { echo 'insert into news(published,url,title,body) values('\'"$1"\'','\'"$2"\'','\'"$3"\'','\'"$4"\'');'; } # $1: DB内最新ニュース一意特定値(published,url,title。デリミタ\n) # $2..3: NewsApi JSON(publishedAt,url) is_new() { local latest_published="`echo "$1" | sed -n 1P`" local latest_url="`echo "$1" | sed -n 2P`" echo "$latest_published $2 `[[ "$2" < "$latest_published" ]]`" [[ "$2" < "$latest_published" ]] && return 0 || [[ "$3" = "$latest_url" ]] && return 0; return 1; } # $1: NewsApiJSONパス run() { local json_path="$1" local insert_sql="insert.sql" [ 'ok' != "`json_extract "$json_path" '$.status'`" ] && { echo 'エラー。JSONのstatusがokでない。: '"`json_extract "$json_path" '$.status'`" 1>&2; exit 1; } # DB内の最新ニュースを一意特定するデータを取得する(published,url,title) local db="news.db" local latest_news="`sqlite3 "$db" < 'get_latest.sql'`" # SQLファイル内容を空にする(さもなくば連続使用時に前の分と合わせて追記されてしまう) : > "$insert_sql" local totalResults="`json_extract "$json_path" '$.totalResults'`" for idx in $(seq 0 $(expr $totalResults - 1)); do # JSONから項目を抽出する local published="`json_extract "$json_path" '$.articles['"$idx"'].publishedAt'`" local url="`json_extract "$json_path" '$.articles['"$idx"'].url'`" local title="`json_extract "$json_path" '$.articles['"$idx"'].title'`" local body="`json_extract "$json_path" '$.articles['"$idx"'].description'`" # とりあえずdescriptionで代用する is_new "$latest_news" "$published" "$url"; [ $? -eq 0 ] && break; # totalResultsが多すぎたとき各項目はNULL(空文字)になる。このときは終了する。JSONが正しい限り起こり得ない。 [ -z "$title" ] && { echo "JSON不正。titleが空。totalResults:$totalResults,idx:$idx" 1>&2; break; } # insert文を作る make_insert_stmt "$published" "$url" "$title" "$body" >> "$insert_sql" done sqlite3 "$db" < "$insert_sql" } run "$1"
追加
前回から追加された部分は以下。
is_new() { local latest_published="`echo "$1" | sed -n 1P`" local latest_url="`echo "$1" | sed -n 2P`" echo "$latest_published $2 `[[ "$2" < "$latest_published" ]]`" [[ "$2" < "$latest_published" ]] && return 0 || [[ "$3" = "$latest_url" ]] && return 0; return 1; }
run() { ... # DB内の最新ニュースを一意特定するデータを取得する(published,url,title) local db="news.db" local latest_news="`sqlite3 "$db" < 'get_latest.sql'`" ... for idx in ... ... is_new "$latest_news" "$published" "$url"; [ $? -eq 0 ] && break; ... ... }
JSONのarticles
配列を1件ずつ、DB内最新ニュースと見比べる。新しいなら挿入する。同じか古いならそこで終了。ニュースの一意特定にはpublishedAt
とurl
を用いている。
動作確認
以下のような手順でテストデータを用意する。
- NewsApiを取得する(NewsApiでカテゴリ別にニュースを取得する)
- 1で取得したJSONファイルを
news.json
とでもリネームしておく - 2のJSONファイルをコピーする
- 3のうち最新(先頭)の2件くらいを削除して
news_old.json
とでもリネームしておく - SQLite3DBファイル作成する(NewsApiで得たニュースを保存するSQLite3テーブルを考える)
- 3のJSONファイルをDBファイルに取り込む(NewsApiのJSONからSQLite3DBファイルへ挿入する)
この状態で、上記コードを実行し、最新2件だけが追記されることを確認する。
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13
- bash 4.4.12(1)-release ※
- SQLite 3.29.0 ※
- MeCab 0.996ユーザ辞書
$ uname -a Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux