SEO内部チェックについて簡単なスクレイピング処理を作成してみる

今回は内部対策で必要な基本的なタグ(項目)について 実際にスクレイピング処理をpythonを使って
構築しつつ、作成してみたいと思います。

弊社ではSEO内部調査において項目を抽出する部分をシステム化していますが、
複数サイトを保有していたりすると手動で抽出するのは大変かと思います。
そこで簡単に抽出するプログラムを作成方法を含め紹介したいと思います。



SEO内部対策における基本的なチェック項目

SEO内部対策で重要な7項目

ご存知の方もいらっしゃるとは思いますが、SEOの内部対策で
よくチェックする基本的な項目についておさらいします。

  1. 見出しタグ(“h1”)
  2. タイトルタグ
  3. ディスクリプションタグ
  4. キーワードタグ
  5. カノニカルタグ
  6. robots.txt
  7. レスポンシブ対応の有無

上記1〜7の項目はSEO内部対策をする上でほぼ確実にチェックされると思います。
(この他にもwwwありなしの統一やSSL化、index数などチェック項目はあると思いますが、
今回は上記の7項目のみに絞って書いて見たいと思います)


seoの内部対策について詳しい項目や解説については以下のリンクを 参照するとわかりやすいかもしれません。


実際にスクレイピング処理を書いて情報を抽出

環境&前準備について

プログラムを作成する前に、環境と前準備についてですが、
今回、環境は以下のものを使用しております。
【OS】
・macOS X 【使用言語】
・python 3.6.1(3系)
【使用ライブラリ】
・openpyxl(エクセル操作に使用します)
・BeautifulSoup4(こちらを使用してスクレイピングします)
【使用ファイル】 urlList.txt(スクレイピング対象のURLを記載しておきます)
項目.xlsx(最終的にこのエクセルファイルを元に情報を出力します)

用意したurlList.txtにスクレイピング対象のURLを記載しておきます。
(下記、画像参照)

【urlList.txt】



【項目.xlsx】



今回、pythonを使った理由としては”なんか最近流行っているらしい・・”,
“beautifulsoupという便利なスクレイピング用ライブラリがあるらしい”
といった漠然とした理由です・・。
という訳で、次の章にてテキストファイルに記載されているURLの
スクレイピングをする処理について書いていきます。

対象サイトのHTMLを丸ごとスクレイピング

まず初めに対象サイトのHTMLを丸ごとスクレイピングする処理を作成します。
当記事のサンプルでは2URL分です。(前述してある”urlList.txt”のURLを増やせばその分出力されます)

【scraping.py】
###モジュールのインポート###
import urllib.request
import requests
from bs4 import BeautifulSoup
###モジュールのインポート###


def scraping(url, j):
    #HTML取得(beutifulsoupを使用)
    r = requests.get(url)
    soup = BeautifulSoup(r.content, "html.parser")
    #文字列からタブと半角空白と全角空白と改行を削除
    strhtml = soup.text
    strhtml = strhtml.replace(" ", "")
    strhtml = strhtml.replace("\n", "")
    strhtml = strhtml.replace("\r", "")

    #テキストファイルを書き込みで作成
    f = open(str(j) + '_sample.txt', 'w')
    #取得したHTMLをファイルに書き込む
    f.write(strhtml)
    #ファイルを閉じる
    f.close()

if __name__ == '__main__':
    
    #urlList.txtファイル読み込み
    lists = []
    conf = ''
    for line in open('urlList.txt', 'r'):
        line = line.rstrip()
        lists = lists + [line]

    #テキストファイル名の先頭に数値をつける
    j = 1
    #urlList.txt内のURL数だけループする
    for url in lists:
        #関数呼び出し
        scraping(url, j)
        #インクリメント
        j+=1


では、実際に実行してみます。
ターミナルにて”python scraping.py”を実行します。
(windowsの場合は、cmdにて実行)

出力した結果を確認します。

【1_sample.txt】



【2_sample.txt】



無事に、HTMLタグ内の文字列が取得できています!
次はこのHTMLから初めに述べた内部調査に必要な項目のみを
抽出していきたいと思います。

SEO内部調査に必要な情報のみをスクレイピング

丸ごと抜き出したHTMLソースから上記で書いた基本的なチェック項目のみを抽出して
出力してみたいと思います。

上記の【scraping.py】の処理を修正、追加してみます。
今度は、テキストファイルだとわかりにくいので
あらかじめ作成したエクセルファイル(【項目.xlsx】)に
取得した情報を記載するようにします。

【scraping.py】
###モジュールのインポート###
import urllib.request
import requests
import openpyxl as px
from bs4 import BeautifulSoup
from urllib.parse import urlparse
from openpyxl.styles import Font, Color, colors
###モジュールのインポート###


