ジョー・ヒタギの止リ木 | 「ものづくり」や「ものなおし」をするブログ

色々なものを作ったり直したりするブログです。主な話題は日用品・電子機器・エアガンなど。

ジョー・ヒタギ の 止リ木

【JavaScript】複数ページをリダイレクトするコード&それを自動生成するスクリプトの改良版【Python】

f:id:Jo-Bitaki:20200124210640p:plain:h200

この記事は以前ご紹介したリダイレクト(ページの転送)用JavaScriptコード、およびそれを自動生成するPythonスクリプトの改良版について述べる。

Pythonスクリプトの使い方やカスタマイズについては以前の記事を参照していただきたい。

【Python】複数ページのリダイレクト用JavaScriptを自動生成するプログラム

リダイレクト用コード

生成するJavaScriptは以下の形式である。

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.2.3.min.js"></script>
<script type="text/javascript" language="javascript">
// <![CDATA[
  var old_array = ["old_entry1", "old_entry2"];
  var new_array = ["new_entry1", "new_entry2"];
  var top_url = "https://www.example.com/entry/";
  var href = window.location.href;
 
  for (var i=0; i<old_array.length; i++){
    var re = new RegExp(".*entry/" + old_array[i]);
    if (re.test(href)) {
      var url = top_url + new_array[i];
      $(document).ready(function() {
        if ($("#main-inner").children().hasClass("no-entry")) {
          var content = "<p>本記事は移転しました。</p><p>3秒後に自動で移動します。</p><p>移動しない場合は<a href='" + url + "'><big><b>こちら</b></big></a>をクリックしてください。</p>" ;
          $(".entry-footer").addClass("sorry_content");
          $(".entry-footer").html(content);
        }
      });
      var link = document.getElementsByTagName("link")[0];
      link.href = url;
 
      setTimeout("redirect()", 3000);
      function redirect(){
      location.href = url;
      }
    }
  }
// ]]>
</script>

このコードは下のサイトに掲載されているものを改変したものである。

【はてなブログ】投稿済みの記事をカスタムURLに変更する場合の対処 - 整理と雑記


最大の改良点は、URLを配列(リスト)に格納したこと(4~5行目)。これにより複数ページを入力した場合の行数が大幅に減り、軽量化と高速化につながったはずである。

あと、次の細かい変更も加えた。

  • 日本語の言い回しを少し変更
  • リンクテキストを大きく・太字にして目立つように変更

旧URLにアクセスするとこのような画面が表示され、自動的に新URLに転送される。

f:id:Jo-Bitaki:20200202220648p:plain:h250

