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

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

新規登録して質問してみよう
ただいま回答率
85.49%
PHP

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

Q&A

解決済

2回答

4673閲覧

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

el_20

総合スコア7

PHP

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

0グッド

0クリップ

投稿2015/10/30 05:09

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

###わからないところ
どうやって更新分を抽出するのかがわかりません

php

1include_once('simplehtmldom_1_5/simple_html_dom.php'); 2 3$html = file_get_html( 'http://google.co.jp' ); 4 5// 指定した要素を$elem1に代入 6$elem1 = $html->find('p[class="hoge"]/a') 7

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

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

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

で、解決方法ですが、必要なのは配列部分だけなので、

php

1foreach( $elem1 as $data ) { 2 if(in_array($data, $elem2)==false){ 3 echo $data."<br>"; 4 } 5} 6 7// $hogeにシリアライズした$elem1を代入 8$hoge = serialize($elem1);

で直接$elem1をシリアライズするのではなく

php

1$new_arr = array(); 2foreach( $elem1 as $data ) { 3 $new_arr[] = $data; 4 if(in_array($data, $elem2)==false){ 5 echo $data."<br>"; 6 } 7} 8 9// $hogeにシリアライズした$new_arrを代入 10$hoge = serialize($new_arr);

とすれば、必要な配列部分だけをシリアライズできるかと思います。

投稿2015/10/30 09:45

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

el_20

2015/10/30 11:18

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

退会済みユーザー

2015/10/30 11:24

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

2015/10/30 11:42 編集

fatalエラーは if(in_array($data, $elem2)==false) の行で起きてます。 一度データを消しましたが状況は変わりませんでした。
退会済みユーザー

退会済みユーザー

2015/10/30 14:58

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

2015/10/31 01:55

$new_arr[] = (string)$data; としたところ、解決しました!! $elem2はキチンと配列になっていました。 今後、それらを意識して書くようにします。 アドバイス等ありがとうございました。大変助かりました。
guest

0

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

配列に入っているデータを単純に比較するだけなら

php

1$new_arr = array(新しい取得データの配列); 2$old_arr = array(古い取得データの配列); 3 4foreach( $new_arr as $data ) { 5 if (in_array($data, $old_arr)==false) echo $data."\n"; 6} 7

とすると、新しく追加されたデータだけ表示されます。

投稿2015/10/30 05:20

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

el_20

2015/10/30 08:00 編集

回答ありがとうございます。一定です。 順番の変化は含まず、新着のみを更新と判定したいです。 書いていただいたコードに関してですが、 新しく追加されたデータを表示させた後、 $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 06:42

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

2015/10/30 08: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' ); // 引っ張るものを指定して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);
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問