2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RSSから情報を取得する

Last updated at Posted at 2022-05-05

Alfredのワークフローなどで、スクリプトにzshをはじめました。初心者用にメモを残します

やりたいこと

GoogleニュースのRSSから記事のタイトルとリンクURLを抽出しましょう
スクレイピングというのですかね
RSSやHTMLを解析して、情報を取得しようというものです

GoogleニュースのRSSを見てください
XMLで書かれています
XMLというのは、タグ付きのテキストデータです
ブラウザでRSSが見れますが
タグで整形されていたり、色付けされていたりするので把握しやすいと思います
HTMLに似ていますね

昨今のGoogleニュースはパーソナライズができていて
検索結果からおすすめやら、GPSから地域情報まで表示できたりするのですが、
実は、こちらは解析ができなかったのです。。。
https://news.google.com/topstories?hl=ja&gl=JP&ceid=JP:ja

RSSを取得する(cURL)

RSSのテキストデータは、cURLで取得することができます。
httpsとしてアクセスを提供しているので、HTMLと同様にcURLで取得できるのですね。
コマンドの記述としては、cURLにアドレスを渡すだけでOKです

 # このまま実行するとRSSを標準出力に返します
 # ターミナルの画面が文字だらけになるのでご注意を
curl 'https://news.google.com/rss?hl=ja&gl=JP&ceid=JP:ja'

テキストを変数に代入することもできます
これでデータとして扱えるようになりますね

 # 変数で受けると、下記のような状況が出力されます
rss=`curl 'https://news.google.com/rss?hl=ja&gl=JP&ceid=JP:ja'`
 # =>  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
 # =>                                 Dload  Upload   Total   Spent    Left  Speed
 # =>100 75756    0 75756    0     0   320k      0 --:--:-- --:--:-- --:--:--  330k

# RSSから情報を収集する(grep,sed)

次は、取得したテキストから、タイトルタグの中身を取り出すためにgrepを使います
具体的には grep -oE '<title>[^<]+</title>'というコマンドです
オプションの-oEですがoはマッチした部分のみを取り出すこと、
Eは拡張正規表現を使うことを意味します(拡張版が必須なのかはわかりません…)
引用符('')で囲まれた正規表現の意味は、<title></title>に挟まれた『<』以外の連続した文字となります

なお、『<』以外の連続した文字([^<]+)の部分を、連続した文字(.+)と指定すると、
最初の<title>と、最後の</title>がマッチして全体で1つのマッチとなってしまいます
それぞれのコマンドを書いておきますので、ターミナルで比較してみてください
正規表現は難しいですね

 # grepに『[^<]+』を指定
curl 'https://news.google.com/rss?hl=ja&gl=JP&ceid=JP:ja'|grep -oE '<title>[^<]+</title>'

# grepに『.+』を指定
curl 'https://news.google.com/rss?hl=ja&gl=JP&ceid=JP:ja'|grep -oE '<title>.+</title>'

タイトルを文字データとして扱うので、タグ自体(<title></title>)はsedの置換で取り除きます
sed 's#<title>\(.*\)</title>#\1#'
置換前は<title>\(.*\)</title>の部分ですが、バックスラッシュはメタ文字の接頭語なので
無視して<title>(.*)</title>とするとわかりやすいと思います
grepしたタイトルタグの1つ1つが置換前の文字列となります
そして、置換後は\1ですが、これは置換前の1つ目の括弧の中身を指します
置換前の括弧は1つだけなので、結局『.*』の部分=タグの中身で置き換えられることになります

これを配列に代入します

title=(`echo $rss |sed 's/ //g' | grep -oE '<title>[^<]+</title>'|sed 's#<title>\(.*\)</title>#\1#'`)

配列代入のポイントは
はじめにsed 's/ //g'として空白を削除している部分です
grepの結果は、複数ある場合は空白で区切られるので
そのまま配列に代入できるのですが
タイトルに空白があると区切り文字と判断されて、配列の数が増えてしまうのです
そのため事前に空白を無くしておきます

タイトル同様にリンク先も抽出しますが
リンクのURLには空白は入らないので、sed 's/ //g'は省いています

ここでのポイントは、タイトルとリンクでそれぞれの配列で両方の添字が
揃っていることです
そうするとロジックで扱いやすくなります

さてさて、完成です
最後に配列の添字とタイトル、リンクをechoしています

rss=`curl 'https://news.google.com/rss?hl=ja&gl=JP&ceid=JP:ja'`;title=(`echo $rss |sed 's/ //g' |grep -oE '<title>[^<]+</title>'|sed 's#<title>\(.*\)</title>#\1#'`);link=(`echo $rss |grep -oE '<link>[^<]+</link>'|sed 's#<link>\(.*\)</link>#\1#'`);for i in `seq 1 ${#title[@]}`; do echo 'No.'$i; echo ' title='$title[i]; echo ' url='$link[i]; echo; done

雑談

RSSのsearchパラメータを付けることでニュースの検索もできるので試してみました

echo 'ニュース検索のキーワードを入力してね'; read kw;rss=$(curl 'https://news.google.com/rss/search?q='`echo $kw | nkf -WwMQ | tr = %`'&hl=ja&gl=JP&ceid=JP:ja');array=(`echo $rss |sed 's/ //g' |grep -oE '<title>[^<]+</title><link>[^<]+</link>'|sed 's#<title>\(.*\)</title><link>\(.*\)</link>#\1 \2#'`); for i in {1..$((${#array[@]}/2-1))}; do echo 'No.'$i; echo ' title='$array[$((i*2+1))]; echo ' url='$array[$((i*2+2))]; echo; done

細々とした修正をしています

その1
検索ワードを変数kwで受け取り、%エンコードの変換をして
URLのパラメータに追加したのですが、
バックスラッシュのネストがうまくできませんでした
そこで、外側のバックスラッシュ(curlコマンド)を『$(コマンド)』の書式に
変更しました

その2
タイトルタグとリンクタグを別々の配列に代入していましたが、1つの配列にしました
その結果、表示する際に利用する添字を計算するようにしましたが、
かえってわかりにくいコードになってしまったかもしれません

イメージしやすいように配列の変更を例示します

変更前

タイトル配列=(タイトル1 タイトル2 タイトル3 …)
リンク先配列=(リンク先1 リンク先2 リンク先3 …)

変更後

全体配列=(タイトル1 リンク先1 タイトル2 リンク先2 タイトル3 リンク先3 …)

その3
検索結果数がgoogleニュースの仕様で、最大100件のようです
基本的に100件は検索されるようなので、最大数を100に固定して、
ロジックを簡単にしてみたのですが、
モノによっては100件もないものがあるので、結局、配列数から計算式で求めるようにしました

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?