Django の management comnand で元記事のステイタスを確認する

このサイトの /article/ ディレクトリ以下の記事は、元々は「エクセルマクロ達人養成塾」というサイト https://exvba.com/ (以下、旧サイト)にあったものをインポートしてきたもの。

ある時期から WordPress にしていたのだが、その WordPress 用の DB から直接データをひっぱりだしてきて、 Django サイト用のDBにインポートした。
そのうえで、このサイト用に属性を追加したりしている。
そして、記事の見直しが済んだものについてはぼちぼち公開している。
公開/非公開を切り替えているのは、オブジェクトの accessible_from という DateTimeField の値で、 None なら公開しない、未来の日時の場合も公開しないとしている。

さて、ここで困るのは、同じまたは非常に類似したコンテンツが複数のURLに存在する場合と、SEO的な評価が下がることがあるという問題。
そこで、このサイトで公開属性にした記事は、旧サイトでは非公開にする必要がある。

そのための仕組みとしては、このサイトからページ更新情報を配信(Webページで公開)し、旧サイトにあるスクリプトがその情報を取得して、必要に応じて WordPress の DB 内で記事のフラグを変更し、また、旧サイト来たリクエストについては、このサイトにアップした新記事にリダイレクトされるようにしている。

例: 旧サイトの以下のページにリクエストが来る。
https://www.exvba.com/webr.php

すると、旧サイトの WordPress は、この記事にかかる DB のフラグを確認し、リダイレクト処理をする。

そして、最終的に、リクエストは、 https://forum.pc5bai.com/article/webr/ に転送される。

さてさて。
で、詳しい事情は省略するが、この仕組みがたまにうまく動かないことがあるので、リダイレクトがきちんとされているかどうかを確認するプログラムを書いた。

以下のとおり。

article/management/commands/article_check.py

import requests
from django.core.management import BaseCommand
from ...models import Entry

def check_all_urls_with_thread(entries):
    """
    if the url is 200, print it
    """
    for entry in entries:
        id, title, base, url = entry.id, entry.title_main, entry.get_absolute_url(), entry.base_content_url
        check_url(id, title, base, url)


def print_result(status_code, id, title, base, ):
    result_list = [
        str(status_code),
        title,
        base,
        f'https://forum.pc5bai.com/article/hogehoge/{id}\n' #URLは記事用にテキトーに用意したものです
    ]
    print('\n'.join(result_list))


def check_url(id, title, base, url):
    """
    check the raw status code and report it.
    """
    response = requests.head(url)
    if response.status_code == 200:
        print_result(response.status_code, id, title, base, )
    elif response.status_code == 301:
        redirect_url = response.headers['Location']
        response = requests.head(redirect_url)
        if response.status_code != 200:
            print(f'redirect: {response.status_code}: {url}')
    else:
        print(f'{response.status_code}: {url}')


def _handle():
    entries = Entry.objects.exclude(base_content_url='').filter(accessible_from__isnull=False)
    check_all_urls_with_thread(entries)


class Command(BaseCommand):
    help = 'exvba.com を確認し、記事のURLが200だったもののリストを出力します'

    def handle(self, *args, **options):
        _handle()
        print('done')

このコードは、コンソールから以下のコマンドによって実行できる。

python manage.py article_check

app_name/management/commands/ パッケージ以下に Python モジュールを置き、そこに BaseCommand クラスを継承したクラス Command を置く。
このクラス内で handle メソッドを用意する。
クラス変数 help の値は、 python manage.py article_check -h とか python manage.py article_check --help とかでヘルプを表示するときに最初に出てくる文字列になる。

コマンドに引数を用意することもできるのだが、そこはまたそのうちに。

check_url 関数内では、旧サイトのページの情報を取りにいってその結果によって処理を分岐。
ステータスコードが 200 ならリダイレクトの処理がされていないので良くないよということで結果を出力。
301 リダイレクトされていればまあ問題ないはずだが、リダイレクト先ページの健康状態もついでにチェック。
200, 301 以外なら、これも、異常系ということで結果を出力。

_handle メソッド内の Entry.objects.exclude(base_content_url='') は、旧サイトからのインポート実施以降に新サイトで新たに追加した記事には旧サイトの記事の url たる base_content_url が存在しないので、その分のフィルター。

公開日時: 2023/05/30 06:30