もっく日記

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

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

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

原因と対策

原因1

ユーザーの言語に合わせてJavascriptでリダイレクトをかけていたせいで、Googlebot(英語ユーザー)が英語ページにリダイレクトされてしまっていた。

対策1

hreflangタグを設定して、リダイレクトを外しました。

hreflangタグとは

Googleの検索結果を、ユーザーの言語に合わせて表示するためのものです。 (例)日本語と英語の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の「ダッシュボード > 検索トラフィック > インターナショナルターゲティング」で確認できます。

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

コードは正しいのに反映されない場合は、サイトがGoogleのルールーに違反してるのが原因かもしれません。

私の場合は「原因2」のせいで、コンテンツがないGoogleのルールーに違反したサイトと認識されていました。(「Fetch as Google」でレンダリング確認したらキャプチャが真っ白でした。)

Fetch as Google」とは

Fetch as Googleは、ヘルプにあるように、「Google が行う URL のクロールまたはレンダリングの方法をテストする」ものです。週に500回まで取得できます。

原因2

ページロード時はコンテンツをcssで非表示にして、読み込み後にJavascriptで表示。としていたせいで、Googlebotのレンダリングでコンテンツが非表示になり、コンテンツのないソースだけのページと認識されたしまった。

対策2

初期表示でコンテンツを非表示にするのをやめて、JSがない状態でもコンテンツが正しく表示されるように修正しました。 (GooglebotのJavascriptレンダリングはまだ万全ではないようです。) 同期的な読み込みには対応していて、Ajax 経由でのコンテンツ表示など、非同期読み込みには対応してないということみたいです。認識違いしてました。。。(2017/7/12修正)

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

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

検索結果を直す

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

修正&反映のながれ

  • (1)ソースを修正します(「Search Console」のアカウントがない場合は再クロールされるのを数日待ちます。)
  • (2)「Search Console」に確認したいサイトを登録して、「クロール > Fetch as Google」に移動します。
  • (3)「取得してレンダリング」ボタンをクリックします https://gyazo.com/8f78ce30acbd65b2397b9d86c760091a

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

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

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

ちなみに

Fetch as Google」直後は日本語の結果が表示されたのに、翌日になると英語に戻ることがありました。そのときはhreflangタグは正しいけど、「原因2」のせいで違反したページになってました。

解決のヒントを探すなら

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

その他

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

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

雑感

Googleガイドラインを理解せねばと思いました。

タグは正しいはずなのに反映されない場合は、クロールエラーとか、仕様にそってない、などの原因が考えられます。ただ何が仕様で、どこが仕様に違反してるのか、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のデフォルトブラウザなども同じらしいので気をつけようと思いました。