質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • PHP

    24042questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

webページをスクレイピングして更新があったところだけを表示させるには...?

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,922

el_20

score 1


前提・実現したいこと

PHPであるサイトをスクレイピングし、前回スクレイピングした時と比べて更新があった部分だけを抽出し、表示させるようなことをやろうと思ってます。
スクレイピングにはPHP Simple HTML DOM Parserを使っています。

わからないところ

どうやって更新分を抽出するのかがわかりません

include_once('simplehtmldom_1_5/simple_html_dom.php');

$html = file_get_html( 'http://google.co.jp' );

// 指定した要素を$elem1に代入
$elem1 = $html->find('p[class="hoge"]/a') 

$elem1の他に$elem2(前回スクレイピングした分)を用意し、それと$elem1比較して、更新があった部分だけを取り出そうといろいろ調べてたのですが、よくわからない&うまく行きませんでした。(array_diff()を使ったりしてみましたが..)

どのように処理すれば、更新分を抽出して表示させることができるでしょうか?



  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

コメントだとコードが見難いので、新しい回答にしますね。

このコードの場合、$elem1 はsimple_html_domオブジェクトになっています。
foreach等でアクセスできているのは、このオブジェクトが、配列で操作できるように作られているためです。
var_export($elem1) を実行すると、この変数の内部が見られますが、実際はアクセスしている配列以外にもたくさんのデータが格納されていることが分かります。
そして深い階層になっている部分もあるため、この階層がserialize関数の許容範囲を超えているためにエラーが出ます。

で、解決方法ですが、必要なのは配列部分だけなので、
foreach( $elem1 as $data ) {
  if(in_array($data, $elem2)==false){
    echo $data."<br>";
  }
}

// $hogeにシリアライズした$elem1を代入
$hoge = serialize($elem1);
で直接$elem1をシリアライズするのではなく

$new_arr = array();
foreach( $elem1 as $data ) {
  $new_arr[] = $data;
  if(in_array($data, $elem2)==false){
    echo $data."<br>";
  }
}

// $hogeにシリアライズした$new_arrを代入
$hoge = serialize($new_arr);
とすれば、必要な配列部分だけをシリアライズできるかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/30 20:18

    そちらに置き換えて再度実行してみたところ、また同じエラーでした。(in_arrayの行です)
    また、表示されるデータに関してですが、新着更新された分のデータだけではなく、
    前回読み込んで抽出した新着+今回抽出した新着

    というような形で表示されていってます。

    キャンセル

  • 2015/10/30 20:24

    そもそも、何行目でエラーが出てるんでしょうかね。
    エラーの内容で、serializeかunserializeのどちらかだと思いますが、unserializeの方で失敗しているなら、一度データを消すしかないかも。

    キャンセル

  • 2015/10/30 20:41 編集

    fatalエラーは
    if(in_array($data, $elem2)==false)
    の行で起きてます。

    一度データを消しましたが状況は変わりませんでした。

    キャンセル

  • 2015/10/30 23:58

    コードを試さずに脳内でバッグですが
    $new_arr[] = $data;
    のところを
    $new_arr[] = (string)$data;
    しないとダメかも。
    $elem2がちゃんと配列になってるかどうかとか、チェックした方がいいかと思います。
    配列とオブジェクトの違いなど、もう少し型を意識してコードを書いた方がいいですね。

    キャンセル

  • 2015/10/31 10:55

    $new_arr[] = (string)$data;
    としたところ、解決しました!!

    $elem2はキチンと配列になっていました。

    今後、それらを意識して書くようにします。
    アドバイス等ありがとうございました。大変助かりました。

    キャンセル

+2

比較したいデータは、常に一定のソート順なのでしょうか?
また順番が変わっただけでも更新と判定したいのかどうか、などに寄っても、処理方法が異なってくるかと思います。

配列に入っているデータを単純に比較するだけなら
$new_arr = array(新しい取得データの配列);
$old_arr = array(古い取得データの配列);

foreach( $new_arr as $data ) {
  if (in_array($data, $old_arr)==false) echo $data."\n";
}
とすると、新しく追加されたデータだけ表示されます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/30 15:09 編集

    回答ありがとうございます。一定です。
    順番の変化は含まず、新着のみを更新と判定したいです。

    書いていただいたコードに関してですが、
    新しく追加されたデータを表示させた後、
    $old_arrに$new_arrのデータをいれる、ということをさせるにはどうすればいいでしょうか

    普通にforeachのあとに$old_arrr = $new_arr としてみたところ、更新がなければ2度目の実行では何も表示されないはずなのに、2度目の実行でも1度目と同じ結果が表示されました。


    プログラム実行

    スクレイピングして$new_arrayに指定した要素を代入

    $old_arrayと比較して$old_arrayにない部分を表示(最初はord_arrは空にしてあるのでnew_arrの内容が全部表示されるはず)

    $new_arrayに$old_arrayを代入(これで2回目以降は更新がなければ何も表示されず、更新があればその箇所だけ表示されるはず...?)

    終了

    キャンセル

  • 2015/10/30 15:42

    $new_array・$old_arrayは、ただの変数ですので、ファイルに保存するなり、データベースに保存するなりしないと、プログラムが終了した時点で消えてしまいます。

    キャンセル

  • 2015/10/30 17:18

    あ、なるほど、たしかにそうですね。

    ご指摘を受けたとおり、ファイルに保存することにして
    http://suin.asia/2011/08/09/4_tips_to_preserve_array_as_string
    こちらのサイトを参考に、配列を文字列化し、ファイルに保存というように
    以下のようにしましたところ、
    「PHP Fatal error: Nesting level too deep - recursive dependency?」とFatalエラーが出てしまいます。
    解決策、もしくは代案はありませんか...?何度もすみません。


    $html = file_get_html( 'http://google.co.jp&#039; );

    // 引っ張るものを指定してa要素を$elem1(新しいデータ)に代入
    $elem1 = $html->find('p[class="hoge"]/a');
    // sample.txtを$hoge2に読み込み
    $hoge2 = file_get_contents('sample.txt');
    // serializeしてたものを元に戻して$elem2(古いデータ)に代入
    $elem2 = unserialize($hoge2);

    if (empty($elem2)) {
    $elem2 = array();
    }

    foreach( $elem1 as $data ) {
    if(in_array($data, $elem2)==false){
    echo $data."<br>";
    }
    }

    // $hogeにシリアライズした$elem1を代入
    $hoge = serialize($elem1);

    // sample.txtに$hogeを書き込み
    $fp = fopen("sample.txt", "w");
    fwrite($fp, $hoge);
    fclose($fp);

    キャンセル

同じタグがついた質問を見る

  • PHP

    24042questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。