先日より、Yahoo のキーワード抽出APIを、当ブログで使っているHTTPヘッダ生成プラグインNP_Headerに導入し、テスト運用中であった。
NP_Header (ページ 1) / プラグインの紹介 / Nucleus(JP)フォーラム
現時点で、データベースをphpMyAdminで確認しても問題がなくなったようなので、修正点を記載する。
主な修正は以下。
- オプションのデフォルト値の変更
- Yahoo キーワード抽出APIを称するための変更
- キーワードと要約のデータベース保存に関する問題の修正
デフォルト値の変更
公開されているNP_Header 2.02にはデフォルト値が設定されている。
言語設定:en(英語)、文字コードメタタグ:なし、viewpor:tメタタグなし
日本語の文字コード設定とviewポートメタタグをデフォルトで追加する。
165行目 追加
'<meta charset="<%charset%>" />' . PHP_EOL .
'<meta name="viewport" content="width=device-width" />' . PHP_EOL .
175行目
$this->createBlogOption('language', 'Default language (ISO 639 language codes)', 'text', 'en');
を以下に変更
$this->createBlogOption('language', 'Default language (ISO 639 language codes)', 'text', 'ja');
Yahooキーワード抽出を行うための変更
NP_Headerではbulkfeedのサービスを使っていたので、Yahooのキーワード抽出を使用するよう改造する。
Yahooのキーワード抽出APIにはAPIキーが必要なので、オプション設定でKeyの設定も可能とする。
155行目
$this->createOption('use_bulkfeeds', 'Acquire keywords automatically, with using bulkfeeds', 'yesno', 'no');
$this->createOption('max_keywords', 'Max keywords acquired with bulkfeeds', 'text', '8');
を以下に変更
$this->createOption('use_yahoo', 'Acquire keywords automatically, with using Yahoo', 'yesno', 'no');
$this->createOption('yatoken', 'Yahoo App Key ID:', 'text', '');
$this->createOption('max_keywords', 'Max keywords acquired with Yahoo', 'text', '8');
223行目
$this->deleteOption('use_bulkfeeds');
を以下に変更
$this->deleteOption('use_yahoo');
$this->deleteOption('yatoken');
これで、Yahoo APIを使用するフラグと、APIキーの追加オプションができた。
実際のキーワード生成部分は以下。
742行目
if ($this->getOption('use_bulkfeeds') == 'yes')
{
$item =& $manager->getItem($itemid, 0, 1);
if (!empty($item) && (($fp = @fsockopen('bulkfeeds.net', 80)) !== FALSE))
{
$data = chr(99) . chr(111) . chr(110) . chr(116) . chr(101) . chr(110) . chr(116) . chr(61) . urlencode(mb_convert_encoding(trim(str_replace(array("\r\n", "\r", "\n"), ' ', strip_tags($item['body'] . $item['more']))), 'UTF-8', _CHARSET)) . chr(38) . chr(97) . chr(112) . chr(105) . chr(107) . chr(101) . chr(121) . chr(61) . chr(49) . chr(50) . chr(49) . chr(101) . chr(48) . chr(53) . chr(55) . chr(99) . chr(50) . chr(100) . chr(97) . chr(100) . chr(101) . chr(53) . chr(48) . chr(97) . chr(51) . chr(56) . chr(52) . chr(52) . chr(101) . chr(56) . chr(54) . chr(99) . chr(101) . chr(99) . chr(97) . chr(102) . chr(102) . chr(48) . chr(100) . chr(57);
$result = $header = '';
$terms = array();
socket_set_timeout($fp, 30);
fputs($fp, "POST /app/terms.xml HTTP/1.0\r\n");
fputs($fp, "Host: bulkfeeds.net\r\n");
fputs($fp, 'User-Agent: PHP/' . phpversion() . "\r\n");
fputs($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
fputs($fp, 'Content-Length: ' . strlen($data) . "\r\n");
fputs($fp, "Accept: */*\r\n\r\n");
fputs($fp, $data);
while ($str = trim(fgets($fp, 4096)))
{
$header .= $str . "\n";
}
while (!feof($fp))
{
$result .= fgets($fp, 4096);
}
fclose($fp);
$result = mb_convert_encoding($result, _CHARSET, 'UTF-8');
preg_match_all('/<term>([^<]+?)<\/term>/', $result, $matches);
for ($i = 0, $j = count($matches[1]); $i < $j; $terms[] = $matches[1][$i], ++$i) ;
$terms = array_slice(array_unique($terms), 0, $this->getOption('max_keywords'));
if (count($terms) > 0)
{
$keywords = implode(', ', $terms);
を、以下に変更
if ($this->getOption('use_yahoo') == 'yes')
{
$item =& $manager->getItem($itemid, 0, 1);
$appid = $this->getOption('yatoken');
if (!empty($item) && $appid != '');
{
$api = "http://jlp.yahooapis.jp/KeyphraseService/V1/extract";
$sentence = htmlspecialchars_decode($item['title'] . $item['body'] . $item['more']);
$sentence = strip_tags($sentence);
$sentence = mb_convert_encoding(str_replace(array('\r\n', '\r', '\n'), ' ', $sentence), 'UTF-8', _CHARSET);
$sentence = mb_strimwidth(urlencode(trim($sentence)),0,100000);
$output = "xml";
$ch = curl_init($api);
curl_setopt_array($ch, array(
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERAGENT => "Yahoo AppID: $appid",
CURLOPT_POSTFIELDS => "sentence=" . $sentence
));
$result = curl_exec($ch);
$result = str_replace ('&','',$result);
$responsexml = simplexml_load_string($result);
$result_num = count($responsexml->Result);
curl_close($ch);
if($result_num > 0){
$loopmax = $this->getOption('max_keywords');
if($loopmax > $result_num){
$loopmax = $result_num;
}
$keywords = '';
for($i = 0; $i < $loopmax; $i++){
$result = $responsexml->Result[$i];
$keywords .= $result->Keyphrase;
if($i < ($loopmax - 1)) {
$keywords .= ', ';
}
}
REPLACE INTOを使用している部分の修正
2.02固有の問題として、キーワード抽出、要約抽出後などデータベースに反映する部分に「REPLACE INTO」を使用しているので、更新対象以外のデータが削除される問題がある。
これは、新規アイテム追加時には問題がないので、気が付かれなかったんだろう。
647行目
sql_query('REPLACE INTO ' . sql_table('plugin_header') .
' (itemid, description) VALUES (\'' . ((int)$itemid) .
'\', \'' . addslashes($description) . '\')');
を以下に変更
sql_query('INSERT INTO ' . sql_table('plugin_header') .
' (itemid, description) VALUES (\'' . ((int)$itemid) .
'\', \'' . addslashes($description) . '\')' .
'ON DUPLICATE KEY UPDATE description = \''.
addslashes($description) . '\'');
711行目
sql_query('REPLACE INTO ' . sql_table('plugin_header') .
' (itemid, keywords) VALUES (\'' . ((int)$itemid) .
'\', \'' . addslashes($keywords) . '\')');
を以下に変更
sql_query('INSERT INTO ' . sql_table('plugin_header') .
' (itemid, keywords) VALUES (\'' . ((int)$itemid) .
'\', \'' . addslashes($keywords) . '\')' .
'ON DUPLICATE KEY UPDATE keywords = \''.
addslashes($keywords) . '\'');
792行目
sql_query('REPLACE INTO ' . sql_table('plugin_header') .
' (itemid, language) VALUES (\'' . ((int)$itemid) .
'\', \'' . addslashes($language) . '\')');
を以下に変更
sql_query('INSERT INTO ' . sql_table('plugin_header') .
' (itemid, language) VALUES (\'' . ((int)$itemid) .
'\', \'' . addslashes($language) . '\')'.
'ON DUPLICATE KEY UPDATE language = \''.
addslashes($language) . '\'');
運用してみた感想
本文中に特殊な文字列、タグなどが入っていると記事自体が表示されないこともあって驚いたところもあるが、Yahoo APIのレスポンスは非常に良好。また、基本的にこのAPIは記事投稿時のみしか利用しないのでレスポンスの低下は気にすることはない。
何より、キーワードをいちいち設定する必要がなくなるのが利点。
現在、Googleではkeywordsメタタグは評価対象としない(無視する)ことになっているので、タグ自体は重要ではない。しかし、このキーワードを、例えばブログ内の関連記事検索に使う、タグクラウドの表示に使用するなど、利用方法はいくつかある。
記事内容に合わせた関連記事の表示は、ブログ,ニュースサイトに必須と言える機能であるため、抽出したキーワードの利用を今後考えてゆく。
コメント