SEO&OGP対応

この記事は [驚異のFANZA女優検索](https://fanza-actress-bust-search.azurewebsites.net/) Advent Calendar 2021 の 16 日目の記事です。

# SEO&OGP対応
SEOに対して色々語れる程本気でやっていないが最低限各ページに設定していることだけ。ASP.NETでやるならSEOとOGPはまとめてやるのがいいと思う。まず各ページに設定できるようにViewDataを使う。

```html:_Layout.html
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"]</title>
    <meta property="og:type" content="website">
    <meta property="og:title" content="@ViewData["Title"]">
    <meta property="og:url" content="@ViewData["OgUrl"]">
    <meta property="og:image" content="@ViewData["OgImage"]">
    <meta property="og:description" name="description" content="@ViewData["OgDescription"]" />
    <meta property="og:site_name" content="驚異のFANZA女優検索">
    <meta property="og:locale" content="ja_JP">
```
これでViewDataを各ページ毎に設定する。例えば商品ページなら以下。

```cs:Product.cshtml
@{
    ViewData["Title"] = $"{Model.Title} | {ViewData["ActressName"]} | 驚異のFANZA女優検索";
    ViewData["OgImage"] = Model.ImageUrlLarge;
    ViewData["OgDescription"] = $"{Model.Title} | {ViewData["ActressName"]}のページ。発売日:{Model.Date}。時間:{Model.Volume}分。女優:{Model.ActressNames}。ジャンル:{Model.GenreNames}。シリーズ:{Model.SeriesNames}。メーカー:{Model.MakerNames}。";
}
```
これで、SEOにはTitle設定した文字がタイトルに、OgDescriptionに設定した文字が説明文になるし、OGPにもタイトルと説明文、画像が出るようになる。後は実際にGoogleやTwitterで見てどういう感じか確認して、内容を詰めていく。

#URLに日本語情報も入れる
あとAmazonのようにURL自体に女優名や商品名を入れられるようにした。女優名や商品名は入れても入れなくてもどちらでも良いので、例えばURL自体に文字情報を入れてシェアするといったことができる。ただ、これを何も考えずにするとURLがばらついてしまって、SEO的に不利になる。ページが重複している場合に、正規URLを検索エンジンに示すための記述方法がある。それがcanonicalだ。

```cs
[Route("/actress/{id}")]        //本当のURL ←　これをcanonicalにする。
[Route("/actress/{id}/{name}")] //装飾付きのURL。女優名はあってもなくても同じなのでURLだけで内容を伝えたい場合に使う。

[Route("/actress/{actressId}/product/{id}")]          //本当のURL ←　これをcanonicalにする。
[Route("/actress/{actressId}/product/{id}/{name}")]   //装飾付きのURL。作品名はあってもなくても同じなのでURLだけで内容を伝えたい場合に使う。
```
これで、ルーティングしてきたURLに対して以下のようにすればCanonicalを指定できる。

```html:_Layout.html
<head>
    <link rel="canonical" href="@ViewData["Canonical"]">
```

```cs:HomeControll.cs
ViewData["Canonical"] = $"{Request.Scheme}://{Request.Host}{Request.PathBase}/{id}";
```
これで例えば以下のようなURLのどちらを使ってもGoogleには上で登録される。

```html
https://fanza-actress-bust-search.azurewebsites.net/actress/25929
https://fanza-actress-bust-search.azurewebsites.net/actress/25929/女優の名前
```


#サイトマップを置いてみる
次にこれもSEOに関わるサイトマップについて。最初はルーティングして動的に返すようにしていた。

```cs
[Route("/sitemap.xml")]
```
ただこの実装でデータベースへのアクセスをしており、量が多いと重くなってしまった。サイトマップは5万ページを超す場合はsitemapIndex.xmlを作って、そこに各ページへのリンクをはって、1ページ毎に5万ページ分の内容を追加する形になる。現状60万ページぐらいあるので13ページある。これだと1Pを開くのにも時間がかかる。試しに130ページにして5000ページ分にしてみたが、それでも重かった。そこでデータ取得の自動化をしている処理の中で、このxmlを静的に作って、そのままサイトにアップする仕組みに変えた。静的に作られたファイルを置くだけなので当然速い。

#robots.txtが置いてみる
さて、サイトマップを実際に置いてみたが、[Google Search Console](https://search.google.com/search-console/welcome?hl=ja)が何故かサイトマップを自動で認識してくれない。試しに手動で登録してみたら登録されたが、自動が駄目。理由は分からなかったが、色々調べるとrobots.txtを置いた方が良いという事が分かった。ところがこれを置いても上手くいかない。[robots.txt によるブロックをテスト](https://www.google.com/webmasters/tools/robots-testing-tool)で調べてみると、1行目の最初でエラーが出ていた。これは文字コードの問題だった。そこで文字コードを直したらテストは成功するようになったが、引き続きブロックされましたのエラーは出ていた。

#robots.txtがブロックしてしまう
この問題が何か月も解決出来ずに困っている。具体的にはGoogle Search Consoleで「robots.txt によりブロックされましたが、インデックスに登録しました」が出るが実際にはブロックされていない。ブロックされていると言われるURLを[robots.txt によるブロックをテスト](https://www.google.com/webmasters/tools/robots-testing-tool)でテストすると**成功**する。成功するのにブロックされたと出るのだ。これが分からない。もし原因が分かる人がいれば是非是非教えて欲しい。