def scraping(Sheet1, url, j):
    
    #HTML取得(beutifulsoupを使用)
    r = requests.get(url)
    soup = BeautifulSoup(r.content, "html.parser")
    
    #header部分だけを抽出
    header = soup.find("head")
    #タイトル
    title = header.find("title").text
    #ディスクリプション
    description = header.find("meta", attrs={"name": "description"})
    #キーワード
    keywords = header.find("meta", attrs={"name": "keywords"})
    #canonical
    can = header.find("link", rel="canonical")
    #viewport(レスポンシブ)
    viewport = header.find("meta", attrs={"name": "viewport"})
    
    
    #タグ内容出力
    Sheet1.cell(row = 2, column = j).value = url
    if title:
        Sheet1.cell(row = 3, column = j).value = title
    
    if can:
        Sheet1.cell(row = 6, column = j).value = can['href']
    else:
        Sheet1.cell(row = 6, column = j).value = "設定なし"
        Sheet1.cell(row = 6, column = j).font = Font(color=colors.RED)
    
    if description:
        Sheet1.cell(row = 4, column = j).value = description['content']
    else:
        Sheet1.cell(row = 4, column = j).value = "設定なし"
        Sheet1.cell(row = 4, column = j).font = Font(color=colors.RED)
    
    if keywords:
        Sheet1.cell(row = 5, column = j).value = keywords['content']
    else:
        Sheet1.cell(row = 5, column = j).value = "設定なし"
        Sheet1.cell(row = 5, column = j).font = Font(color=colors.RED)
    

    if viewport:
        Sheet1.cell(row = 8, column = j).value = str(viewport)
    else:
        Sheet1.cell(row = 8, column = j).value = "設定なし"
        Sheet1.cell(row = 8, column = j).font = Font(color=colors.RED)


    #body部分だけを抽出
    body = soup.find("body")
    com_h1tag = ""

    #h1タグを全て取得します
    h1tags = body.findAll("h1")
    #タグ内容出力(タグをまるごと)
    for h1tag in h1tags:
        if h1tag is not None:
            com_h1tag += str(h1tag) + "\n"

    Sheet1.cell(row = 7, column = j).value = com_h1tag

    #robots.txtの内容を取得します(トップページ下にある場合のみ)
    #ドメインを取得
    parsed_url = urlparse(url)
    scheme = parsed_url.scheme
    domain = parsed_url.netloc

    re_url = scheme + "://" + domain + "/robots.txt"
    r2 = requests.get(re_url)
    soup2 = BeautifulSoup(r2.content, 'html.parser')

    if soup2:
        if r2.status_code == 200:
            Sheet1.cell(row = 9, column = j).value = soup2.text
        else:
            Sheet1.cell(row = 9, column = j).value = "robots.txtがトップページ下に存在しません。"
            Sheet1.cell(row = 9, column = j).font = Font(color=colors.RED)


if __name__ == '__main__':
    
    #urlList.txtファイル読み込み
    lists = []
    conf = ''
    for line in open('urlList.txt', 'r'):
        line = line.rstrip()
        lists = lists + [line]
    
    #excelテンプレート
    book = px.load_workbook('項目.xlsx')
    
    #excel結果ファイル名
    bookname = '結果.xlsx'
    
    #excelシート
    Sheet1 = book.get_sheet_by_name('Sheet1')
    
    j = 2
    #urlList.txt内のURL数だけループする
    for url in lists:
        #関数呼び出し
        scraping(Sheet1, url, j)
        #インクリメント
        j+=1

    #excel保存
    book.save(bookname)


結果のエクセルファイルを確認してみます。

【結果.xlsx】



無事、各項目が取得できているようです!


最後に処理をカスタマイズしてみる

キーワードの出現数を確認

最後に今まで書いた処理と検索キーワードを絡めて
タイトルタグとh1タグにおけるキーワードの出現回数を
を自動で出力するようにしてみます。

【scraping.py】を以下のように修正します。


【scraping.py】
###モジュールのインポート###
import sys
import re
import urllib.request
import requests
import openpyxl as px
from bs4 import BeautifulSoup
from urllib.parse import urlparse
from openpyxl.styles import Font, Color, colors
###モジュールのインポート###


