もっく日記

書いておぼえるためのブログ

多言語サイの検索結果が英語表記になってしまったときのメモ

多言語サイトのGoogle検索結果が英語表記になってしまったので修正した時のメモです。

原因と対策

原因1

ユーザーの言語に合わせて、日本語の場合はhttp://xxx/に、英語の場合はhttp://xxx/en/に、スペイン語の場合はhttp://xxx/es/に、それぞれJavascriptでリダイレクトをかけていたのが原因でした。

こういったリダイレクトの場合、「Googlebot」は英語ユーザーになるので英語ページにリダイレクトされてしまい、英語のMETA情報が検索結果に表示されたようです。

対策1

Javascriptでのリダイレクトをやめて、かわりにhreflangタグを設定しました。

hreflangタグを設定すると、ユーザーの言語に合わせた検索結果が表示できます。

(例)メインターゲットが日本語の、日・英2言語に対応したサイトの場合

<link href="日本語サイトのページURL" hreflang="x-default" rel="alternate">
<link href="日本語サイトのページURL" hreflang="ja" rel="alternate">
<link href="英語サイトのページURL" hreflang="en" rel="alternate">

上記のように指定します。

hreflangタグの確認方法

Search Console」のアカウントをもっていれば、Search Consoleの「ダッシュボード > 検索トラフィック > インターナショナルターゲティング」で確認できます。

正しく設定されてないと「サイトにhreflangタグがありません。」と表示されます。

ここで問題がないのに反映されない場合は、サイトがGoogleのルールーに違反してるのが原因かもしれません。←(原因2)

原因2

ページロード時は<body>cssで非表示にして、読み込み後にjsで表示させていた(非同期読み込み)のが原因で、コンテンツのないページと認識されていました。

Googlebotのレンダリング結果を調べるのには「Fetch as Google」を使いました。

Fetch as Google」とは

Google が行う URL のクロールまたはレンダリングの方法をテストする」もので、週に500回まで取得できます。 「Search Console」内にあるので、Search Consoleのアカウントが必要です。 私の場合、ここでレンダリングを確認したら、キャプチャ画像にコンテンツが何も表示されていない状態(真っ白)でした。

対策2

css<body>を非表示にするのをやめて、jsがなくても全コンテンツが正しく表示されるように作り直しました。

Googlebotのjsレンダリングは、同期的な読み込みには対応しいるけど、Ajax 経由など非同期読み込みには対応してないそうです。

こちらのサイトが参考になりました

javascriptを使ったSEO対策まとめ - Qiita

検索結果を直すには「Search Console

Search Console」のアカウントを持っていれば、サイトの再クロールの依頼を出したり、クロールエラーの確認ができます。アカウントがない場合は再クロールされるのを数日待ちます。

修正&反映のながれ

  • (1)ソースを修正します
  • (2)「Search Console」に確認したいサイトを登録して、「クロール > Fetch as Google」に移動します。
  • (3)「取得してレンダリング」ボタンをクリックします https://gyazo.com/8f78ce30acbd65b2397b9d86c760091a

  • (4)しばらくすると読み込みが完了するので、リストから確認したい項目を選択してレンダリング表示を確認します

  • (5)表示に問題がなければ「インデックス登録をリクエスト」をクリックします

あとは再クロールされるのを待ちます。即時に反映されることもあれば、1〜2日かかることもありました。

ちなみに

再クロール直後は、日本語の検索結果が表示されるようになった!と思ったのに、翌日には英語に戻ってるということがありました。そのときはhreflangタグは正しいけど、クロールのレンダリングが正しくないのが原因でした。(←原因2)

その他

解決のヒントを探すなら

ウェブマスター ヘルプ フォーラム

メインターゲットを日本以外にするなら、ドメインは「.com」や「.net」

日本のユーザーがメインターゲットで、補足として多言語サイトを設置するなら「.jp」など地域に紐づいたドメイン(ccTLD)でも問題ないそうです。ただし英語圏をメインターゲットにする場合は、「.com」や「.net」など(gTLD)にするのだそうです。

雑感

検索結果の表示が意図通りにならない場合、クロールエラーやGoogleの仕様にそってない、などSEO的な要因が多いようですが、SEOに不慣れだと単純なことでも原因をみつけるまでが一苦労でした。

