PythonのfeedparserでRSSのデータをExcelに出力するものを作ってみた(ダラダラ解説編)

Python(Ver 2.7)でfeedparserを使ってRSSリーダーを作った。

インストール編
コード編

フリーでもRSSリーダーはたくさんあるのだが、数十のサイトの新規記事名を一覧に抽出したいと思い、PythonとExcelを連動させてRSSリーダーを作ってみた。
記事名や更新日から、いつどのような記事名でブログやニュースが更新をしているのか、統計を取りたくなった。
統計を取るなら、記事名と更新日の管理はデータベースかExcelが最適だと思っている。
しかし、データベースはいまいちわからないので(PythonでもMySQLやその他各種データベースを操作できるが)、なじみのあるExcelを使うことにした。
管理は複雑ではないので、Excelで十分である。

フリーのRSSリーダーはいくつか試してみたのだが、記事名をCSV等に出力する機能を持っているものはなかった。そのため、ソフト自体は更新記事を確認したり独自のタグやラベルを付けて読み返す分にはいいが、記事タイトルを抽出するには手作業で一つずつコピペしなければならない。

そこでPythonの登場である。

Pythonって結構なんでもできるから、抽出するやつなんかないかな~と思っていたら、やっぱりありました。さすがです。
feedparserというやつができるみたいです。
素人ながら記事名と記事URLをExcelに抽出するRSSリーダーを作ってみたので、以下にやったことをつらつら書いてきます。

【流れ】

→以下、Excel
ファイル名は「RSS.xlsm」とする。

・RSSを取得できるURLを用意した。
feed、rss、xml、rdfは取得できることを確認済み。
Atomはわらからないけど、多分できそう。

・URLをExcelシートの2ページ目に一覧にした。
URLをA列に順に入力した。

・最終記事取得日時を入力できるセルをシート2ページ目に用意した。
更新取得日時がないと、起動するたびに取得した記事名やURLが、前回取得した時と重複する。そこで、取得日以降に更新した日だけを抽出するため、取得日を入力できるセルを用意した。
取得日は、日付と時間を分けてセルを2個用意した。
例えば記事取得日をセルD1、時間をセルD2とする。
日付はYYYY/MM/DD表示(例:2019年1月1日→2019/01/01)、時間はHH:MM:SS表示(例9時6分02秒→09:06:02)とする。

・シート1ページ目(記事名と記事URLを一覧にするシート)に、抽出した結果を入力する欄を作った。
A列にサイト名、B列に記事名、C列に記事URL、D列に各記事の更新日を入れることにした。

・シート1ページ目の最終行を取得するマクロを組んだ
記事をどんどん最終行の次の行に入力していく。そこで、最終行がどこかを把握する必要がある。Pythonでも最終行を取得することはできるが、Pythonを少しでもスッキリ(文字量を少なく)させるため、最終行の取得はマクロで行うことにした。
最終行は、シート1ページ目の邪魔にならないように、シート2ページ目のセルD3に入れるようにした。

マクロは以下の通り
~~~~~~~
Sub GetLastRow()

Dim LastRow As Long

LastRow = Worksheets(1).Cells(Rows.Count, 1).End(xlUp).Row
Worksheets(2).Range(“D3”) = LastRow

End Sub
~~~~~~~

→以下、Python

・win32comでExcelのシート1ページ目、2ページ目を変数にした。
コードを記述するたびに頭から書き続けるのは長くなるので。

・前回の記事取得日時を変数にした。
ライブラリdatetimeや時間のstrftimeメソッド、strptimeメソッドを使った。
これの使い方がよくわらかなくて、結構検索した。
多くのサイトを参考にしたので、感謝申し上げる。

datetime、timeどちらにもstrftimeおよびstrptimeメソッドはあるのだが、メソッドの使い方が違うらしい。
そして、現在時刻はtimeよりdatetimeの方がうまくでき、Excelの時間はdatetimeよりtimeを使った方がうまくいったので、今回はそれぞれで使い分けた。

strptimeは、日付や時間のような文字列、日付や時間として認識して変数に入れるメソッドである。
これにより、日付や時間の比較や演算が可能となる。文字列のままだと、比較や演算はできない。
Excelのシート2ページ目のセルD1に最終取得日、セルD2に最終取得時間を入力している。
これらを文字列として取得し、それを日付や時間だと認識する。
取得した記事が、前回の最終記事日時より後に更新したかどうかを比較する。

次に、strptimeで日付や時間として認識した変数を、strftimeでそれぞれどのような表示形式になっているかを抽出する。
なぜ、これの作業が必要なのかというと、Pytohnで日時をExcelに入力すると、時間もセットで入力されてしまうからである。
PythonでExcelのセルに「2019/01/01」と入力→セルにはなぜか「2019/01/01 00:00:00」と入力されている
この問題を解決することができなかったので、下記のようにした

D = time.strptime( str( Sheet_URL.cells(1, 4).Value ), “%m/%d/%y %H:%M:%S”)
Prev_Day = time.strftime(“%Y/%m/%d”, D)

