前回、wordpressのインストールを終えて、いよいよPHPのコーディングに取り掛かったその続きである。先ず作るのは、RSSクロール用のPHPだ。

どのようなものを作るのかを簡単にまとめると次のようになる。

  1. cronによるキックで定期実行する。
  2. 指定したアドレスのRSSを収集しDBへ格納する。
  3. RSS取得にはSimplePieを使用する。
  4. RSSから取得した情報は、1記事リンクにつき1レコードをWordPressの投稿として格納する。
  5. 既に投稿した記事リンクは、重複して投稿しない。
  6. 作成するPHPはWordpressの変数をインクルードし、共通関数functions.phpを参照する。

cronからのキックは前回検討した通り、wp-cronではなく、Webサーバのcronを使う事にした。RSSの取得にはSimplePieを使用する。WordPressには最初からSimplePieが含まれている。Webサーバのドキュメントルートからの相対パスで、”./wp-includes/class-simplepie.php”があれば、それがSimplePieさんである。使いたいところでこいつをインクルードしてやるとSimplePieによるRSS取得機能が使えるようになる。今回はその処理をfunctions.phpに記述する。取得したRSSはMysqlのDataBaseに入れる。そうすることで検索とか、何やらかんやらがしやすく、何かと都合がいい。ではどのようにDBに入れるかと言えば、やはり折角WordPressを使っているのだから、既存の仕組みを利用させてもらう。今回は、WordpressのBlog記事投稿として、リンクに必要な記事タイトル、記事リンク、サイトタイトル、サイトリンクを格納することにした。本来ならば、美味しい食事の写真や、日々の日記などをつづるべき場所を、単なる情報格納場所として使ってしまうのは心苦しくもあるのだが、Blogをアンテナサイトに改造すると言うミッションの為である。致し方あるまい。

では、実際どのようなコードに成ったかと言えばこんな感じである。適用したテーマのfunctions.phpにだいたいこんな感じで書く。注意してほしいのは、このままコピペしても動かないだろうと言う事だ。実際動かしている物からは少し変えている。大体こんなことをしているというイメージを掴んでいただければと思う。


function RSSwoPost($url, $num = 1, $post_cat)  ←関数の作成
{
include_once(ABSPATH . WPINC . '/class-simplepie.php');←SimplePieのインクルード
    $feed = new SimplePie;
    $feed->set_feed_url($url);
    $feed->enable_cache(false);
    $feed->init();
    $items = $feed->get_items(0, $num);
    $lists = Array();
    foreach($items as $item) {
        $list = Array(
            'date' => $item->get_date('Y-m-d H:i:s'),
            'title' => $item->get_title(),
            'link' => $item->get_link(),
            'sitetitle' => $item->get_feed()->get_title(),
            'sitelink' => $item->get_feed()->get_permalink(),
            'contdescription' => $item->get_description(),
            'sitedescription' => $item->get_feed()->get_description(),
        );


 $post = array(); ←wordpressのDBに格納する内容を配列に格納
          $post['ID'] = ''; 
          $post['menu_order'] = '';
          $post['comment_status'] = 'closed';
          $post['ping_status'] = 'closed';
          $post['pinged'] = '';
          $post['post_author'] = ''; 
          $post['post_category'] = array($post_cat) ;
          $post['post_content'] = "{$list['link']}-::-{$list['title']}-::-{$list['sitelink']}-::-{$list['sitetitle']}-::-{$list['date']}";
          $post['post_date'] = $list['date']; 
          $post['post_date_gmt'] = ''; 

          if (!empty($list['contdescription'])) {
               $post['post_excerpt'] = $list['contdescription'];
          } else {
               $post['post_excerpt'] = $list['sitedescription'];
          }

          $post['post_name'] = ''; 
          $post['post_parent'] = ''; 
          $post['post_password'] = ''; 
          $post['post_status'] = 'publish'; 
          $post['post_title'] = $list['title']; 
          $post['post_type'] = 'post';
          $post['tags_input'] = '';  
          $post['to_ping'] = ''; 

/* duplicate post drop */  ←すでにDBにある物はスキップ

        $link = mysql_connect('DB名', 'DBユーザ', 'ぱすわーど');
        if (!$link) {
                echo $link;
                $sql_error = "mysql_error()";
                die($sql_error);
        } else {
                echo "login success!";
        }

        $db_selected = mysql_select_db('DB名', $link);

        if (!$db_selected) {
                echo $db_selected;
                $sql_error = mysql_error();
                die($sql_error);
        } else {
                echo "DB connect success!";
        }


        $resultb = mysql_query("SELECT post_title,ID FROM wp_posts WHERE post_title LIKE \"%".$list['title']."%\""); 

        if (!$resultb) {
                echo 'select failed.' ;
                $sql_error = mysql_error();
                die($sql_error);
        } else {
                echo "select success!";
        }

        $duplicate_num = mysql_num_rows($resultb) ;
        echo $duplicate_num ;

        if ($duplicate_num == 0 && substr(ltrim($list['title']),0,2) != 'PR')  {
                 wp_insert_post( $post );  ←格納した配列を使ってDBへ格納
        } else {
                echo "post skip!";
        }

    };
}
endif;

