雑記帳

整理しない情報集

更新情報

FreshRSSをセルフホストして快適な情報収集生活

公開日:

カテゴリ: ソフトウェア

ニュースや公式リリース情報など、情報社会の今日は日頃の情報収集が大切です。しかし、複数の情報ソースをすべて見に行くのは非常に大変です。そこでWebサイトから新着情報を収集する際に便利なツールを使ってみます。

情報の収集について

情報の取得は主に2点を考える必要があります。1点目は情報をどこからどのようにして取得するか、2点目は収集した情報をどのようにして集約・表示するかです。

前者にはRSSやAtomといった情報を配信するための専用フォーマット(XML)が存在し、Webサイトがその形式で情報を発信していれば、対応するアプリで手軽に情報を取得することができます。この配信フォーマットに非対応の場合、基本的にWebサイトのソースコードから解析して情報を取得(スクレイピング)するしかありません。

後者はRSS/Atomの対応アプリケーションで集約・表示することになりますが、方法は千差万別です。専用のアプリやソフトウェアを用いるもの、ブラウザに機能が搭載されているもの(Vivaldiなど)、RSS/Atomを集約・表示するWebサービスを利用する方法(Feedlyや旧Google リーダーなど)、はたまた自分でサーバを立てて動かすものなどがあります。

今回は自分でサーバを立てて動かすセルフホスト方式のFreshRSSというWebアプリケーションを使います。RSSやAtomに加えてXMLやHTMLをスクレイピング可能なため、設定次第で幅広いWebサイトの情報を集めることができます。

ちなみにRSS/Atomはかなり昔から存在しており、SNSの発達でRSSやAtomの配信は近年徐々に縮小傾向にあります。ブログサービスではRSS/Atom配信が標準機能であるため健在で、さらにブログの枠組みを使ったWebサイト(WordPressなど)でも使えるサービスが多く存在します。逆に、それ以外のサービスはいつまで配信されるかは少々不透明ではあります。

FreshRSSの特徴

  • セルフホスト型サーバアプリ・PHPスクリプト
  • オープンソースソフトウェア
  • RSSやAtomに加えてXMLやHTMLをスクレイピング可能
  • フィードの自動取得機能(CRON)
  • 未読管理・フィルタ・検索・ブックマーク機能

本記事では扱いませんが、FreshRSSには以下の機能もあります。

  • OIDCログイン
  • JSONデータの購読
  • 取得データをフィードとして再配信
  • スマホ向けレイアウト・ダークモード対応

インストール

Dockerで構築するのが簡単です。PHPスクリプトのため、制約に引っかからなければPHPのWebホスティングサービスでも動作すると思われます。

以下の設定は例です。コンテナサイズは小さいものを使いたいため、alpineイメージを採用しています。

services:
  freshrss:
    image: freshrss/freshrss:alpine
    container_name: freshrss
    restart: unless-stopped
    environment:
      - TZ=Asia/Tokyo
      - CRON_MIN=2,32
    logging:
      options:
        max-size: 10m
    volumes:
      - ./data:/var/www/FreshRSS/data
    ports:
      - "8080:80"

CRON_MIN環境変数に自動で情報の再取得を行う分をセットします。上記の例では毎時2分と32分に再取得を行います。

情報取得ソースの追加

ソースのURLにはRSS/AtomのURL以外では、一般公開されているページ、あるいはAPIとして仕様が公開されているURLを使うようにしましょう。

RSS/Atom

基本的にRSS/AtomのURLを入力して追加ボタンを押すだけで完了です。対象のWebサイトにRSS/Atomの<link rel="alternate">タグがあれば、そのページのURLを入力すると自動でRSS/AtomのURLに置き換わります。

HTML+XPath

こちらはスクレイピングするページのURLと、記事のタイトルやURLをはじめとした情報が出力されている要素を自分で指定する必要があります。記述形式はXPathという記法が採用されており、クローラーなどでよく使用されています。

色々高度なことができますが、今回のような新着を取得するような用途では、次項の記法を知っておけば十分でしょう。

XPath

Google ChromeなどのChromium系ブラウザでは開発者ツールのコンソールに$xという関数が定義されており、引数のXPath文字列を入れて実行すると解析して結果を確認することができます。覚えておくと非常に便利です。

基本記法

XPathではルートからのHTML要素のネストをスラッシュ区切りで表記します。例えば、HTML要素内のBODY要素は以下のように表記します。

/html/body

スラッシュ2個//を使用すると途中の階層を省略できます。

