こんにちは、にょろりんこの備忘録的技術ブログです。
今回のシリーズでは、動画タイトルの文字列をそのまま使って、動的サイトマップのSEOフレンドリーなURLを自動生成する方法を書いていきます。

なぜこんなことが必要かというと、こんな現象でお困りではないですか?
- 動画サイトを運営しているけど、Googleのインデックスが全然進まない
- 動画ごとにURLはあるけど、/video.php?id=1234 みたいな無機質なURLでSEO評価が上がらない
- 動画タイトルをURLに含めたいけど、日本語タイトルをどうやってURLセーフに変換すればいいかわからない
- SNSやLINEでURLを共有しても、何の動画かパッと見て分からない
こういう悩み、私もずっとありました。
では、こんな時にどうすればいいかというと、動画タイトルをもとにSEOフレンドリーなスラッグ(slug)を自動生成し、そのスラッグ付きURLをサイトマップに登録するという方法を使います。
これによって、
という、一石三鳥の効果が得られます。
今回使う言語はPHPです。
なぜPHPかというと「サーバーサイドでサクッと実行できる」「cronに組み込むだけでバッチ処理として動かせる」からです。もちろん、Node.js や Python でも同じことはできますが、今回は私が実際に運用しているPHPスクリプトを紹介します。
以下実際にコード見ていきましょう。
排他ロックの設定準備
このような自動処理プログラムの場合、まずは他の処理と競合しないように排他ロックの設定が重要になってきます。
排他ロック設定は、cronバッチを安定稼働させるための必須テクニックですね。
$lockFile = __DIR__ . '/generate_sitemap.lock';
$fp = fopen($lockFile, 'c');
if (!$fp) {
fwrite(STDERR, "ロックファイルを作成できませんでした: {$lockFile}\n");
exit(1);
}
上記コードでは、ロックファイルのパスを変数$lockFileにセットしfopenでそのファイルを作成または開いて、排他ロックをかける準備をしています。
ここまでで、排他ロックを設定する準備ができました。次は、実際にこのロックを取得して二重起動を防ぐ処理に進みます。
排他ロック取得と二重起動防止
if (!flock($fp, LOCK_EX | LOCK_NB)) {
// すでに別プロセスが動いている
echo "サイトマップ生成プロセスは既に実行中です。終了します。\n";
exit(0);
}
上記コードでは、すでに他のプロセスがロックを取得していないか確認し、もし取得できなければ「すでに実行中」と表示して、二重起動を防ぐためにスクリプトを終了しています。
ここまでで、排他ロックの取得が完了しました。次は、スクリプト終了時にロックを解除する後処理を登録していきます。
スクリプト終了時の後処理
// スクリプト終了時にロック解除・ファイル削除
register_shutdown_function(function() use ($fp, $lockFile) {
flock($fp, LOCK_UN);
fclose($fp);
@unlink($lockFile);
});
上記コードでは、スクリプトが終了するときに自動でロックを解除し、ファイルポインタを閉じて、最後にロックファイルを削除する処理を登録しています。これにより、次回実行時に古いロックが残って動かなくなる問題を防いでいます。
ここまでで、排他ロックに関する一連の設定が完了しました。次は、実際にサイトマップを生成する処理に進んでいきます。
古いサイトマップの削除
実際にサイトマップを作成する前に、まずは古いサイトマップを削除しておく必要があります。実際のコードは以下です。
$old = glob($sitemapDir . '/sitemap*.xml');
if ($old) {
foreach ($old as $f) {
if (is_file($f)) {
unlink($f);
echo "古いサイトマップ削除: " . basename($f) . "\n";
}
}
}
上記コードでは、glob 関数で既存のサイトマップファイルを全て取得し、unlink で削除しています。これにより、前回生成された古いサイトマップを一掃してから新しいサイトマップを作成できるようにしています。
ここまでで、サイトマップを生成する前のクリーンアップが完了しました。次は、静的ページ用のサイトマップを作成する処理に進みます。
静的ページURLリストの定義
サイトマップには、動的な動画ページだけでなく、トップページや利用規約ページなどの静的ページも含める必要があります。以下のコードでは、その静的ページのURLや優先度、更新頻度を配列で定義しています。
$staticUrls = [
['url' => "{$baseUrl}/", 'priority' => '1.0', 'changefreq' => 'monthly'],
['url' => "{$baseUrl}/terms", 'priority' => '0.5', 'changefreq' => 'yearly'],
['url' => "{$baseUrl}/pc", 'priority' => '0.7', 'changefreq' => 'monthly'],
];
SaePornsは、コンテンツページとトップページ、規約ページ、管理者用のプロセスコントロールページを含めた、3種類の固定ページが存在します。
上記コードでは、その3つのURLに対して、それぞれの優先度(priority)と更新頻度(changefreq)を設定しています。
優先度はグーグル公式にも「この値がインデックス順位を保証するものではない」とされていますが「クローラビリティ向上」「サイト全体構造のヒント」を与えるという意味で設定しておくことが推奨されています。
正直なところ、管理者用ページはグーグルなどの検索エンジンにクロールさせる必要性も無いと思いますが、ここらへんはいずれABテストをして考えていこうと思います。
ここまでで、静的ページ用のURLリストが準備できました。次は、このリストをもとに静的ページ用サイトマップを生成する処理に進みます。
XMLヘッダとルート要素の定義
$xmlStatic = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
$xmlStatic .= "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n";
この2行では、静的ページ用サイトマップのXMLファイルとしての基本構造を宣言しています。
1行目では、XML宣言としてバージョン1.0と文字エンコーディングUTF-8を指定しています。
2行目では、サイトマップのルート要素である <urlset> タグを定義し、その中で sitemaps.org で定められているスキーマURLを xmlns 属性としてセットしています。
ここまでで、XMLファイルを正しく認識させるためのヘッダ部分が完成しました。
静的ページ用サイトマップの生成と保存
foreach ($staticUrls as $page) {
$loc = htmlspecialchars($page['url'], ENT_QUOTES, 'UTF-8');
$lastmod = date('Y-m-d');
$freq = $page['changefreq'];
$prio = $page['priority'];
$xmlStatic .= " <url>\n";
$xmlStatic .= " <loc>{$loc}</loc>\n";
$xmlStatic .= " <lastmod>{$lastmod}</lastmod>\n";
$xmlStatic .= " <changefreq>{$freq}</changefreq>\n";
$xmlStatic .= " <priority>{$prio}</priority>\n";
$xmlStatic .= " </url>\n";
}
$xmlStatic .= "</urlset>\n";
file_put_contents($sitemapDir . '/sitemap-static.xml', $xmlStatic);
echo "固定ページ用サイトマップ作成: sitemap-static.xml\n";
このブロックでは、先ほど定義した $staticUrls 配列をもとに、静的ページ用のサイトマップXMLを作成しています。
まず foreach で $staticUrls に含まれる各ページ情報を取り出し、htmlspecialchars を使ってURLをエスケープしています。更新日時には、スクリプト実行日の Y-m-d 形式の日付をセットし、変更頻度(changefreq)や優先度(priority)も配列から取得してそれぞれXML要素として組み立てています。
ループが終わったあと、</urlset> タグでXMLを閉じ、file_put_contents で sitemap-static.xml というファイル名で保存しています。最後に、固定ページ用サイトマップが作成されたことを示すメッセージをechoしています。
ここまでで、静的ページ用サイトマップの生成と保存が完了しました。
長くなってきたので、今回はここまで。
次は、いよいよ、動画ページなど動的URLのサイトマップ生成処理に進みます。
このコードは、実際に「あなたを追跡しないアダルト動画検索エンジンSaePorns」で運用されています。よかったら見ていってください。
※18歳未満の方はご利用いただけません。