使い方

  1. old_entry1を旧URLの〜entry/以降と置換する(例:2019/08/12/000313
  2. new_entry1を新URLの〜entry/以降と置換する(例:electronic_dictionary-repair
  3. 2つ目以降のURLも同様に置換していく
  4. top_urlに新URLの〜entry/までを代入する(例:https://www.joe-hitagi.com/entry/
  5. コードを「デザイン設定」→「ヘッダー」に貼る

"old_entry1""new_entry1"へ、"old_entry2""new_entry2"へリダイレクトされる。すなわちold_arrayのある要素は、new_arrayの同じ場所の要素に対応している。

リダイレクトするページが3つ以上あるなら、配列の要素を増やすことで対応できる。その場合、区切り文字はカンマ,を使う。

なお、このコードより前でjQueryを読み込んでいるなら1行目は不要である。

コード生成用スクリプト

# -*- coding: utf-8 -*-
 
import os
import sys
import re
import pandas as pd
 
#=======================設定する変数ここから=======================
top_url = "https://www.example.com/entry/"
#転送先URLの先頭部分から"entry/"まで
 
#output_dir = r"/Users/xxx/Desktop/"
output_dir = ""
#出力ファイルを保存するディレクトリ(末尾に区切り文字を含む)
#空白ならこのスクリプトがあるディレクトリに出力する
 
output_name = r"URLtest2.txt"
#出力ファイル名(拡張子含む)
#=======================設定する変数ここまで=======================
 
if output_dir == "":
    output_dir = os.path.dirname(os.path.abspath(__file__)) + os.sep
    #スクリプトがあるディレクトリの絶対パスを取得
 
script_head = '<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>\n'\
              '<script type="text/javascript" language="javascript">'
 
script = \
    '// <![CDATA[\n'\
    '  var old_array = {old_urls};\n'\
    '  var new_array = {new_urls};\n'\
    '  var top_url = "{top_url}";\n'\
    '  var href = window.location.href;\n'\
    '  for (var i=0; i<old_array.length; i++){\n'\
    '    var re = new RegExp(".*entry/" + old_array[i]);\n'\
    '    if (re.test(href)) {\n'\
    '      var url = top_url + new_array[i];\n'\
    '      $(document).ready(function() {\n'\
    '        if ($("#main-inner").children().hasClass("no-entry")) {\n'\
    '          var content = "<p>本記事は移転しました。</p><p>3秒後に自動で移動します。</p><p>移動しない場合は<a href=\'" + url + "\'><big><b>こちら</b></big></a>をクリックしてください。</p>" ;\n'\
    '          $(".entry-footer").addClass("sorry_content");\n'\
    '          $(".entry-footer").html(content);\n'\
    '        }\n'\
    '      });\n'\
    '      var link = document.getElementsByTagName("link")[0];\n'\
    '      link.href = url;\n'\
    '      setTimeout("redirect()", 3000);\n'\
    '      function redirect(){\n'\
    '      location.href = url;\n'\
    '      }\n'\
    '    }\n'\
    '  }\n'\
    '// ]]>'
 
script_foot = "</script>"
 
inputs = sys.argv
#コマンドライン引数を取得
if len(inputs) != 2:
    print('[ERROR: 入力ファイルをコマンドライン引数で1つ指定してください]')
    quit()
 
url_file = inputs[1]
df = pd.read_excel(url_file, header=None, index_col=None)
#エクセルファイルをdata frameとして読み込み
 
old_url_lst = []
new_url_lst = []
#旧URLと新URLを格納するリスト
for row in df.itertuples():
    #ループで各行を取得
    old_url = row[1]
    new_url = row[3]
 
    if (type(old_url) is str) and ("/entry/" in old_url) and (type(new_url) is str) and re.match("https?://", new_url):
        old_entry = re.search("entry/(.*)", old_url).group(1)
        old_url_lst.append(old_entry)
 
        new_entry = re.search("entry/(.*)", new_url).group(1)
        new_url_lst.append(new_entry)
 
with open(output_dir + output_name, "wt") as output_file:
    print(script_head, file=output_file)
 
    script2 = script.replace("{old_urls}", str(old_url_lst))
    script2 = script2.replace("{new_urls}", str(new_url_lst))
    script2 = script2.replace("{top_url}", top_url)
    print(script2, file=output_file)
 
    print(script_foot, file=output_file)

Pythonのリスト(配列)はJavaScriptのそれと全く同じ形式のため、Pythonのリストを丸ごと文字列に変換してJavaScriptコードに埋め込んでいる(85〜86行目)。

使い方

使用法は以前と同様で、新旧URLの対応表をエクセルで作成してスクリプトに読み込ませる。
冒頭でも述べたが、詳しくは前回の記事を参照していただきたい。

【Python】複数ページのリダイレクト用JavaScriptを自動生成するプログラム

おわりに

本コードをテスト用ブログで試したところ、リダイレクトURLが40個ある状態でも読み込み速度を許容範囲内に抑えることができた。
2020年2月8日現在、当ブログでも20個のページをリダイレクトしている。読み込み速度はそれほど遅くないと思うのだがいかがだろうか。

しかし、私はJavaScriptに関して全くの初心者のため、まだまだ軽量化や高速化の余地はあるかもしれない。特にループ処理には何パターンもあるらしいので、高速化を考えるならよく検討すべきと思われる。

【注意】Googleでの検索評価を引き継げないおそれあり(2020年2月12日 追記)

当ブログにリダイレクトコードを設置してから2週間ほど経過した。
旧URLは検索結果に表示されなくなり、代わりに新URLがすべてGoogleにインデックスされた。新URLが重複コンテンツと認定されている様子もない。

しかし、検索順位が明らかに下がっているようだ。すなわち、このコードでは検索評価を正常に引き継げない可能性がある。
その原因として次のようなものを考えてみた。

1. タイムアウトまでの時間が長すぎる

当記事のコードではsetTimeoutの引数を3000ミリ秒、すなわち3秒としている。
この時間をもっと短くしないとGoogle Botにリダイレクトが認識されないのかもしれない。

実際、以下のサイトでは次のような記述がある。

SEOを考慮するとsetTimeout内の数字は0がお勧めです。
出典:javascriptで転送(リダイレクト)を行う方法と注意点 | SEO研究所サクラサクラボ


次のサイトでは検索評価の引継ぎ実験が行われており、検索順位の継承に成功したらしい。

edit.co.uk

上の実験ではそもそもリダイレクトまでの待機時間を設けておらず、即座に新URLへ転送されるようなコードとなっている。

また、以下のサイトの実験ではsetTimeoutの引数を1000ミリ秒(=1秒)としておられる。
この場合にはリダイレクトがSearch Consoleできちんと認識されていたらしい。

beiznotes.org


したがって、setTimeoutの待機時間はできるだけ短くするべきと考えられる。当ブログでも0ミリ秒に設定しなおした。

ただし、Googlebotはページのロード時間が3分未満であれば大人しく待っていてくれるらしい。
 出典:The Googlebot Timeout is 3 Minutes - DeepCrawl

そのため、転送待機時間が3秒でも問題ない可能性もある。

2. コードを<head>に記述していない

当ブログではリダイレクトコードを「デザイン設定」→「ヘッダ」に記述していた。

しかし、前述のサイトには<head>内に記述せよと書かれている。
 出典:javascriptで転送(リダイレクト)を行う方法と注意点 | SEO研究所サクラサクラボ

「ヘッダ」よりも<head>に書いたほうが早く読み込まれるため、Googlebotが認識しやすくなるのかもしれない。
当ブログでも試験的にコードを「設定」→「詳細設定」→「headに要素を追加」に移植してみている。

3. Googleの仕様

こちらの記事によれば、GoogleのPageRankは301リダイレクトをするといくらか失われるらしい。

www.suzukikenichi.com

ただし、これは別のドメインへ移転するときの話であるため、今回のような「個別の記事のURLを変更する」場合に当てはまるかは不明である。


いずれにしても、URLの変更は検索順位を下げる覚悟で臨むべきだろう。