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

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

ジョー・ヒタギ の 止リ木

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

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

はてなブログは独自ドメインへの移行時を除いて301リダイレクトをサポートしていない。そのため、JavaScriptなどでリダイレクトを実装する必要がある。
ところがリダイレクトしたいURLが複数ある場合、私が調べた限りではコーディングがかなり手間になってしまう。

そこで、新旧URLの対応表からリダイレクト用コードを自動生成するスクリプトをPythonで作ったのでご紹介する。

※追記:本記事のJavaScriptコードで大量のページをリダイレクトする場合、ページの読み込みが非常に遅くなる可能性がある。この点を改良した軽量化・高速化バージョンを別の記事で公開している。

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

リダイレクト用コード

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

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript" language="javascript">
// <![CDATA[
  var href = window.location.href;
  var re = new RegExp(".*entry/{old_url}");
  if (re.test(href)) {
    $(document).ready(function() {
      if ($("#main-inner").children().hasClass("no-entry")) {
        var content = "<p>本記事は移転しました。</p><p>約3秒後にリダイレクトします。</p><p>リダイレクトしない場合は<a href='{new_url}'>こちら</a>をクリックしてください。</p>" ;
        $(".entry-footer").addClass("sorry_content");
        $(".entry-footer").html(content);
      }
    });
    var url = "{new_url}";
    var link = document.getElementsByTagName("link")[0];
    link.href = url;

    setTimeout("redirect()", 3000);
    function redirect(){
    location.href = url;
    }
  }
// ]]>
</script>

上のコードはこちらのサイトに掲載されているものをごく一部だけ変更したものである。

seiritozakki.hatenablog.com

変更箇所は次の通り。

  • jQueryの読み込み先を最新版に変更
  • クオテーションマークをできるだけダブルに統一
  • 置換箇所の明示
  • 日本語文の言い回し

旧URLにアクセスすると以下のようなページが表示され、自動的に新URLに転送される。

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

使い方

  1. {old_url}を旧URLの〜entry/以降と置換する(1箇所、例:2019/07/29/225324
  2. {new_url}を新URL(全体)と置換する(2箇所、例:https://www.joe-hitagi.com/entry/ksc_m11-plug
  3. コードを「デザイン設定」→「ヘッダー」に貼る

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

リダイレクトしたいページが複数ある場合は// <![CDATA[// ]]>の部分をコピペして対応する。しかし、なかなかに面倒なのでコードを自動で生成するスクリプトをPythonで書いた次第である。

コード生成用スクリプト

# -*- coding: utf-8 -*-

import os
import sys
import re
import pandas as pd

#=======================設定する変数ここから=======================
#output_dir = r"/Users/"
output_dir = ""
#出力ファイルを保存するディレクトリ(末尾に区切り文字を含む)
#空白ならこのスクリプトがあるディレクトリに出力する

output_name = r"URLtest.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 href = window.location.href;\n'\
        '  var re = new RegExp(".*entry/{old_url}");\n'\
        '  if (re.test(href)) {\n'\
        '    $(document).ready(function() {\n'\
        '      if ($("#main-inner").children().hasClass("no-entry")) {\n'\
        '        var content = "<p>本記事は移転しました。</p><p>約3秒後にリダイレクトします。</p><p>リダイレクトしない場合は'\
        '<a href=\'{new_url}\'>'\
        'こちら</a>をクリックしてください。</p>" ;\n'\
        '        $(".entry-footer").addClass("sorry_content");\n'\
        '        $(".entry-footer").html(content);\n'\
        '      }\n'\
        '    });\n'\
        '    var url = "{new_url}";\n'\
        '    var link = document.getElementsByTagName("link")[0];\n'\
        '    link.href = url;\n'\
        '\n'\
        '    setTimeout("redirect()", 3000);\n'\
        '    function redirect(){\n'\
        '    location.href = url;\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として読み込み

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):
    #URLが書かれているかを判定
        url_lst.append([old_url, new_url])

with open(output_dir + output_name, "wt") as output_file:
    print(script_head, file=output_file)
    for item in url_lst:
        old_entry = re.search("entry/(.*)", item[0]).group(1)
        script2 = script.replace("{old_url}", old_entry)
        script2 = script2.replace("{new_url}", item[1])
        print(script2, file=output_file)
    print(script_foot, file=output_file)

動作環境

上記コードはPython3で動く。ただし追加で以下のライブラリが必要。

  • Pandas
  • xlrd

ライブラリのインストールはpipコマンドで行う。 Anacondaの場合はpipの代わりにconda installを使わないと故障の危険があるので注意。

使い方

URL対応表の用意

URLの新旧の対応を記録したエクセルファイル(.xlsx)を予め用意する必要がある。ファイルの形式は次の通り。

f:id:Jo-Bitaki:20200117192215p:plain

1列目に旧URLを書き、2列目を空けて3列目に新URLを書く。URL以外の文字が書かれたセルや空白のセルは無視される。それを利用して項目名などを書いていただいても良い。
上の図の例では、実際に読み込まれるのは2行目と4行目のみである。

スクリプトの設定

設定すべき変数はoutput_diroutput_nameの2つのみ。スクリプト内の記入例を参考に設定していただきたい。

スクリプトの起動方法

コマンドプロンプトに次のように入力すると、リダイレクト用のJavaScriptが書かれたテキストファイルが出力される。

python [スクリプト.py] [URL対応表.xlsx]

環境によってはpythonではなくpython3と入力しないと動かないかもしれない。
スクリプトファイルや入力ファイルがカレントディレクトリにない場合、ファイル名だけでなくパスも入力する必要がある。ファイルをコマンドプロンプトにドラッグアンドドロップすれば自動的に絶対パスが入力されるので手間がないだろう。

注意

試しに40個のURLを組み込んだJavaScriptコードを本ブログに貼り付けたところ、ページの読み込みが非常に遅くなった。本スクリプトを使用される場合、まずは少ないURL数で様子見していただきたい。

※追記:冒頭にも述べたとおり、改良型を下の記事でご紹介している。基本的な使い方は変わっていない。

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

おまけ:スクリプトのカスタマイズ

URL対応表を下図のようにし、1列目に「1」が入力されている行のURLだけリダイレクト用コードに埋め込むようにしてみた。

f:id:Jo-Bitaki:20200117192211p:plain

この例では、実際にコードに埋め込まれるのは2行目と5行目である。

カスタマイズ後のコードは、前述のコードのforループを以下のように書き換えたもの。処理の一部に新たな条件分岐が加えてある。

for row in df.itertuples():
    #ループで各行を取得
    flag = row[1]
    if flag == 1:
        old_url = row[2]
        new_url = row[4]

        if (type(old_url) is str) and ("/entry/" in old_url) and (type(new_url) is str) and re.match("https?://", new_url):
            url_lst.append([old_url, new_url])