↓ここらへんを理解しておくと何かとよさそうだなと思いました。

ガイドライン

ListingAPIをさわってみた

リクルートが公開してるListing APIをさわってみたので、より理解を深めるためにメモ。

参考サイト

ListingAPIとは

ユーザーの購入履歴などから、レコメンドリストを生成するAPI

用途

同一のAPI呼び出しに、最低60秒間をおく必要があるそうなので、 定期的な手動でのログデータ解析とかに使うのかなと思いました。 で、そのレコメンドデータをさらに他の解析と組み合わせたりもするんですかね。

試してみたこと

train_data.csvをアップして、演算にかけて、listing_list.csvをダウンロード。

感想

ユーザーの購入してない商品のなかで、APIが優先順位(スコア値)をつけてお勧めしてるみたいでした。AIの精度はわからないので様子見ですね。

手順(*curlを使える環境があることが前提です。)

公式サイトの方法です。

下準備

0-1)ログデータの用意

サンプルデータ

フォーマット

  • CSV形式
  • 英数字のみ
  • ファイル名はtrain_data.csv

下記3つの情報が必要です。

  • user_id:(ユーザーID)
  • item_id:(商品ID)
  • time_stamp:(購入時間)

0-2)APIキーの取得

公式サイトの「API KEY 発行」ボタンから「APIキー」を取得します。

ここからが実作業

1)演算対象ファイルアップロードURLの取得

下記コードの「xxxxxxxxxxxxxxxxx」を取得したAPIキーに書き換えて、ターミナルでたたく。

curl "https://api.a3rt.recruit-tech.co.jp/listing/v1/get_upload_url" \--get \--data "apikey=xxxxxxxxxxxxxxxxx"

すると

{"status": 0, "message": "ok", "result": {"url": "https://www.googleapis.com/upload/storage/v1/b/a3rt-public-api-listing/o?xxxxxxxxxx"}}

という結果がかえってくれば成功です。

"result"urlhttps://www.googleapis.com/upload/storage/v1/b/a3rt-public-api-listing/o?xxxxxxxxxx がファイルのアップロード先です。

違う結果になった場合

公式サイトの「ステータスコード / メッセージ」を参照します。

2)演算対象ファイルのアップロード

アップロード先を指定

さっき取得した「アップロード先URL」を下記コードの「yyyyyyyyyyyyyyyy」に貼り付けてターミナルでたたきます。

export UPLOAD_LOCATION='yyyyyyyyyyyyyyyy'

ログデータを指定してファイルをアップ

そのあと下記を実行。(アップするログデータを置いてる階層に移動するのをお忘れなく。)

curl -H 'Content-Type: text/plain' -X PUT --upload-file train_data.csv "$UPLOAD_LOCATION"

すると

{
 "kind": "storage#object",
 (中略)
 "etag": "COuso4L+z9MCEAE="
}

みたいな値が返って来ればアップロード完了です。

3)w2v演算処理開始

下記を実行

curl "https://api.a3rt.recruit-tech.co.jp/listing/v1/start_w2v" \--get \--data "apikey=xxxxxxxxxx"

// xxxxxxxxxx はAPIキー

↓このように返ってきたら演算開始です。演算が終了するまでしばらく待ちます。

{"status": 0, "message": "instance starts up."}

4)演算の進捗確認

w2v演算処理のステータスは下記コードで取得できます。

curl "https://api.a3rt.recruit-tech.co.jp/listing/v1/status_w2v" \--get \--data "apikey=xxxxxxxxxx"

// xxxxxxxxxx はAPIキー

下記のように返ってきたら演算完了です。

{"status": 0, "message": "SHUTDOWN instance"}

5)演算結果ファイルダウンロードURLの取得

下記を実行

curl "https://api.a3rt.recruit-tech.co.jp/listing/v1/get_download_url" \--get \--data "apikey=xxxxxxxxxx"

// xxxxxxxxxx はAPIキー

このように返ってきたら成功です。

{"status": 0, "message": "ok", "result": {"url": "https://storage.googleapis.com/a3rt-public-api-listing/xxxxxxxxxx"}}

"result"url