一度セルの値(シート2ページ目をSheet_URLとした)をstrメソッドを使って文字列「2019/01/01 00:00:00」とした。そしてそれを、strptimeを使って変数Dに「2019/01/01 00:00:00」という日時だと認識させ、そこからstrftimeを使って2019/01/01だけ抽出した。

→以下、Pythonにおいて、ExcelのRSSのURL最終行まで、1行ずつRSSのURLを読み込んで以下の操作を繰り返す

・Excelマクロで最終行を求める
シート2ページのセルD3にExcelの最終行が入力される。

・feedparserの出番
feedparserにExcelのRSSのURLを読み込ませる
取得したデータは配列として変数に格納した。

→ここからさらに、配列内データから順に更新時間を取得し、それが最後にRSSを取得した日より前に更新した記事か、後に更新した記事かを比較し、後に更新した記事だけを抽出するように繰り返す

・RSSの型を調べる
RSSにはいくつかの形式があるのだが、それぞれ記事の更新日時の表示形式が異なる。
2019年1月2日水曜日午前1時2分3秒を例にする。

1 feedおよびrss
例は「Wed, 02 01 2019 01:02:03 +0900」と表示される。
短い表記の曜日が入ったり、GMTからどれだけずれているかという+0900が入ったりとややこしい。
これを time.strptime(T, “%a, %d %b %Y %H:%M:%S +0900”) とすれば万事解決・・・ではなかった。
どういう違いがあるかわからないが、サイトによってはこの+0900が+0000という時間で取得されるのである。(おそらくサーバーとかによって違うのかな・・・?海外のサーバーを使っていたり・・・)
そこで、調べたら、文字列は%%でいけるらしいのである。
しかし、time.strptime(T, “%a, %d %b %Y %H:%M:%S %%”) や+0900の文字数に合わせてtime.strptime(T, “%a, %d %b %Y %H:%M:%S %%%%%”) としても、うまくいかなかった。

サイトによって+0900だったり+0000だったり・・・困ったな・・・
ということで、置換することにした。
この+0900は以後の処理では使わないので、全部+0000表記とすることにした。

コードは以下の通り

Result = feedparser.parse(URL)
T = Result.entries[2].updated.replace(“+0900″,”+0000”)
T = time.strptime(T, “%a, %d %b %Y %H:%M:%S +0000”)

URLをResultという変数に入れる。例えば、記事の3番目はResult.entries[2]に入る。
その更新日時は .update で取得できるので、replaceメソッドで+0900を+0000とした。
そして、strptimeを使ってそれぞれどういう値なのかを変数Tに格納する。

2 xmlおよびrdf
例は「2019-01-02T01:02:03+09:00」と表示される。
これも、最後の+09:00が+00:00の場合もあったため、置換した。

Result = feedparser.parse(URL)
T = Result.entries[2].updated.replace(“+09:00″,”+00:00”)
T = time.strptime(T, “%Y-%m-%dT%H:%M:%S+00:00”)

・取得した記事の時間の比較をする
前回取得した日時(Excelシート2ページ目セルD1、D2)と、記事更新の日時を比較する。
(...はコード上のタブ。)
前回の日時はPrev_DayおよびPrev_Time、記事更新の日時はT_DayおよびT_Timeとした。
「前回取得と記事更新の日時が同じ日 かつ 前回取得の時間より記事更新の時間が後」 または 「前回取得の日付より記事更新の日付が後」 ならExcelに情報を入力していく。
ただ単に日付だけ比較すると、同じ日に2回以上取得したら、前回取得した日付と同じ日付になってしまうので、取得できない。
そこで、同じ日の場合は、同じ日だけど前回取得した時間より記事更新の時間が後であれば取得するように条件をくわえる。
上記太文字において、 「~~かつ~~」または「~~」 のandとorをうまく使って1行にする自信がなかったので、同じ処理だけど条件を2行にした。うまくやれば1行でいけると思うんだけど・・・

 

if Prev_Day == T_Day and Prev_Time <= T_Time :
...情報をExcelに入力
elif Prev_Day < T_Day :
...情報をExcelに入力

 

・サイトタイトルを取得する
サイトタイトルは、URLを読み込んだfeedparserの、feed.title(メソッド?)で取得できる。

 

Result = feedparser.parse(URL)
Site_Name = Result.feed.title

 

・記事タイトルを取得する
更新記事3番目のタイトルは以下の通り

 

Result = feedparser.parse(URL)
Page_title = Result.entries[2].title

 

・記事URLを取得する
更新記事3番目のURLは以下の通り

 

Result = feedparser.parse(URL)
Page_title = Result.entries[2].link

 

→1サイトの全更新記事(配列内の全て)を更新時間を比較しながらExcelに入力していったら、次のURLに行く

 

→全てのURLを更新し終わったら、現在時刻をExcelに入力する。
datetime.datetime.now()を使う。

 

コードはこちら

コメント

タイトルとURLをコピーしました