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=http://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に保持し、その保持を元に関連性キーワードを作成することができます。
それはまた今度。
[amazonjs asin=”4798117129″ locale=”JP” title=”Zend Framework徹底入門”]


tsunokawaのはてなダイアリー