最近ブームのスクレイピング。
大体Pythonで取得するものだ~という情報になっている。
「だから他の言語ユーザもPythonやろうぜ!」みたいな流れなんだけど、実はPHPでもスクレイピングができる。
きっとPythonの方が要領よく、効率よく、メモリも使わず、高速だとか、そういうこともあるのだろう(無調査)から、ちゃんとやりたいのであれば、Pythonをオススメしておく。
なので、コチラは今すぐやりたくて、新しい言語を覚えるよりも、サクッと今できるPHPでやりたい人だけに向けた記事です。
スクレイピングについて
ウェブスクレイピングとは、サイトから情報を抽出する技術のこと。
ウェブクローラーやウェブスパイダーともいうらしいですよ。
「ウェブクローラーってそうなの?」て気もするけど、そうらしいですよ。
そしてスクレイピングに必要になるのは、ザックリ言えば主に2つ。
1.ページを読む。必要ならログインする。
2.ページ内容を解析する。
1のログインとかページを読む方法については、いずれ書こうとは思うけども、いつになるか分からないので、他のサイトをご参照ください。
たくさんあるから大丈夫!
こちらは2のページ内容を解析する方法、
つまり『HTMLソースから、タグの情報を取得する方法』について書いておく。
自分で解析しようとしてみた
最初は自分でタグを解析してみようとしていた。
タグの情報を取得しようとすると出てくるのが大体『preg_match』だからである。
/** * タグのを情報取得 * @param $html_source 対象文章 * @param $tag タグ名 * @param $key $key=$key_value * @param $key_value $key=$key_value */ // タグ情報取得 下記例<input ~ name="mail"~> function getTagInfomation($html_source, $tag='input', $key='name', $value='mail') { // タグを探す $pattern = '/(<'.$tag.'.*'.$key.'=\s*[\"|\'].*'.$value.'.*[\"|\'].*>)/i'; preg_match_all($pattern, $html_source, $match); // タグがない if (count($match) == 0) { return ''; } // 重複タグを削除する $tags = []; foreach($match as $m_key => $m_val){ if(!in_array($m_val[0], $tags)){ $tags[] = $m_val[0]; } } // タグ内情報を取得する $infomation = []; $pattern = '/ (.*?=\s*[\"|\'].*?[\"|\']|checked|selected)/i'; foreach ($tags as $t_key => $t_val) { preg_match_all($pattern, $t_val, $infomation[]); } // tag情報がない if (count($infomation) == 0) { return ''; } // 情報を分かりやすく配列化 $return = []; $pattern = '/(.*?)=\s*[\"|\'](.*?)[\"|\']|(checked)|(selected)/i'; foreach ($infomation as $i_key => $i_val) { foreach ($i_val[1] as $iv_key => $iv_val) { preg_match($pattern, $iv_val, $temp); if(!isset($temp[2])){ $temp[2] = $temp[1]; } $return[$i_key][trim($temp[1])] = $temp[2]; } } return $return; }
ただコレ『textarea』とか、タグに囲まれた情報については取れない。
だから別途作らなきゃいけないのが、面倒だったし上に正規表現のパターンが微妙に上手く行かなくて、時間がかかるかかる。
もうどれだけかかるんだというレベル。
そして探しに探した結果、何か便利な機能があった…無知は罪とはこのことか…。
なので、こちらのソースはもはや無用の産物であるが、自力でタグ情報を取得しようと使う人もいるかもと、記載しておく。
『DOMDocument』と『DOMXPath』を使う方法
HTMLタグの情報を取得しようと四苦八苦していたら『DOMDocument』が現れた。
これでDOM情報が取れる。
そして『DOMDocument』だけで使うものだと、アレだコレだと四苦八苦していたら『DOMXPath』が現れた。
まるでJavaScriptの様に情報が取得できる。
この時点で、そもそも自分はタグの情報ではなく、値がほしかったのであったことを思い出す。
組み合わせてから、しばしアレコレしていたら…できたー!!
結果がコレ。
/** * タグの値を取得 * @param $html_source 対象文章 * @param $tag タグ名 * @param $key $key=$key_value * @param $key_value $key=$key_value */ function getTagValue($html_source, $tag='input', $key='name', $key_value='token') { $domDocument = new DOMDocument(); @$domDocument->loadHTML($html_source); $xpath = new DOMXPath($domDocument); // '//ul[@class="menu"]' switch($tag){ case 'input': $pattern = '//input[@'.$key.'="'.$key_value.'"]/attribute::value'; break; case 'input-selected': $pattern = '//input[@'.$key.'="'.$key_value.'" and @selected]/attribute::value'; break; case 'input-checked': $pattern = '//input[@'.$key.'="'.$key_value.'" and @checked]/attribute::value'; break; case 'select': // /attribute::valueをつけない場合、挟まれた値が帰ってくる $pattern = '//select[@'.$key.'="'.$key_value.'"]/option[@selected]/attribute::value'; break; case 'textarea': default: $pattern = '//'.$tag.'[@'.$key.'="'.$key_value.'"]'; break; } $tag_nodes = $xpath->query($pattern); return isset($tag_nodes->item(0)->nodeValue) ? $tag_nodes->item(0)->nodeValue : ''; }
短っ!
これで出来るとは…自分の苦労のアレさよ…
因みに
『case 'input-selected':』は『ラジオボタン』
『case 'input-checked':』は『チェックボックス』
であるが、実はコレらについては、未テスト。
あんまり使ってるサイトがなくて…テストケースを作るのが手間で…
なので、後日この2点については変動する可能性があるので、ご注意くだされ。
まとめ
バージョンで多少の差はあれど、PHP5から使えるので『DOMDocument』と『DOMXPath』を使った方がいい。
自分で作るとすっごい手間! 疲れる!
場合によっては、上手く取れないこともある様子なので、そこは頑張って!
コメント