Yahoo!JAPANの「カスタムサーチ」のページで「内容が重複する複数のURLをまとめるよう、検索エンジンに通知」という記事を見つけました。
サイトには、URLは異なるがウェブページの内容は変わらないというケースがあります。たとえば、URLがトラッキング用のパラメータを含んでいる場合や、URLに含まれるパラメータをもとに閲覧環境によってウェブページの表示を最適化しているような場合です。
例
- http://www.example.com/products?trackingid=feed
- http://www.example.com/products?sessionid=hgjkeor2
- http://www.example.com/products?printable=yes&trackingid=footer
このような場合、検索エンジンのインデックスに個々のURLで登録されると、同じ内容のウェブページが検索結果に表示されたり、同じ内容のウェブページであるにもかかわらず、各URLにクローラーが巡回し、サーバーに負荷をかけてしまう、また、サイト内の巡回が効率的に行われないといった不都合が発生することがあります。このようなことを避けるため、サイト管理者がウェブページのなかで<link>タグを利用して、重複を避けるように検索エンジンに通知する方法が用意されています。
具体的にはヘッダに下の様に書いたとすると「このページはhttp://www.example.com/と同じ内容です」と宣言したことになるようです。
<link rel=”canonical” href=”http://www.example.com/”>
ということは、ここでひとつの疑問が出てきます。
別のドメインでもcanonicalは適用できるのだろうか?
その回答はGoogleの「rel=”canonical” 属性について – ウェブマスター ツール ヘルプ」にありました。
rel=”canonical” 属性を使用して、まったく別のドメイン上の URL を指定できるか
リダイレクトは簡単に設定できない場合があります。たとえば、サーバーサイドのリダイレクトを作成できないウェブ サーバーを使用しているときに、新しいドメイン名に移行する場合などです。このような場合には、rel=”canonical” リンク要素を使用して、このドメインでインデックス登録の対象になる正確な URL を指定できます。rel=”canonical” リンク要素は絶対的な指示ではなく、ヒントとしてみなされますが、Google では可能な限りこの要素を追跡します。
つまり、解釈が間違っていなければ「rel=”canonical” 属性」は、次のような使い方が出来るということでしょうか?
ブログやサイトを別ドメインに移転した。今までに作ったページも新しいドメインにコピーした。今後は新ドメインで運用するが、これまでの遺産として古いドメインにも記事を残しておきたい。しかし、そうすると後から作った新しいサイトがコピーサイトとして検索エンジンに低く扱われる可能性がある。
そうならないために、今までの(古い)サイトのHTMLに「rel=”canonical” 属性」でコピー済みの新しいサイトの記事を指定しておく。そうすることで検索エンジンには、新サイトを優先するよう要望する。
そうすると「Google では可能な限りこの要素を追跡」してくれるのでしょうか?実は最近、この条件に合致した移転ブログがあります。
パート派遣主婦のぐーたら子育て生活 (長いので以下「パー…」と省略表記)
「パー…」は最近、独自ドメインを取って「ココロデザイン」というサイトに移転しました。その移転の際のリポートを「技術のタマゴ」というブログに書いています。
ということで「技術のタマゴ」を開いたら、こんな記述が見つかりました。
※rel=”canonical”で重複記事の中で、新記事を一番だと主張する
という案もありましたが、同一ドメイン間じゃないと
使えないということで、却下になりました。
rel=”canonical”は使わなかったようです。しかしGoogleのページには、こう書いてあります。「リダイレクトを作成できないウェブ サーバーを使用しているときに、新しいドメイン名に移行する場合などです。このような場合には、rel=”canonical” リンク要素を使用して、このドメインでインデックス登録の対象になる正確な URL を指定できます」
そうであるなら「同一ドメイン間じゃないと使えない」というのは間違いじゃないでしょうか?
追記:今ご覧いただいているこのブログの移転で試したところrel=”canonical”は適用されました。尚「技術のタマゴ」の記事は訂正されています。
しかし、rel=”canonical” で新サイトを指定できるとしても、ブログで実際にどうやればいいのかという問題があります。すべての記事のヘッダにrel=”canonical”属性で、新しいURLを書き込まないといけませんが、多くの無料ブログのテンプレートでは1記事ごとに違うURLを指定する事は出来ません。
記事の中に書いたら記事毎にURLを変えられるがどうだろうか、と思い調べてみたのですが「rel=canonicalタグによくある5つの間違い | 海外SEO情報ブログ」によると「間違い その5: <body>内のrel=”canonical”」という項目で次のように書いてありました。記事の中に書いても有効化されないようです。
rel=”canonical”はHTMLドキュメントの<head>セクションだけに出現しなければならない。またHTMLの読み取りの問題を避けるために<head>の先頭にできるだけ近いほうがいい。
<body>にrel=”canonical”が出てきたときは無視する。
ファンブログハックの記事から
ファンブログハックに「「タイトルタグの重複」をjavascriptで回避する(ファンブログ、FC2)」という記事があります。JavaScriptを使ってHTMLに書いてあるのと違うタイトルに書きかえたところ、Googleには書きかえたタイトルが反映されたという内容です。
実はこのブログ(移転前の旧ブログ)は今月1日に新しいスキンに変えているんですが、「site:fanblogs.jp/ayzfqir5」をググるとおもしろい結果が出ます。このブログのスキンには、タイトルにページ番号やカテゴリー名を表示させる機能がありません。なので、JavaScriptで書き加えているんですが、スキンを変えて数日で、検索結果に反映されるようになりました。ファンブログハックの記事の通りです。
赤枠内はスクリプトで追加したものですが、見事に反映されています。
ヘッダにrel=”canonical” 属性を追加するスクリプト
ということは、JavaScriptで、ヘッダにrel=”canonical” 属性を追加すれば、検索に反映されるのではないだろうか?つまり、新しいサイトを優先して表示してくれるのではないだろうか?と仮定できるのです。もし、それが出来るなら「パー…」にnoindexを指定する必要はなくなります。
とは言ったものの、ページ数がたくさんある時は大変です。ちなみにページが数ページしかない時には、下のようなスクリプトで実現できると思います。
実際にスクリプトを使った処理で rel=”canonical” が適用されるかは不明です。このブログの実際の移転では、この下の「新ドメイン側の.htaccessに旧URLを渡して、振り分ける」方法を使って適用に成功しました。
前提条件として、古い記事のURLはすべて「http://old_url.com/archive/xxx」というフォーマットになっているものとします。URLの中のxxxは数字です。この数字ごとに新しいURLをヘッダに書き加えます。新しいサイトでは、記事の内容ごとに違うブログに分けていたとしても大丈夫です。
<script type="text/javascript"><!-- var urls={ "001":"http:\/\/hoge.example.com/page_001.html", "002":"http:\/\/moge.example.com/page_002.html", "003":"http:\/\/kome.example.com/page_003.html" }; var key=window.location.href.match(/\/archive\/([0-9]+)/); if(key){ document.write('\<link rel="canonical" href="'+urls[key[1]]+'"\>'); } //--> </script>
これをheadタグの中で、なるべく上の方に書けばいいと思います。古い記事のURLがhttp://old_url.com/archive/001なら「http://hoge.example.com/page_001.html」というように、それぞれの新URLをヘッダに追記します。
しかし、記事が何百ページもあったら上のやり方では無理があります。
新ドメイン側の.htaccessに旧URLを渡して、振り分ける
大抵の無料ブログでは.htaccessは使えないし、だからこの記事のような困りごとになるわけですが、新しいサイトでは.htaccessが使えます。だから新サイトの.htaccessにパラメータを渡してリダイレクトさせればいいわけです。
旧ブログのヘッダには次のように書き加えます。スクリプトで追記したタグが有効に作用するとは断言出来ないので完全なURLを書き込むようにしました。
{記事のURLを書き出すタグ}はブログによって違いますが
- ライブドアブログなら {$ArticlePermalink$}
- FC2ブログなら <%topentry_link>
となります。
参考:
独自タグ一覧(変数) – livedoor ブログ ヘルプセンター
FC2ヘルプ | FC2ブログ | テンプレート用 変数一覧
これで古いブログのURLが「http://old_url.com/archive/001」である記事が開かれると、ヘッダの中に次のタグが書き込まれます。URLエンコードが出来ないのが心配ですが、このブログでは無事にパラメータを渡せました。
<link rel=”canonical” href=”http://new_domain.com/url_converter.php?old_url=http://old_url.com/archive/001“>
Googleなどの検索エンジンがこのタグを読んだら、新ドメインのサーバに「http://new_domain.com/url_converter.php?old_url=http://old_url.com/archive/001」を問い合わせます。新しいサーバには古いURLがパラメータで渡されるので、それを判断材料に新しいURLに誘導すれば(リダイレクトさせれば)いいわけです。
サーバー側のリダイレクト手順
ということで、サーバー側で.htaccessを使ってリダイレクトと書きましたが、何百個もある記事を、一定のパターンに沿って書きかえるならともかく、記事ごとに違うブログに振り分けるとなると.htaccessでは大変です。こうなると、旧URLと新URLを紐付けたデータベースを作って処理する方が簡単ではないでしょうか。作るデータベースのtableはこんな仕様になると思います。
CREATE TABLE url( old varchar(256), new varchar(256) );
このテーブルに、URL対応表を作ってから、PHP等のインタープリタでアクセスすればいいと思います。アクセスする際は「SELECT new FROM url WHERE old=’xxx’」というクエリで新URLを取れるでしょう。
PHPの場合のソースは次のようになります。
<?php $host='localhost'; $db='detabase_name'; $user='user_name'; $pwd='password'; $old=$_GET['old_url']; if(empty($old)){ header('HTTP/1.1 400 Bad Request'); return; } try{ $pdo=new PDO('mysql:host='.$host.'; dbname='.$db,$user,$pwd); $stmt=$pdo->query('SELECT new FROM url WHERE old="'.$old.'"'); $row=$stmt->fetch(PDO::FETCH_ASSOC); if($row){ header('HTTP/1.1 301 Moved Permanently'); header('Location: '.$row['new']); }else{ header('HTTP/1.1 404 Not Found'); } }catch (PDOException $e){ header('HTTP/1.1 500 Internal Server Error'); } $pdo=null;
余談ですがPHPコードのみからなるファイルでは、終了タグは書かない方がいいようです。
Zend Framework: Documentation: PHP ファイルの書式 – Zend Framework Manualより
PHP コードのみからなるファイルでは、終了タグ (“?>”) は決して含めてはいけません。これは必須なものではなく、 終了タグを省略することで、ファイルの最後にある空白文字が出力に影響することを防ぎます。
私はHTMLとの混合PHPの場合でも、最後がPHPの場合はいつも閉じタグを書きませんが、エラーが出たことはありません。
このブログが実際に使っているスクリプト
データベースを使わない場合は、連想配列で処理します。実際にこのブログで使っているのはデータベースを使わない以下のスクリプトです。
<?php if(empty($_GET['old_url'])||!preg_match('|/ayzfqir5/archive/(\d+)|',$_GET['old_url'],$m)){ header('HTTP',TRUE,400); exit(); } $url_table=array( "826" => "1264", "825" => "1263", "824" => "1262", (中略) "12" => "587", "9" => "586", "6" => "585" ); if(empty($url_table[$m[1]])){ header('HTTP',TRUE,404); exit(); } header('Location: http://dwm.me/archives/'.$url_table[$m[1]],TRUE,301);
$url_tableの左側のキーが旧ブログのURL、右が新しいブログのURLに当たります。
古いブログのURLは http://fanblogs.jp/ayzfqir5/archive/xxx/0 という形でした。xxx の部分だけ記事毎に違う数字です。その数字部分を正規表現で抽出してキーにします。新しいこのブログのURLは http://dwm.me/archives/xxx という形ですが、古いブログとは番号が違います。それを古いブログのキーと照らし合わせて抜き出し http://dwm.me/archives/ にくっつけて、header関数で返しています。
このブログは実際の移転でこの手法を使い、rel=”canonical”を発動させる事に成功したのですが、どのような効果を発揮したかを別記事「ブログの引越しで rel="canonical" が適用されたら検索結果とアクセス数がこう変わった」にまとめました。