def scraping(Sheet1, keyword, url, j):
    
    #HTML取得(beutifulsoupを使用)
    r = requests.get(url)
    soup = BeautifulSoup(r.content, "html.parser")
    
    #header部分だけを抽出
    header = soup.find("head")
    #タイトル
    title = header.find("title").text
    #ディスクリプション
    description = header.find("meta", attrs={"name": "description"})
    #キーワード
    keywords = header.find("meta", attrs={"name": "keywords"})
    #canonical
    can = header.find("link", rel="canonical")
    #viewport(レスポンシブ)
    viewport = header.find("meta", attrs={"name": "viewport"})
    
    
    #タグ内容出力
    Sheet1.cell(row = 2, column = j).value = url
    if title:
        Sheet1.cell(row = 3, column = j).value = title
    
    if can:
        Sheet1.cell(row = 6, column = j).value = can['href']
    else:
        Sheet1.cell(row = 6, column = j).value = "設定なし"
        Sheet1.cell(row = 6, column = j).font = Font(color=colors.RED)
    
    if description:
        Sheet1.cell(row = 4, column = j).value = description['content']
    else:
        Sheet1.cell(row = 4, column = j).value = "設定なし"
        Sheet1.cell(row = 4, column = j).font = Font(color=colors.RED)
    
    if keywords:
        Sheet1.cell(row = 5, column = j).value = keywords['content']
    else:
        Sheet1.cell(row = 5, column = j).value = "設定なし"
        Sheet1.cell(row = 5, column = j).font = Font(color=colors.RED)
    

    if viewport:
        Sheet1.cell(row = 8, column = j).value = str(viewport)
    else:
        Sheet1.cell(row = 8, column = j).value = "設定なし"
        Sheet1.cell(row = 8, column = j).font = Font(color=colors.RED)


    #body部分だけを抽出
    body = soup.find("body")
    com_h1tag = ""

    #h1タグを全て取得します
    h1tags = body.findAll("h1")
    #タグ内容出力(タグをまるごと)
    for h1tag in h1tags:
        if h1tag is not None:
            com_h1tag += str(h1tag) + "\n"

    Sheet1.cell(row = 7, column = j).value = com_h1tag

    #robots.txtの内容を取得します(トップページ下にある場合のみ)
    #ドメインを取得
    parsed_url = urlparse(url)
    scheme = parsed_url.scheme
    domain = parsed_url.netloc
    #urlリクエスト
    re_url = scheme + "://" + domain + "/robots.txt"
    r2 = requests.get(re_url)
    #リクエストページのHTMLをスクレイピング
    soup2 = BeautifulSoup(r2.content, 'html.parser')
    #リクエストが成功&HTMLが取得できた場合
    if soup2:
        if r2.status_code == 200:
            Sheet1.cell(row = 9, column = j).value = soup2.text
        #リクエストが失敗した場合
        else:
            Sheet1.cell(row = 9, column = j).value = "robots.txtがトップページ下に存在しません。"
            Sheet1.cell(row = 9, column = j).font = Font(color=colors.RED)

    #キーワード出現数
    #結果格納用の変数
    output1 = ""
    output2 = ""
    output3 = ""
    #htmlソースからscriptとstyleタグを除く
    for script in soup("script"):
        script.decompose()
    for style in soup("style"):
        style.decompose()
    strhtml = soup.text
    #文字列からタブと半角空白と全角空白と改行を削除
    strhtml = strhtml.replace(" ", "")
    strhtml = strhtml.replace("\n", "")
    strhtml = strhtml.replace("\r", "")
    #キーワードが複数の場合(SEO 東京など)キーワード一つづつ配列へ
    kensakukeys = re.split(" +", keyword)
    #キーワードの数だけループ
    for kensakukey in kensakukeys:
        #ページ全体のキーワード出現数
        cnt = strhtml.count(kensakukey)
        #タイトルキーワード出現数
        titleKeyCnt = title.count(kensakukey)
        #h1キーワード出現数
        h1KeyCnt = com_h1tag.count(kensakukey)
        #全て変数に入れる
        output1 += kensakukey + " : " + str(cnt) + "\n"
        output2 += kensakukey + " : " + str(titleKeyCnt) + "\n"
        output3 += kensakukey + " : " + str(h1KeyCnt) + "\n"

    #excelへ出力
    Sheet1.cell(row = 10, column = j).value = output1
    Sheet1.cell(row = 11, column = j).value = output2
    Sheet1.cell(row = 12, column = j).value = output3


if __name__ == '__main__':
    
    argvs = sys.argv
    keyword = argvs[1]
    
    #urlList.txtファイル読み込み
    lists = []
    conf = ''
    for line in open('urlList.txt', 'r'):
        line = line.rstrip()
        lists = lists + [line]
    
    #excelテンプレート
    book = px.load_workbook('項目.xlsx')
    
    #excel結果ファイル名
    bookname = '結果.xlsx'
    
    #excelシート
    Sheet1 = book.get_sheet_by_name('Sheet1')
    
    j = 2
    #urlList.txt内のURL数だけループする
    for url in lists:
        #関数呼び出し
        scraping(Sheet1, keyword, url, j)
        #インクリメント
        j+=1

    #excel保存
    book.save(bookname)


ここで、実際に実行してみます。
ターミナルにて”python scraping.py “[キーワード]””
を実行します。
(今回のサンプルでは[キーワード]の部分を”SEO 東京”にしております。)

出力された結果のエクセルファイル(結果.xlsx)を確認します。

【結果.xlsx】



結果それぞれのキーワード出現回数が記載されているのを確認しました!

まとめ

SEOにおいて内部対策を行うことはとても重要です。
しかし、チェックすべきWebサイトやページが沢山有る場合、
一つ一つ手動で見ていくのはとても手間で時間のかかる作業です。

Pythonのbeautifulsoupを使ってスクレイピングを行うと
必要な情報だけを選別して瞬時に取得してチェックすることができます。

今回はPythonを使用しましたがPHPやRubyを使っても同様な
ことを行うことが出来ます。

今回はHTMLソースからタグを取得しただけですが、
Pythonのseleniumを使い、ブラウザを操作して
セーフブラウジングの確認やドメイン年齢取得などの
処理もまとめて自動取得が可能です。

この記事が呼んでくださった方の作業短縮の助けになれば幸いです。

お気軽にお問い合わせください。