https://storage.googleapis.com/a3rt-public-api-listing/xxxxxxxxxx

がダウンロードURLです。

このURLをブラウザに入力すると、リスティングされたデータをダウンロードできます。

Googleタグマネージャーの読了率計測でタブのフォーカスもチェックする

できる逆引き Googleアナリティクス」を読みながらGoogleタグマネージャの読了率を設定した時に、ブラウザのタブのフォーカス状態もチェックしたものが欲しかったのでその時のメモ。

仕組み

ページ下部までスクロールしたかフラグと、タブにフォーカスが当たってるかフラグの2つの変数を用意。 1分後に2つのフラグの状態を確認。両方trueだったら読了とする。

1. 変数を作成

  1. 変数メニューを選択
  2. ユーザー定義変数の「新規」ボタンをクリック
  3. 変数タイプ「JavaScript変数」を選択し、グローバル変数名を設定

上記の手順で下記2つの変数をつくります

  • IS_READTHROUGH:ページ下部までスクロールされたかチェックする変数
  • IS_ONFOCUS:ブラウザのタブの状態をチェックする変数

https://gyazo.com/1db000bd6a9622755fa7ea7cab1dee36

2. 測定するページのトリガーを作成

計測ページを指定する場合は埋め込むページ分のトリガーをつくります。全ページに埋め込む場合はこの作業はいりません。

  1. トリガーメニューを選択
  2. 「新規」ボタンをクリック
  3. トリガータイプ「ページビュー」を選択
  4. このトリガーの発生場所「一部のページビュー」を選択して、パスやURLを指定します。(詳しくは以下)

ディレクトリ以下全ページを指定する場合

(例)http://www.xxx/company/以下全ページ

「Page URL」+「等しい」+「http://www.xxx/company/」

https://gyazo.com/15944a1d8dd122af21ff0ffd7ce05e57

●1ページだけ指定する場合

(例)http://www.xxx/about/index.html

「Page Path」+「等しい」+「/about/index.html」

https://gyazo.com/a7590bfc717713c70289d7ab452fc249

注)複数条件指定するとand検索になるため、1つのトリガーの「 Page Path 」に複数指定すると正しく動作しません。1ページにつき1トリガー作る必要があります。

参考サイト

Googleタグマネージャで「特定のページ」を指定するルールの作り方|コラム アユダンテ株式会社

3. カスタムHTMLタグでJSを書く

  1. タグメニューを選択
  2. 「新規」ボタンをクリック
  3. タグタイプ「カスタムHTML」を選択
  4. 下記のJSを記述
  5. トリガーに『2. 測定するページのトリガーを作成』でつくったトリガーを設定します
<script>
// スクロール
IS_READTHROUGH = false;
window.addEventListener( 'scroll', function(){
  var scrollHeight = Math.max.apply( null, [document.body.clientHeight , document.body.scrollHeight, document.documentElement.scrollHeight, document.documentElement.clientHeight] );
  var scrollPosition = window.innerHeight + window.pageYOffset;
  if((scrollHeight - scrollPosition) / scrollHeight <= 0.05){
    IS_READTHROUGH = true;
  }
});
  
// タブのフォーカス
IS_ONFOCUS = true;
window.onfocus=function(){
  IS_ONFOCUS = true;
}
window.onblur=function(){
  IS_ONFOCUS = false;
}
</script>

ここで使ってるIS_READTHROUGHIS_ONFOCUSが『1. 変数を作成』で作ったグローバル変数です。

https://gyazo.com/42dcffd445e1fe69d6024c52788374ba

ここまでで実行部分は完了です。 あとは1分後に変数の状態を確認しにくる部分と、その結果をGoogleアナリティクスに送る部分をつくります。

4. 1分後発火するトリガーを作成

  1. トリガーメニューを選択
  2. 「新規」ボタンをクリック
  3. トリガータイプ「タイマー」を選択
  4. 以下のように設定
    • 「イベント名」:timer60sec
    • 「間隔」:60000
    • 「制限」:1
    • 「これらすべての条件が true の場合にこのトリガーを有効化」:

      「Page Path」+「含む」+「/」

    • 「このトリガーの発生場所」:

      「IS_READTHROUGH」+「等しい」+「true」

      「IS_ONFOCUS」+「等しい」+「true」

