shimomo / autorace-news-collector
Collects the latest AutoRace news from official feeds and APIs.
Package info
github.com/shimomo/autorace-news-collector
pkg:composer/shimomo/autorace-news-collector
Requires
- php: ^8.4
- ext-dom: *
- ext-json: *
- ext-libxml: *
- symfony/http-client: ^8.0
Requires (Dev)
- ergebnis/composer-normalize: ^2.52
- laravel/pint: ^1.27
- phpunit/phpunit: ^13.2
- vimeo/psalm: ^6.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
オートレースの最新記事を、公式サイトの RSS、日刊スポーツの Atom、各レース場公式サイトの WordPress REST API、公式 YouTube チャンネルのフィードから集めて Article の配列として返す PHP ライブラリです。
保存・既読管理・重複排除は呼び出し側の責務です。HTML の一覧ページはスクレイピングしません。
📦 インストール
PHP 8.4 以上(ext-dom、ext-json、ext-libxml)。
composer require shimomo/autorace-news-collector
🚀 使い方
use Shimomo\AutoraceNewsCollector\Collector; $collector = Collector::default(); $result = $collector->collect(since: new DateTimeImmutable('-1 day')); foreach ($result->articles as $article) { // $article->source, $article->id, $article->title, $article->bodyText, ... } foreach ($result->failures as $failure) { // $failure->source, $failure->url, $failure->message, $failure->previous }
ソースをキーで絞る場合は only() / without() を使います。存在しないキーと空の only() は InvalidArgumentException になります(設定漏れで黙って 0 件にならないため)。maxPages は各レース場(WordPress)で since を指定したときのページ送り上限です(既定 3)。
$collector = Collector::default(maxPages: 5)->only('autorace.jp', 'kawaguchi'); $collector = Collector::default()->without('youtube');
独自の組み合わせは Collector に直接渡します。
use Shimomo\AutoraceNewsCollector\Collector; use Shimomo\AutoraceNewsCollector\Http\HttpFetcher; use Shimomo\AutoraceNewsCollector\Http\NativeSleeper; use Shimomo\AutoraceNewsCollector\Sources\AutoraceJpSource; use Shimomo\AutoraceNewsCollector\Sources\WordPressSite; use Shimomo\AutoraceNewsCollector\Sources\WordPressSource; use Symfony\Component\HttpClient\HttpClient; $fetcher = new HttpFetcher(HttpClient::create(), new NativeSleeper(), interval: 2.0); $collector = new Collector([ new AutoraceJpSource($fetcher), new WordPressSource(WordPressSite::kawaguchiNews(), $fetcher), ]);
HttpFetcher は User-Agent、タイムアウト(既定 15 秒)、リクエスト間隔(既定 1 秒)を持ちます。再試行が要るときは symfony の RetryableHttpClient で包んだクライアントを渡してください。
🧩 Laravel から使う
このパッケージは Laravel に依存しません。ServiceProvider、config、artisan コマンドはアプリ側に置いてください。
since は DateTimeInterface を受けるので now()->subDay() をそのまま渡せます。Article::toArray() は snake_case の配列を返すので updateOrCreate に渡せます(id は主キーと衝突するため source_id になります)。categories は配列なので、モデル側で 'categories' => 'array' の cast(JSON カラム)が要ります。published_at は DateTimeImmutable のままで、保存時のタイムゾーンはアプリの設定に従います。
$result = Collector::default()->collect(since: now()->subDay()); foreach ($result->articles as $article) { NewsArticle::updateOrCreate( ['source' => $article->source, 'source_id' => $article->id], $article->toArray(), ); }
テストでは Sources\ArraySource を Collector に差し込むとネットワークに出ません。since の扱いは実ソースと同じです。
use Shimomo\AutoraceNewsCollector\Sources\ArraySource; $collector = new Collector([new ArraySource('autorace.jp', 'AUTORACE.JP', [$article])]);
📰 収集元
source |
表示名 | 取得経路 | 本文 | 1回の件数 |
|---|---|---|---|---|
autorace.jp |
AUTORACE.JP | RSS | フィードに本文 HTML | 15 |
nikkansports |
日刊スポーツ | Atom + 記事ページ | 記事ページから抽出 | 10 |
kawaguchi |
川口オートレース | WordPress REST(お知らせ・選手インタビュー) | API に本文 | 最大 100 |
isesaki |
伊勢崎オートレース | WordPress REST | API に本文(空の投稿が多い) | 最大 100 |
hamamatsu |
浜松オート | WordPress REST | API に本文 | 最大 100 |
sanyo |
山陽オート | WordPress REST | API に本文 | 最大 100 |
youtube |
オートレース公式 YouTube | Atom | 動画説明文 | 15 |
飯塚オート公式は RSS も API も無いため対象外です。
📄 Article
| プロパティ | 型 | 内容 |
|---|---|---|
source |
string |
ソースキー |
sourceName |
string |
表示名 |
id |
string |
ソース内で安定した ID。(source, id) で重複判定できる |
url |
string |
記事 URL |
title |
string |
|
categories |
list<string> |
ソース固有の分類 |
publishedAt |
DateTimeImmutable |
Asia/Tokyo |
summary |
?string |
フィードの要約 |
bodyHtml |
?string |
整形済み本文 HTML(script 等を除去、URL を絶対化) |
bodyText |
?string |
本文のプレーンテキスト |
thumbnailUrl |
?string |
アイキャッチまたは本文先頭画像 |
toArray() で snake_case の配列になります。id は source_id、publishedAt は DateTimeImmutable のままです。
🔁 since と重複
collect(since)はpublishedAt >= sinceの記事を返します。省略時は各ソースが1回で返せる範囲をそのまま返します。- 日刊スポーツの記事は AUTORACE.JP にも「【日刊提供】」として載るため、同じ内容が2ソースから返ります。URL も ID も異なるのでライブラリでは束ねません。
⚠️ 失敗の扱い
collect() は例外を投げません。ソース全体の失敗(HTTP エラー、フィードの解析失敗)も、1件単位の失敗(必須項目の欠落、日刊の記事ページ取得失敗)も failures に SourceFailure として積まれ、他の記事は返ります。日刊の記事ページ取得に失敗した記事は要約だけを持つ Article になります。
⏱️ 実行間隔の目安
日刊スポーツの Atom は最新 10 件しか無く、SG 開催日は 1 日に 10 本を超えます。1〜2 時間おきに実行してください。各サイトへのアクセスは 1 秒間隔です。
📝 注意
AUTORACE.JP のサイトポリシーは無断転載・複製・公開を禁じています。本ライブラリは本人の私的な保存に限って使うものです。
🛠️ 開発
composer test # phpunit composer analyse # psalm composer lint # pint --test composer fix # pint composer normalize # composer.json の整形
テストはネットワークへ出ません。tests/fixtures/ は 2026-10-13 に採取した実レスポンスです。