目次
サンプル・プログラムの実行例
サンプル・プログラムのダウンロード
| RSSmaker.php | サンプル・プログラム本体 |
| pahooInputData.php | データ入力に関わる関数群。 使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。 |
| pahooRSS.php | RSS処理に関わるクラス pahooRSS。 RSS処理に関わるクラスの使い方は「PHPで作るRSSビューア」「[/e-soul/webtech/php02/php02-38-01.shtm:title=PHPでRSSを作る]」「[/e-soul/webtech/php02/php02-52-01.shtm:title=PHPでRSSを作る(その2)]」を参照。include_path が通ったディレクトリに配置すること。 |
| pahooScraping.php | RSS処理に関わるクラス pahooScraping。 スクレイピング処理に関わるクラスの使い方は「PHPで作るRSSビューア」を参照。include_path が通ったディレクトリに配置すること。 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 2.0.0 | 2026/01/10 | 大幅改訂 |
| 1.4.4 | 2025/06/06 | yomiuri() -- コンテンツ構造変更対応 |
| 1.4.3 | 2025/03/16 | rnnnews() -- 生の & を & に置換 |
| 1.4.2 | 2025/02/19 | ynaCoKr() -- bug-fix |
| 1.4.1 | 2024/12/28 | ynaCoKr() -- 記事URLのパラメータを削除 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 2.0.1 | 2025/08/11 | getParam() bug-fix |
| 2.0.0 | 2025/08/11 | pahooLoadEnv() 追加 |
| 1.9.0 | 2025/07/26 | getParam() 引数に$trim追加 |
| 1.8.1 | 2025/03/15 | validRegexPattern() debug |
| 1.8.0 | 2024/11/12 | validRegexPattern() 追加 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 1.3.1 | 2024/08/01 | atom() -- 修正 |
| 1.3.0 | 2024/04/20 | RSS 0.91対応 |
| 1.2.0 | 2024/04/20 | 名前空間 NS_dc を変数に変更;複数RSSに対応のため |
| 1.1.0 | 2023/09/24 | メーカー系のメソッド、プロパティを追加 |
| 1.0.0 | 2023/09/18 | 初版 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 1.2.1 | 2024/10/31 | __construct() 文字化け対策 |
| 1.2.0 | 2024/09/29 | getValueFistrXPath() 属性値でない指定に対応 |
| 1.1.0 | 2023/10/15 | getValueFistrXPath() 追加 |
| 1.0.1 | 2023/09/29 | __construct() bug-fix |
| 1.0.0 | 2023/09/18 | 初版 |
サンプル・プログラムの流れ
RSS 1.0を作成するユーザー関数 makeRSS10、RSS 1.1を作成するユーザー関数 makeRSS1w は、「PHPでRSSを作る」をそのまま流用した。
準備:pahooInputData 関数群
また、各種クラウドサービスに登録したときに取得するアカウント情報、アプリケーションパスワードなどを登録した .pahooEnv ファイルから読み込む関数 pahooLoadEnv を備えている。こちらについては、「各種クラウド連携サービス(WebAPI)の登録方法」をご覧いただきたい。
準備:pahooRSS クラス
pahooRSS.php
15: class pahooRSS {
16: private $rssURL; //RSS URL
17: private $items; //チャネル情報、フィード情報
18: private $language; //使用言語(初期値は日本語)
19: private $error; //エラー・メッセージ
20: private $parseTable; //定義済みパーサ一覧
21: private $templateRSS10; //RSS1.0テンプレート
22: private $templateRSS11; //RSS1.0テンプレート
23: private $templateRSS20; //RSS1.0テンプレート
24: private $templateAtom; //Atomテンプレート
25: private $nameSpaces; //名前空間
26: private $userParseTable; //ユーザー定義パーサ一覧
27: private $errorTable; //エラー番号 => エラー・メッセージ 一覧
28: /**
29: * プロパティ $items の構造
30: *
31: * 添字[0] チャネルの情報
32: * [0]['title'] タイトル
33: * [0]['link'] URL
34: * [0]['rss'] RSSのURL
35: * [0]['creator'] 製作者
36: * [0]['copyright'] 著作権者
37: * [0]['description'] 説明
38: *
39: * 添字[1以上] フィードの情報
40: * [#]['title'] タイトル
41: * [#]['link'] URL
42: * [#]['description'] 説明
43: * [#]['date'] 更新日時(ISO 8601形式)
44: */
45:
RSS を PHP の連想配列として扱えるようにする。連想配列の構造は、上記コメントを参考にしていただきたい。
RSS 1.0, RSS 1.1, RSS 2.0, Atom の読み込み/作成に対応している。
PHPのクラスについては「PHPでクラスを使ってテキストの読みやすさを調べる」を参照されたい。
準備:pahooScraping クラス
pahooScraping.php
13: class pahooScraping {
14: private $dom; //DOMDocument
15: private $xpath; //DOMXPath
16: private $language; //使用言語(初期値は日本語)
17: private $error; //エラー・メッセージ
18: private $errorTable; //エラー番号 => エラー・メッセージ 一覧
19:
20: /**
21: * コンストラクタ
22: * @param string $contents 解析対象テキスト(UTF-8)
23: * @return object /NULL:PHP8未満のため実行できない.
24: */
25: function __construct($contents) {
26: //PHPのバージョンをチェックする.
27: if (! $this->isphp8over()) {
28: $this->error = 111;
29: throw new Exception($this->getErrorMessage());
30: return NULL;
31: }
32: //プロパティの初期値を設定する.
33: try {
34: // Unicodeの範囲を指定
35: $map = [ 0x80, 0xFFFF, 0, 0xFFFF ];
36: // DOMの文字化け対策:UTF-8文字を数値エンティティに変換
37: $contents = mb_encode_numericentity($contents, $map, 'UTF-8');
38: // DOMDocument クラス
39: $this->dom = new DOMDocument();
40: libxml_use_internal_errors(TRUE);
41: @$this->dom->loadHTML($contents);
42: libxml_clear_errors();
43: $this->xpath = new DOMXPath($this->dom);
44: } catch (Exception $e) {
45: $this->error = 121;
46: throw new Exception($e->getMessage());
47: return FALSE;
48: }
49:
50: //エラー番号 => エラー・メッセージ 一覧
51: $this->errorTable = array(
52: 111 => array('PHP8以上が必要です', 'PHP8 or higher is required'),
53: 121 => array('DOMエラーです', 'DOM error'),
54: 999 => array('不明のエラー', 'unknown error'),
55: );
56: }
PHPのクラスについては「PHPでクラスを使ってテキストの読みやすさを調べる」を参照されたい。
解説:RSS作成サイト
| サイトID (1次元目) | 添字 (2次元目) | 値 (2次元目) |
|---|---|---|
| 1 | title | サイト名 |
| url | スクレイピングURL | |
| func | スクレイピング関数名 | |
| 2 | title | サイト名 |
| url | スクレイピングURL | |
| func | スクレイピング関数名 |
RSSmaker.php
71: // RSS作成サイト
72: $ListSites = array(
73: 1 => array(
74: 'title' => 'アニメ!アニメ!',
75: 'url' => 'https://animeanime.jp/rss/index.rdf',
76: 'func' => 'animeanime'
77: ),
78: array(
79: 'title' => '日本気象協会',
80: 'url' => 'https://tenki.jp/forecaster/',
81: 'func' => 'tenkiJp'
82: ),
83: array(
84: 'title' => '聯合ニュース',
85: 'url' => 'https://jp.yna.co.kr/RSS/news.xml',
86: 'func' => 'ynaCoKr'
87: ),
88: array(
89: 'title' => 'RNN時事英語辞典',
90: 'url' => 'https://rnnnews.jp/rss/rss.xml',
91: 'func' => 'rnnnews'
92: ),
93: array(
94: 'title' => '朝日新聞デジタル',
95: 'url' => 'https://www.asahi.com/rss/asahi/newsheadlines.rdf',
96: 'func' => 'asahi'
97: ),
98: array(
99: 'title' => '讀賣新聞(経済)',
100: 'url' => 'https://www.yomiuri.co.jp/economy/',
101: 'func' => 'yomiuri'
102: ),
103: array(
104: 'title' => '讀賣新聞(政治)',
105: 'url' => 'https://www.yomiuri.co.jp/politics/',
106: 'func' => 'yomiuri'
107: ),
108: array(
109: 'title' => '讀賣新聞(社会)',
110: 'url' => 'https://www.yomiuri.co.jp/national/',
111: 'func' => 'yomiuri'
112: )
113: );
解説:「アニメ!アニメ!」をスクレイピングする
RSSmaker.php
209: /**
210: * アニメ!アニメ!をスクレイピングする
211: * @param array $id RSS作成サイト番号
212: * @param array $param スクレイピング用パラメータ
213: * @return string RSS文字列/FALSE:スクレイピング失敗
214: */
215: function animeanime($id, $param) {
216: // ページ読み込み
217: $str = @file_get_contents($param['url']);
218: // エラー処理
219: if (($str == NULL) || ($str == FALSE)) {
220: // インスタンス生成
221: $prs = new pahooRSS();
222: $errmsg = 'アニメ!アニメ!:情報が取得できない.';
223: errorRSS($errmsg, $items);
224: $outstr = $prs->maker($items, 'RSS1.0');
225: // インスタンス解放
226: $prs = NULL;
227: return $outstr;
228: }
229:
230: static $pat11 = '/^<\?xml[^>]+>/iums';
231: $outstr = trim(preg_replace($pat11, '', $str));
232:
233: return $outstr;
234: }
解説:「日本気象協会」をスクレイピングする
RSSmaker.php
236: /**
237: * 日本気象協会をスクレイピングする
238: * @param array $id RSS作成サイト番号
239: * @param array $param スクレイピング用パラメータ
240: * @return string RSS文字列
241: */
242: function tenkiJp($id, $param) {
243: // ページ読み込み
244: $curl = curl_init() ;
245: curl_setopt($curl, CURLOPT_URL, $param['url']);
246: curl_setopt($curl, CURLOPT_HEADER, 1) ;
247: curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
248: curl_setopt($curl, CURLOPT_SSL_VERIFYPEER , FALSE); // 証明書は無視
249: curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); // 結果を文字列で
250: curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0');
251: curl_setopt($curl, CURLOPT_TIMEOUT, 5);
252: $res1 = curl_exec($curl);
253: $res2 = curl_getinfo($curl);
254: // PHP8.5:非推奨関数
255: if (PHP_VERSION_ID < 80500) {
256: curl_close($curl);
257: }
258: $html = substr($res1, $res2['header_size']);
259:
260: // インスタンス生成
261: $scrp = new pahooScraping($html);
262: $prs = new pahooRSS();
263:
264: // エラー処理
265: if ($scrp->iserror()) {
266: $errmsg = '日本気象協会:情報が取得できない.';
267: errorRSS($errmsg, $items);
268: $outstr = $prs->maker($items, 'RSS1.0');
269: return $outstr;
270: }
271:
272: // サイト諸元
273: $items[0]['title'] = $param['title'];
274: $items[0]['link'] = getDomainURL($param['url']);
275: $items[0]['rss'] = $_SERVER['SCRIPT_NAME'] . '?id=' . $id;
276: $items[0]['creator'] = CREATOR;
277: $items[0]['copyright'] = '日本気象協会';
278: $items[0]['description'] = $scrp->getDescription();
279:
280: // コンテンツ情報
281: $nodes = $scrp->queryXPath('//a[starts-with(@href, "/forecaster/")]');
282: $cnt = 1;
283: for ($i = 0; $i < $nodes->length; $i++) {
284: $url = $nodes->item($i)->getAttribute('href');
285: if (preg_match('/\/[0-9]+\.html$/', $url) > 0) {
286: $items[$cnt]['link'] = $items[0]['link'] . preg_replace('/^\// i', '', $url);
287: $cnt++;
288: }
289: }
290: $nodes = $scrp->queryXPath('//div[contains(concat(" ", normalize-space(@class), " "), " text-box ")]/p[@class="title"]');
291: $cnt = 1;
292: for ($i = 0; $i < $nodes->length; $i++) {
293: $title = $nodes->item($i)->nodeValue;
294: $items[$cnt]['title'] = $title;
295: $items[$cnt]['description'] = '';
296: $cnt++;
297: }
298: $nodes = $scrp->queryXPath('//span[@class="date-time"]');
299: $cnt = 1;
300: for ($i = 0; $i < $nodes->length; $i++) {
301: $dt = $nodes->item($i)->nodeValue;
302: $items[$cnt]['date'] = str2iso8601_02($dt);
303: $cnt++;
304: }
305:
306: // 不要な情報を削除
307: foreach ($items as $key=>$item) {
308: if (! isset($item['title']) || ! isset($item['link'])) {
309: unset($items[$key]);
310: }
311: }
312:
313: // RSS1.0作成
314: $outstr = $prs->maker($items, 'RSS1.0');
315:
316: // インスタンス解放
317: $scrp = NULL;
318: $prs = NULL;
319:
320: return $outstr;
321: }
解説:「聯合ニュース」をスクレイピングする
RSSmaker.php
323: /**
324: * 聯合ニュースをスクレイピングする
325: * @param array $id RSS作成サイト番号
326: * @param array $param スクレイピング用パラメータ
327: * @return string RSS文字列/FALSE:スクレイピング失敗
328: */
329: function ynaCoKr($id, $param) {
330: $items = array();
331:
332: // ページ読み込み
333: $curl = curl_init() ;
334: curl_setopt($curl, CURLOPT_URL, $param['url']);
335: curl_setopt($curl, CURLOPT_HEADER, 1) ;
336: curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
337: curl_setopt($curl, CURLOPT_SSL_VERIFYPEER , FALSE); // 証明書は無視
338: curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); // 結果を文字列で
339: curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0');
340: curl_setopt($curl, CURLOPT_TIMEOUT, 5);
341: $res1 = curl_exec($curl);
342: $res2 = curl_getinfo($curl);
343: // PHP8.5:非推奨関数
344: if (PHP_VERSION_ID < 80500) {
345: curl_close($curl);
346: }
347: $str = substr($res1, $res2['header_size']);
348:
349: // エラー処理
350: if (($str == NULL) || ($str == FALSE)) {
351: // インスタンス生成
352: $prs = new pahooRSS();
353: $errmsg = '聯合ニュース:情報が取得できない.';
354: errorRSS($errmsg, $items);
355: $outstr = $prs->maker($items, 'RSS1.0');
356: // インスタンス解放
357: $prs = NULL;
358: return $outstr;
359: }
360:
361: static $pat11 = '/^<\?xml[^>]+>/iums';
362: $outstr = trim(preg_replace($pat11, '', $str));
363:
364: return $outstr;
365: }
解説:「RNN時事英語辞典」をスクレイピングする
RSSmaker.php
367: /**
368: * RNN時事英語辞典:RSS 2.0→1.0
369: * @param array $id RSS作成サイト番号
370: * @param array $param スクレイピング用パラメータ
371: * @return string RSS文字列
372: */
373: function rnnnews($id, $param) {
374: $items = array();
375:
376: // インスタンス生成
377: $prs = new pahooRSS();
378:
379: // RSS 2.0パース
380: $items = $prs->parse($param['url']);
381: if ($items === FALSE) {
382: $errmsg = 'RNN時事英語辞典:情報が取得できない.';
383: errorRSS($errmsg, $items);
384: $outstr = $prs->maker($items, 'RSS1.0');
385: return $outstr;
386: }
387:
388: // サイト諸元
389: $items[0]['rss'] = $_SERVER['SCRIPT_NAME'] . '?id=' . $id;
390: $items[0]['creator'] = CREATOR;
391: $items[0]['copyright'] = 'RNN時事英語辞典';
392:
393: // RSS1.0作成
394: $outstr = $prs->maker($items, 'RSS1.0');
395:
396: // インスタンス解放
397: $prs = NULL;
398:
399: return $outstr;
400: }
解説:「朝日新聞デジタル」をスクレイピングする
RSSmaker.php
402: /**
403: * 朝日新聞デジタル:?→RSS 1.0
404: * @param array $id RSS作成サイト番号
405: * @param array $param スクレイピング用パラメータ
406: * @return string RSS文字列
407: */
408: function asahi($id, $param) {
409: define('NS_dc', 'http://purl.org/dc/elements/1.1/'); //名前空間
410: $items = array(); // アイテムを格納する配列
411:
412: // コンテンツ読み込み
413: $ss = @file_get_contents($param['url']);
414: $xml = simplexml_load_string($ss);
415:
416: // インスタンス生成
417: $scrp = new pahooScraping($xml);
418: $prs = new pahooRSS();
419:
420: // エラー処理
421: if ($xml == FALSE) {
422: $errmsg = '朝日新聞デジタル:情報が取得できない.';
423: errorRSS($errmsg, $items);
424: $outstr = $prs->maker($items, 'RSS1.0');
425: return $outstr;
426: }
427:
428: // サイト諸元
429: $items[0]['title'] = $xml->channle->title;
430: $items[0]['link'] = getDomainURL($param['url']);
431: $items[0]['rss'] = $_SERVER['SCRIPT_NAME'] . '?id=' . $id;
432: $items[0]['creator'] = CREATOR;
433: $items[0]['copyright'] = '朝日新聞デジタル';
434: $items[0]['description'] = $xml->channle->description;
435:
436: // コンテンツ情報
437: $cnt = 1;
438: for ($i = 0; $i < count($xml->item); $i++) {
439: $items[$i + 1]['title'] = $xml->item[$i]->title;
440: $items[$i + 1]['link'] = $xml->item[$i]->link;
441: $items[$i + 1]['description'] = '';
442: $node = $xml->item[$i]->children(NS_dc);
443: $dt = strtotime((string)$node->date);
444: $items[$i + 1]['date'] = date('c', $dt);
445: $cnt++;
446: }
447:
448: // RSS1.0作成
449: $outstr = $prs->maker($items, 'RSS1.0');
450:
451: // インスタンス解放
452: $scrp = NULL;
453: $prs = NULL;
454:
455: return $outstr;
456: }
解説:「讀賣新聞」をスクレイピングする
RSSmaker.php
458: /**
459: * 讀賣新聞をスクレイピングする(共通)
460: * @param array $id RSS作成サイト番号
461: * @param array $param スクレイピング用パラメータ
462: * @return string RSS文字列
463: */
464: function yomiuri($id, $param) {
465: $items = array(); // アイテムを格納する配列
466:
467: // インスタンス生成
468: $prs = new pahooRSS();
469:
470: // コンテンツ読み込み
471: $html = @file_get_contents($param['url']);
472:
473: // エラー処理
474: if ($html === FALSE) {
475: $errmsg = '讀賣新聞:情報が取得できない.';
476: errorRSS($errmsg, $items);
477: $outstr = $prs->maker($items, 'RSS1.0');
478: return $outstr;
479: }
480:
481: // インスタンス生成
482: $scrp = new pahooScraping($html);
483:
484: // サイト諸元
485: $items[0]['title'] = $param['title'];
486: $items[0]['link'] = getDomainURL($param['url']);
487: $items[0]['rss'] = $_SERVER['SCRIPT_NAME'] . '?id=' . $id;
488: $items[0]['creator'] = CREATOR;
489: $items[0]['copyright'] = '讀賣新聞';
490: $items[0]['description'] = $scrp->getDescription();
491:
492: // コンテンツ情報
493: $nodes = $scrp->queryXPath('// div[@class="item"]/h3[@class="title"]/a');
494: $cnt = 1;
495: for ($i = 0; $i < $nodes->length; $i++) {
496: $node = $nodes->item($i);
497: $uri = $items[0]['link'] . preg_replace('/^\// i', '', $node->getAttribute('href'));
498: if (strpos($uri, $param['url']) !== FALSE) {
499: $items[$cnt]['title'] = trim($node->nodeValue);
500: $items[$cnt]['link'] = $uri;
501: $items[$cnt]['description'] = trim($node->nodeValue);
502: $cnt++;
503: }
504: }
505: $nodes = $scrp->queryXPath('// div[@class="info"]/time');
506: $cnt = 1;
507: for ($i = 0; $i < $nodes->length; $i++) {
508: $node = $nodes->item($i);
509: if (isset($items[$cnt]['title'])) {
510: $dt = strtotime((string)$node->getAttribute('datetime'));
511: $items[$cnt]['date'] = date('c', $dt);
512: $cnt++;
513: }
514: }
515:
516: // RSS1.0作成
517: $outstr = $prs->maker($items, 'RSS1.0');
518:
519: // インスタンス解放
520: $scrp = NULL;
521: $prs = NULL;
522:
523: return $outstr;
524: }
参考サイト
- PHPでRSSを作る:ぱふぅ家のホームページ
- PHPで作るRSSビューア:ぱふぅ家のホームページ

(2026年1月10日)大幅改訂
(2025年12月28日)PHP8.5対応:curl_closeを使わない