//body

要素内のテキストを取得するには、該当の要素でtext()を使用することで取得できます。

//div/text()

要素の属性値はアットマーク@属性名を使用することで取得できます。

//a/@href

大かっこを使用すると条件を設定することができます。数値が入力された場合は、n番目の要素を取得します(プログラミングの配列とは異なり、0ではなく1から始まります)。次の例ではdiv#news要素を取得します。

//div[@id="news"]

基本的に完全一致や部分一致の判定なので、CSSのクラスに複数の値が指定されている場合に分割して判定するような機能はありません。あまりきれいではありませんが、次のように前後にスペースを連結して部分一致検索することで実現できます。

部分一致はcontains()で判定できます。

//div[contains(concat(" ",normalize-space(@class)," ")," class-name ")]

その他、論理演算も使用可能です。

//div[contains(...) and contains(...)]
//div[contains(...) or contains(...)]
//div[not(contains(...))]

FreshRSSでよく使うもの

Webサイトの更新情報はリストや表になっていて、1要素ごとに同じレイアウトをループしていることがほとんどだと思います。そこで繰り返し探索となる要素を設定し、その要素から相対的にタイトルやリンクを取得していきます。

descendant::は子孫要素を表します。FreshRSSに「項目」で指定した要素を基準として、その子孫要素を取得します。次の例では「項目」で指定した要素内にあるh3要素を取得します。

descendant::h3

指定方法の定義だけ見ても分かりにくいので、簡単な例を載せておきます。

<div id="news">
	<div>
		<h3><a href="./link2">記事のタイトル2</a></h3>
		<p>記事の概要2</p>
		<p class="date">2025/05/01</p>
	</div>
	<div>
		<h3><a href="./link1">記事のタイトル1</a></h3>
		<p>記事の概要1</p>
		<p class="date">2025/04/01</p>
	</div>
</div>
項目
//div[@id="news"]/div
項目のタイトル
descendant::a/text()
項目のコンテンツ
descendant::p[1]/text()
項目のリンク
descendant::a/@href
項目の日付
descendant::p[contains(@class,"date")]
カスタム日時フォーマット
Y/m/d

便利な使い方

表示の優先度を分ける

FreshRSSには表示させるリストを指定することができます。指定方法は4種類あります。

  • 重要なフィードに表示する: 重要のリストにも表示
  • メインストリームで表示する: デフォルトの表示(指定しない場合はすべて表示)
  • カテゴリで表示する: メインには表示せず、カテゴリ別のリストのみに表示
  • 非表示にする(アーカイブ): その情報ソース単独のリストのみに表示

優先度が低いもので、更新速度が非常に早くメインストリームに流してしまうと他の情報が流れてしまうものは、カテゴリのみの表示もしくは非表示にすると良さそうです。

取得時の除外フィルタ

多くのRSS/Atomリーダーでは検索機能があり未読状態やキーワードで検索できますが、それらの多くは取得後のデータの中から自分の操作でフィルタを行うものであり、FreshRSSでいうところのメインストリームでは除外されません。

FreshRSSではデータの取得時点でフィルタを行えます。最終更新日だけが変わっただけの古い記事や広告しか載っていない記事などが流れてくるWebサイトでは、フィルタを行うと効果的です。構文はキーワード検索で使えるフィルタ構文がそのまま使えます。

発行日時が2ヶ月以内に絞り込む例

pubdate:P2M/

タイトルに「PR」が含まれるものを除外する例(このままでは単語の一部にPRが含まれる記事も除外されるためご注意ください)

!intitle:PR

RSS/Atom取得時のUserAgent指定

極稀に推奨環境外からのアクセスに対してエラーを返すWebサイトがあります。スクレイピングをしているならともかく、RSSやAtomはそれ自体で完結したフォーマットですので、どのようなソフトウェアで取得しても内容は変わりません(多くの場合、通常のWebページに適用されるべきエラーがRSSやAtomにも適用されてしまっているものと思われます)。

UserAgentで判定されているWebサイトであれば、高度な設定の中の「フィードを取得するときのユーザーエージェント」で、データ取得時のUserAgentを設定できます。

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36

ちなみに高度な設定では、記事取得時のクッキーやHTTPヘッダなども設定することができます。RSSやAtomを取得する際は出番は滅多にありませんが、トークンなどを指定して直接APIにアクセスすることができるので、JSONデータの購読など使い方によっては便利かもしれません(Authorization: Bearer ~など)。

カテゴリ: ソフトウェア