ZendFrameworkとmecabを使ってみる
mecabの使いどころがいまいちわからないと言われたので、ZendFrameworkとmecabを使ってみる
やることはサイトから一番多く使われている名詞を抽出する。
ZendFrameworkのインストールや、設定方法は割愛する。
サイトのスクレイピング部分はsimple_html_domを使う
$ret=str_get_html($html); $str=$ret->plaintext; echo $str;
サイト全部の文字列が出力される。
しかしこれだと、リンク集等に含まれる文字列まで出力されるのでコールバック関数を用いてAタグ内の文字列を除外する
コールバック部分の作成
function my_callback($element) { if ($element->tag=='a') $element->plaintext = ''; }
コールバックを用いて書き直す
$ret=str_get_html($html); $ret->set_callback($this->my_callback); $str=$ret->plaintext;
文字列からMecabを用いて形態素解析をする
$str='ようこそ、バーボンハウスへ。このテキーラはサービスだから、まず飲んで落ち着いて欲しい。'; $mecab = new MeCab_Tagger(); $nodes=$mecab->parseToNode($str); foreach ($nodes as $node) { print 'ID: '.$node->getId()."\n"; print 'Surface: '.$node->getSurface()."\n"; print 'Stat: '.$node->getStat()."\n"; print 'Length: '.$node->getLength()."\n"; print 'Feature: '.$node->getFeature()."\n"; print "\n"; }
この部分の結果が下記となる
ID: 0 Surface: Stat: 2 Length: 0 Feature: BOS/EOS,*,*,*,*,*,*,*,* ID: 21 Surface: ようこそ Stat: 0 Length: 12 Feature: 感動詞,*,*,*,*,*,ようこそ,ヨウコソ,ヨーコソ ID: 39 Surface: 、 Stat: 0 Length: 3 Feature: 記号,読点,*,*,*,*,、,、,、 ID: 45 Surface: バーボンハウス Stat: 0 Length: 21 Feature: 名詞,一般,*,*,*,*,バーボンハウス,*,* ID: 162 Surface: へ Stat: 0 Length: 3 Feature: 助詞,格助詞,一般,*,*,*,へ,ヘ,エ ID: 163 Surface: 。 Stat: 0 Length: 3 Feature: 記号,句点,*,*,*,*,。,。,。 ID: 171 Surface: この Stat: 0 Length: 6 Feature: 連体詞,*,*,*,*,*,この,コノ,コノ ID: 178 Surface: テキーラ Stat: 0 Length: 12 Feature: 名詞,一般,*,*,*,*,テキーラ,*,* ID: 237 Surface: は Stat: 0 Length: 3 Feature: 助詞,係助詞,*,*,*,*,は,ハ,ワ ID: 240 Surface: サービス Stat: 0 Length: 12 Feature: 名詞,一般,*,*,*,*,サービス,*,* ID: 298 Surface: だ Stat: 0 Length: 3 Feature: 助動詞,*,*,*,特殊・ダ,基本形,だ,ダ,ダ ID: 307 Surface: から Stat: 0 Length: 6 Feature: 助詞,接続助詞,*,*,*,*,から,カラ,カラ ID: 311 Surface: 、 Stat: 0 Length: 3 Feature: 記号,読点,*,*,*,*,、,、,、 ID: 317 Surface: まず Stat: 0 Length: 6 Feature: 副詞,一般,*,*,*,*,まず,マズ,マズ ID: 322 Surface: 飲ん Stat: 0 Length: 6 Feature: 動詞,自立,*,*,五段・マ行,連用タ接続,飲む,ノン,ノン ID: 337 Surface: で Stat: 0 Length: 3 Feature: 助詞,接続助詞,*,*,*,*,で,デ,デ ID: 344 Surface: 落ち着い Stat: 0 Length: 12 Feature: 動詞,自立,*,*,五段・カ行イ音便,連用タ接続,落ち着く,オチツイ,オチツイ ID: 365 Surface: て Stat: 0 Length: 3 Feature: 助詞,接続助詞,*,*,*,*,て,テ,テ ID: 376 Surface: 欲しい Stat: 0 Length: 9 Feature: 形容詞,非自立,*,*,形容詞・イ段,基本形,欲しい,ホシイ,ホシイ ID: 393 Surface: 。 Stat: 0 Length: 3 Feature: 記号,句点,*,*,*,*,。,。,。 ID: 395 Surface: Stat: 3 Length: 0 Feature: BOS/EOS,*,*,*,*,*,*,*,*
あとはControllerの実装をするだけ
*取得したHTMLの文字コードは考慮していないので、本番実装の際には考慮する必要がある。
require_once APPLICATION_PATH . '/modules/default/models/simple_html_dom.php'; Class Default_IndexController extends Zend_Controller_Action { public function init() { Zend_Layout::startMvc(); } /** * Index */ public function indexAction(){ $param["url"] = $this->getRequest()->getParam('url'); if(!$param["url"]){ exit; } //scraping $client = new Zend_Http_Client(); $client->setUri($param["url"]); $client->setConfig(array( 'adapter' => 'Zend_Http_Client_Adapter_Proxy', 'proxy_host' => 'test.com', 'useragent' => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36', 'proxy_port' => 80, 'maxredirects'=> 2, 'timeout' => 10 )); $response = $client->request("GET"); if($response->getStatus()==200){ $html=$response->getBody(); $ret=str_get_html($html); $ret->set_callback($this->my_callback); $str=$ret->plaintext; $ret->clear(); $mecab = new MeCab_Tagger(); for($node=$mecab->parseToNode($str); $node; $node=$node->getNext()){ if($node->getStat() != 2 && $node->getStat() != 3){ $feature=explode(",",$node->getFeature()); if($feature[0]=="名詞" && ($feature[1]=="一般"|| $feature[1]=="固有名詞")){ $meisi[]=$node->getSurface(); } } } $tmpArray = array_count_values($meisi); arsort($tmpArray); } var_dump($tmpArray); exit; } /** * aタグのテキストの除外 */ function my_callback($element) { if ($element->tag=='a') $element->plaintext = ''; } }
結果を出力する
curl http://localhost/?url=https://productionig.sakura.ne.jp/blog/
array(71) { ["辞書"]=> int(8) ["mecab"]=> int(8) ["環境"]=> int(6) ["hellip"]=> int(5) ["php"]=> int(4) ["形態素解析"]=> int(4) ["c"]=> int(4) ["月"]=> int(4) ["コメント"]=> int(4) ["お仕置き"]=> int(4) ["テスト投稿"]=> int(4) ["gcc"]=> int(4) ["productionig"]=> int(4) ["SE"]=> int(4) ["Mecab"]=> int(4) ["日記"]=> int(3) ["レベル"]=> int(3) ["カテゴリー"]=> int(3) ["巻き"]=> int(3) ["S"]=> int(3) ["US"]=> int(3) ["続き"]=> int(3) ["下記"]=> int(2) ["形態素"]=> int(2) ["前回"]=> int(2) ["三井住友カード"]=> int(2) ["プライベート"]=> int(2) ["デフォルト"]=> int(2) ["インストール"]=> int(2) ["三井住友VISAカード"]=> int(2) ["ABOUT"]=> int(2) ["CONTACT"]=> int(2) ["名詞"]=> int(2) ["一つ"]=> int(2) ["文章"]=> int(2) ["キーワード"]=> int(2) ["HOME"]=> int(2) ["PHP"]=> int(1) ["ブックマーク"]=> int(1) ["nodejs"]=> int(1) ["Rights"]=> int(1) ["Reserved"]=> int(1) ["Programing"]=> int(1) ["All"]=> int(1) ["RADL"]=> int(1) ["tsunokawa"]=> int(1) ["はてなダイアリー"]=> int(1) ["Copyright"]=> int(1) ["備忘録"]=> int(1) ["div"]=> int(1) ["ひよっこ"]=> int(1) ["エンジニア"]=> int(1) ["CATEGORY"]=> int(1) ["個人"]=> int(1) ["社内"]=> int(1) ["Zabbix"]=> int(1) ["死活"]=> int(1) ["デスマーチ"]=> int(1) ["ul"]=> int(1) ["navigation"]=> int(1) ["Toggle"]=> int(1) ["外部"]=> int(1) ["画像"]=> int(1) ["人気"]=> int(1) ["記事"]=> int(1) ["RECENT"]=> int(1) ["FOLLOW"]=> int(1) ["本人"]=> int(1) ["同僚"]=> int(1) ["ちょっと"]=> int(1) ["POST"]=> int(1) }
私のサイトのTOPページは「辞書」が8回、「mecab」が8回使用されていて、もし世界中に私のサイトしかない場合は「辞書」と「mecab」の関連性がきわめて高いといえます。
(実際には数千万~数億ページの取得と検証が必要ですが・・・・)
今後の使い道や応用としては、サイト巡回システムを作成し、各ページの名詞と使用頻度をDBに保持し、その保持を元に関連性キーワードを作成することができます。
それはまた今度。