https://gyazo.com/5e668e6edc64fbc9c7a984dac695db15

5. Googleアナリティクスに送るタグを作成

  1. タグメニューを選択
  2. 「新規」ボタンをクリック
  3. タグタイプ「ユニバーサルアナリティクス」を選択
  4. 「トラッキングID」にGoogleアナリティクスのトラッキングIDを入れます
  5. 「トラッキングタイプ」に「イベント」を選択
  6. 「イベントトラッキングタイプ」(Googleアナリティクスで表示される名前)
    • 「カテゴリ」:記事の読了率1分
    • 「アクション」:{{Page Path}}
  7. トリガーに『4. 1分後発火するトリガーを作成』でつくったトリガーを設定

https://gyazo.com/aab0380671b42bae61d4fb5d70c08ea3

以上で設定は完了です。

あとはプレビューモードにして、正しく発火してるか確認後、公開。

Googleアナリティクスで確認

翌日以降、Googleアナリティクスに反映されてるはずです。 Googleアナリティクスページの「行動」>「イベント」>「サマリー」で確認。

(イベントカテゴリ表示例) https://gyazo.com/a374d0fd228386aba4a0b8a5f1d28ac7

slick.jsを使ったスライド画像をランダム表示する

参考サイト

https://github.com/kenwheeler/slick/issues/359

ソース

サンプル

HTML

<div class="slideshow">
  <div class="slide"><img src="xxxx.png"></div>
  <div class="slide"><img src="xxxx.png"></div>
  <div class="slide"><img src="xxxx.png"></div>
  <div class="slide"><img src="xxxx.png"></div>
  <div class="slide"><img src="xxxx.png"></div>
</div>

JavaScript

var $slideshow = $('.slideshow');
var $slide = $('.slide');

function randomize(selector){
  $slideshow.find(selector).sort(function(){
    return Math.round(Math.random()) - 0.5;
  }).detach().appendTo($slideshow);
}

$(function(){
  randomize('.slide');
  $slideshow.slick($slide);
});

gulp-iconfontでハマったこと

Cannot read property 'toString' of undefinedとエラーが出る

原因

template.cssglyph.codepointが取れていなかったのが原因でした。

解決方法

gulp-iconfontのドキュメントをちゃんと読んでみたら、

template.cssのこの部分を↓

glyph.codepoint.toString(16).toUpperCase()

このように直す↓

glyph.unicode[0].charCodeAt(0).toString(16).toUpperCase()

と書いてありました。

illustlatorから切り出したSVGのフォントファイルが壊れる

原因

画像サイズが縦横10pxと、小さすぎたのが原因でした。

解決方法

画像サイズを大きくして書き出し直したら解決しました。 (20px以上だと問題なさそうです)

ブラウザの印刷プレビューでハマったことメモ

全ブラウザで白紙の2ページ目が印刷される。表示は1ページに収まってるのに。

原因

htmlbodyheight:100%;をかけていたのが原因でした。

解決方法

印刷時はheight:auto;にするようにしたら解決しました。

@media print{
  html,body{
    height: auto;
  }
}

<body>overflow: visible !important;を設定してもFirefoxで改ページした2ページ目以降が印刷されない

原因

全体の拡大率を調整するために

@media print{
  .section_print{
    transform: scale(2) translate(0, 25%);
  }
}

をかけていたのが原因でした。

解決方法

拡大率で表示調整するのをやめて、幅を%指定にして、印刷時のフォントサイズを大きくするなどCSSを作り直しました。

印刷対応ページを作る時は、比率調整でリサイズできる作りにした方が後々の追加削除などの更新でも調整しやすくていいなと思いました。(scale調整はブラウザによって拡大率に差があるし)

IE10でYoutubeAPIの動画を設定できない

display:none;で非表示にしてる要素に、YoutubeAPIで動画を設定しようとしたらIE10で表示も操作もできない不具合がありました。

display:none;にしてない要素に動画を設定するようにしたら解決しました。

調べてみたらIE10ではdisplay:none;にした要素の機能は無効化されるそうです。

参照元こちら↓)

http://arakaze.ready.jp/archives/3175

Androidのデフォルトブラウザなども同じらしいので気をつけようと思いました。