プロクラシスト

今日の寄り道 明日の近道

自サイトの記事のリンク切れを自動で抽出するアレを作った


スポンサーリンク

こんにちは!ほけきよです。

今日は自動化第四弾!! またまたGoogleに媚びを売るSEO対策です(^^)

前回は内部リンクネットワークの可視化でした。今回は、リンク切れの抽出です!

悲しきNot FoundGoogleさんがお怒りになる前に片付けちゃいましょう!

リンク切れとは?

自サイトで言うと、こういうのです

悲しいですよね。以前まであったはずのものがなくなるのは…

というわけで、リンク切れは早めに対処しましょう

めんどい

そう思い、いちいちリンククリックして確かめてたんですが、

めんどい、めんどうがすぎる

大体のリンクはちゃんと通るのに、通らないリンクを探すなんて、修行ですか? というわけで、3記事で飽きました。ううーん、そうだ、自動化しよう

環境を作る

python環境のある人へ : pipで全部入ります。面倒な人は、anacondaに全部入っているはずなのでそれで。

python環境のないwinユーザへ : python環境をwindowsにいれる方法は、私の過去記事に書いています。anacondaを入れておくと大抵のことができるのではかどります(容量が2GBほど必要ということには注意しておいてください)

コード

例の如く下記コードをコピペしてinvalid_links.pyなどで保存してください *1

どこでもいいのですがあんまりわからない!って人はデスクトップに一旦保存しておきましょう。

コードをみる
from bs4 import BeautifulSoup
import urllib
from urllib import request
import time
from argparse import ArgumentParser
import csv


def extract_url(root_url):
    page = 1
    is_articles = True
    urls = []
    
    while is_articles:
        html = request.urlopen(root_url+"/archive?page={}".format(page))
        soup = BeautifulSoup(html, "html.parser")
        articles = soup.find_all("a",class_="entry-title-link")
        for article in articles:
            urls.append(article.get("href"))
        if len(articles) == 0:
            # articleがなくなったら終了
            is_articles = False
        page += 1
    return urls

def url_checker(url, urls):
    #変なリンクは除去したい
    flag1 = "http" in url[:5]     
    #ハテナのキーワードのリンクはいらない
    flag2 = "d.hatena.ne.jp/keyword/" not in url    
    #amazonリンクはダメ
    flag3 = "http://www.amazon.co.jp" not in url and "http://amzn.to/" not in url
    return flag1 and flag2 and flag3

def check_invalid_link(root_url, urls, output):
    import re
    regex = r'[^\x00-\x7F]' #正規表現    
    entry_url = root_url + "/entry/"
    with open (output, "w") as f:
        writer = csv.writer(f, lineterminator='\n')
        writer.writerow(["URL", "ERROR", "LINK", "STATUS"])
        for i,url in enumerate(urls):
            print(i+1,"/",len(urls),url)
            try:
                html = request.urlopen(url)
            except urllib.error.HTTPError as e: 
                print(e.reason)
            except urllib.error.URLError as e: 
                print(e.reason)
            soup = BeautifulSoup(html, "html.parser")
            entry = soup.select(".entry-content")[0]
            links = entry.find_all("a")
            for link in links:
                l = link.get("href")
                #日本語リンクは変換
                matchedList = re.findall(regex,l)
                for m in matchedList:
                    l = l.replace(m, urllib.parse.quote_plus(m, encoding="utf-8"))
                check = url_checker(l, urls)
                if check:
                    #リンク切れ検証
                    try:
                        html = request.urlopen(l)
                    except urllib.error.HTTPError as e: 
                        writer.writerow([url, "HTTP ERROR", l, e.reason])
                        print("HTTPError:", l, e.reason)
                    except urllib.error.URLError as e: 
                        writer.writerow([url, "URL ERROR", l, e.reason])                        
                        print("URLError:", l, e.reason)
                    except UnicodeEncodeError as e:
                        writer.writerow([url, "UNICODE ENCODE ERROR", l, e.reason])
                        print("UnicodeEncodeError:", l, e.reason)                        
            # time.sleep()

if __name__ == '__main__':
    """
    TODO
    - APIを叩いてなんとかなるやつ実装
        - amazon associateの対応
        - youtubeの削除された動画対応
    """
    parser = ArgumentParser()
    parser.add_argument("-u", "--url", type=str, required=True,help="input your url")
    parser.add_argument("-o", "--output", type=str, default="articles.csv", help="output csv name")
    args = parser.parse_args()
    urls = extract_url(args.url)
    check_invalid_link(args.url, urls, args.output)

なにをやっているかだけ簡単に説明しておきます。

  • 本文中からhttpで始まるリンクだけ抜き出している
  • ハテナのキーワードリンクは邪魔なので排除する
  • amazon associateリンクは特殊なことをしないとアクセスできないので除去する
  • リンクにアクセスして、エラーが出たら出力する

という流れになります。

実行する

ターミナル or コマンドプロンプトを開き*2、さっきのinvalid_links.pyが保存されている場所まで移動します。 デスクトップに保存している方は下記コマンドで実行されるはずです。

cd Desktop
python invalid_links.py --url http://www.procrasist.com --output procrasist.csv
  • --url URLで、調べたいブログのURLを入力してください
  • --output hoge.csv で、出力されるcsvの名前を決められます(省略できて、省略した場合はarticles.csvになります)

結果はこんな感じ。

最新記事から順番にびゃぁーーっと調べてくれます。

なお、結果はcsvファイルにも出力されます。 結構リンク切れってあるのね。

今後の課題/注意

下記のことはまだできていません

  • amazon商品リンクのリンク切れ
  • youtubeの削除されたものの追従
  • はてなブログのみに対応
  • ブラウザでのみアクセスを許しているものがあり、拒否(Forbidden)されちゃう。
  • 日本語以外のエンコードエラーに非対応(いずれ直します)

いずれもAPIでうまくすればうまくいくっぽいですが、ちょっと面倒だったので、今回はやめておきます。TODO! はてなブログ以外で試したいという方は、相談していただければ応えられる範囲で答えます!URLをぶっこ抜くところがおそらく一番のポイントです

あと、これは注意ですが、外部へのアクセスを頻繁に行いすぎると、そのサイト運営者の迷惑になりますので、コード実行は最小限にしておいてください

※コードが動かない場合も連絡ください。

まとめ

いかがでしたか? コレでいちいち眠たい眼こすりながらリンクポチポチする必要もなくなりましたねっ

どうぞ試してみてください!

よし、リンク切れ見つかったし、あとはリンクを直すだけd...( ˘ω˘)スヤァ

*1:Windowsのメモ帳でコピペする際は、デフォルトでShift-JISとかのふざけた文字コードになっている可能性があるので、UTF-8で保存しましょう。

*2:windowsユーザーへ。簡単な開き方は、windowsボタン+“cmdと入力”+Enterです

PROCRASIST