ちょっと簡単に解説する。RSSwoPostという関数を作っている。此の関数は引数に、RSSのURL、取得する記事の件数、取得した記事情報のカテゴリ番号、の3つを取る。取得した記事情報のカテゴリ番号とは、WordPressでは、投稿した記事をカテゴリー分けする事が出来る。管理画面から投稿へと進んで、好きなカテゴリーを作成する。取得した記事をそのカテゴリーと紐づける事で、その記事がなんなのかを整理する事が出来るのだ。例えば、時事ネタなのか、芸能ネタなのか、といった具合である。その機能をそっくり利用してやろうと言うわけだ。

そして前述のSimplePieのPHPをインクルードした上で、$feedと言うオブジェクトを作成し、必要なパラメータを渡してやる。そしてそこから、欲しい情報を引っ張り出してやる。ここで、本来本文が入る所に、「記事のURL-::-記事タイトル-::-サイトのURL-::-サイトのタイトル-::-記事の投稿日時」を格納している。この状態で他のテンプレートのPHPをいじらずに自分のサイトにアクセスすると、「記事のURL-::-記事タイトル-::-サイトのURL-::-サイトのタイトル-::-記事の投稿日時」がずらっと並んだ病的なブログが出来上がっている。後にこれを整形して、リンクの形で表示するPHPと、テーマのデフォルトのPHPを置き換える。がそれはまだ先の話である。

引っ張り出した情報を、$postという配列に格納している。また$postには、WordPressにpostする際に必要な情報も附け加る。先ほどのカテゴリ番号もここで付加してやると、御望みのカテゴリーに成ると言うわけだ。

その後、取ってきた情報がすでにDBにある場合、スキップする。これは、直接WordPressの中身をmysqlコマンドとSQLで覗いている。また、件名がPRで始まる物は広告なので除外する。

そしてようやく、wp_insert_post()と言うwordpressの関数を使って取得した情報を投稿している。

これで、RSSwoPostと言う関数が、WordPress世界で呼び出せるようになった。これを呼び出すPHPをcronで定期実行すればいい。PHPはこんな感じで。


<?php require('./wp-load.php'); ?>

<?php
     RSSwoPost(array(
'登録したいRSSのURL',
'登録したいRSSのURL',
'登録したいRSSのURL',
 ),50,3); ?>

<?php
     RSSwoPost(array(
'登録したいRSSのURL',
'登録したいRSSのURL',
'登録したいRSSのURL',
 ),50,4); ?>

<h1>クロール用です。</h1>

見ての通り、RSSwoPOST関数に引数を渡しているだけだ。注意するべきは一行目、WordPressの環境をインクルードしている。これで自分が勝手に作ったこのPHPもWordPress世界の一員としてfunctions.phpに記述されている関数を堂々と呼び出せるのだ。あとは簡単な話だ。URLは配列の形で複数指定する事が出来るが、造った関数の仕様上、カテゴリは複数指定できないのでカテゴリごとに関数を呼び出している。この例では、カテゴリ3番と4番へ登録するURLを別けている。htmlの形にしているのは、テストでブラウザからこのPHPにアクセスした時に状況を分かりやすくするためだ。

此のPHPをwordpressをインストールしたディレクトリに配置し、Webブラウザからアクセスすれば、DBへ取得情報がたまっているはずだ。wp-config.phpの

define(‘WP_DEBUG’, false);

の”false”を”true”に変えると、PHPデバッグ情報がアクセスしたWebブラウザに出るようになる。バグが出ている場合はこれでデバッグが出来るが、”true”にしたままだと、インストールしているWordPressのプラグインによっては、プラグインが出すワーニングで画面遷移が阻害されてしまい、管理画面からの各ファイル編集やりにくくなる事がある。セキュリティー上、デバッグ情報を不特定多数に公開してしまうのは良くないし、かっこ悪くもある。なのでPHPがCGI版で動いている場合には”.user.ini”ファイルを配置するか、モジュール版で動いている場合には、apacheなら”.htaccess”ファイルを配置するなどして、ログファイルにPHPのエラーを吐かせた方がスマートだろう。この辺の詳細は、他のサイトでも詳しく説明されているので割愛する。cronへは、作ったPHPをwgetするコマンドか、またはそのような記述のshellを登録するといいだろう。crotabで行う。あんまり頻繁にアクセスするといろんな方面に負担をかけるので、適当な間隔にすると良いだろう。

これで、RSSの取得ができた。このままでは、意味不明な文字列が表示されるだけの不気味なサイトとなってしまうので、あとはWrodPress見栄えを整えていくのだが、記事が長くなってしまったので、それはまた次回委しく述べる事にしよう。

*追記: 反響にお答えし、アンテナサイト用Wordpressテーマ「Antena Institute」をリリースいたしました。
詳しくは、「Antena Instituteについて」をご参照ください。
ご購入を希望される方は、下記リンクにてAntena Instituteをご購入ください。

Antena Institute(PHP7版) | 銀仁堂

Antena Institute(PHP5版) | 銀仁堂

さらに、TwitterBotスクリプトも併せてどうぞ。
Twibot Institute | 銀仁堂

5 件のコメント!

  • 初めまして、こんにちは。

    WordPressでアンテナサイトの作り方を調べていて、
    いっぱい読ませて頂きました。

    すみません、もしよろしければ
    RSSwoPost関数が正常に動くコードを記事にして頂けませんでしょうか。

    DBに突っ込むところまでは出来たのですが、
    PHPをキックする度、同じRSS記事が溜まっていってしまいます。

    おそらくSELECTしてる部分がなにか違うのかと思っております。

    勝手すみません。どうぞよろしくお願いいたします。

    • 贔屓にしていただいて、どうもありがとうございます。

      おそらく、/* duplicate post drop */ のあたりがうまくいっていないようですね。このやり方では、記事のタイトルだけで引っ掛けていますので、タイトルが修正されたりすると対応できません。なので

      $resultb = mysql_query(“SELECT post_title,ID FROM wp_posts WHERE (post_date = \”$list[date]\” and post_content like \””.$list[link].”%\”) or post_title LIKE \”%”.$list[‘title’].”%\””);

      とすると、日付が同じでURLが同じだった場合と、タイトルが同じだった場合、の2パターンに対応できます。

      他にもいろいろ方法があると思うので、echoを入れる等テストロジックを入れて、SELECT文でちゃんと思い通りに引っ掛けることができているのかなど、SQLとPHPの動きを確認しながらちゃんと動作するものを作り込んでいくと良いと思います。

      良いアンテナサイトができるといいですね。頑張ってください。

    • 仁伯爵さま

      おせわになります。
      ご返信頂き、ありがとうございます。
      また、こちらからの返信、遅くなりまして申し訳ありません。

      私はフィリピン在住でありまして、
      ネット回線が繋がらない状況が多く、参りました。

      SQL教えて頂き、ありがとうございます。
      溜まっていく更新情報・記事はどのようにしていますか。

      サイトのタイトルをチェックさせて、
      更新されてればUPDATE、されてなければthrow。

      こんな感じになりますでしょうか。
      仁伯爵さまは、どのように運用されておられますか。

    • そのままDBサーバーの容量が許す限り溜めて行って、限界に達したら古い記事から削除していくというやり方をとっています。
      他にもやり方はいろいろあると思うのでご自身で工夫してみてください。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*


*

投げ銭はこちらへ
bitcoin : 1AFU37YroGt8ohmFz8nG1N2ockL56Z4hfQ

ADA Coin: DdzFFzCqrhskq33AqGL8XkJZ3bb1hpxJYTd2UrJFKVpXphWG8d1RuhQrKymmKU1zzjvGi7oU69PaJ7nXECRG4Kpvg27Pghf3hpRNhRMy
2020年8月
 12
3456789
10111213141516
17181920212223
24252627282930
31  
カテゴリー