自社のサイトのSEO対策を考える際、インプットとして競合サイトのSEO対策を知りたくなる場合は多いでしょう。
しかし、手作業でサイトの必要な情報(タイトル、description、見出し、キーワード等)を集めて一覧かするのは非常にコストのかかる作業です。
そこで、ここではスクレイピングを利用し、競合サイトの情報を一発でExcelファイルに書き出すスクリプトをご紹介します。
競合サイト調査は時間がかかる
よくSEO解説記事では競合サイトの見出しやキーワードを集めて調査すべしと記述されていますが、手作業ではとにかく時間がかかり、全くもってコストパフォーマンスに優れません。
例えば次のサイトを見てみましょう。こちらのサイトは「プログラミング 独学」で検索した最も上位のWebサイトです。
こちらのサイトから調査に必要な情報を取得するとどうなるかと言うと
- h2見出し:12件
- h3見出し:40件
- h4見出し:16件
- キーワード(strongタグ):39件
こうなります。
これを手動で集めるのは気の遠くなる話です。正直あまりやりたくない作業でしょう。
これをスクレイピングを使ってExcelに全て書き出すことがこのページの主旨となります。
スクレイピングで取得できるようになることで
- 競合ページのキーワード/コンテンツに力を入れているのかがわかる。
- 文字数をカウントすることでどれ程のページボリュームなのかが一目でわかる。
- 自身の作業コストを大幅に削減できる
といったメリットを享受できます。
また、下記で紹介するスクリプトを使用することで、次のデータを抽出できます。
- サイトのURL
- メタタイトル/ディスクリプション
- cannonicalタグ
- h1〜h4までの見出しタグ
- strongタグの文字(キーワード)
- 記事内の文字数
- 記事内の画像の枚数
実際にスクリプトを動かすと、次のようなExcelファイルが出力されます。
使用するライブラリ
今ページのスクリプトで使用されているライブラリの一覧です。
requests / Beautiful soup
requestsは主にPythonからHTTPリクエストを送信し、結果を取得するライブラリです。
またBeautiful soupはhtmlをパース(解析)し、必要な情報をプログラム内で扱いやすくするためのライブラリです。
openpyxl
openpyxlはPythonからExcelファイルを作成・操作するためのライブラリです。
スクリプトの紹介
こちらが紹介するスクリプトです。
import requests
from bs4 import BeautifulSoup
import openpyxl
def h_join(ary):
join_str = ""
for tmp in ary:
join_str = join_str + tmp.get_text().strip() + '\n'
return join_str
#ワークブックとシートの作成
workbook = openpyxl.Workbook()
sheet = workbook.active
#ヘッダを書く
sheet['A1'].value = 'サイトURL'
sheet['B1'].value = 'タイトル'
sheet['C1'].value = 'ディスクリプション'
sheet['D1'].value = 'canonical'
sheet['E1'].value = 'h1'
sheet['F1'].value = 'h2'
sheet['G1'].value = 'h3'
sheet['H1'].value = 'h4'
sheet['I1'].value = 'strong'
sheet['J1'].value = '記事文字数'
sheet['K1'].value = '画像枚数'
# スクレイピングするサイトのURLをリスト形式で記述
urls = [
'https://tech-camp.in/note/technology/69/',
'https://www.creativevillage.ne.jp/72956',
'https://note.com/takkun_desu/n/n7297b6ea03ff',
'https://www.sejuku.net/blog/81',
'https://web-camp.io/magazine/archives/24594',
]
# urls変数の分ループ処理
# enumerate関数のstart引数は変数iのスタート値
# iはシートの行数を表す変数です
for i, url in enumerate(urls, start=2):
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser') #Beautiful Soupにhtmlを渡してパース(解析)する
#サイトURL
sheet[f"A{i}"].value = url
#タイトルの取得・書き出し
title = soup.find('title')
sheet[f"B{i}"].value = title.get_text().strip()
#ディスクリプションの取得・書き出し
description = soup.find('meta', {'name': 'description'})
if description is not None:
sheet[f"C{i}"].value = description['content']
#canonicalの取得・書き出し
canonical = soup.find('link', {'rel': 'canonical'})
if canonical is not None:
sheet[f"D{i}"].value = canonical['href']
# articleタグの要素を取得
main_content = soup.find('article')
# h1〜h4の見出し一覧を取得・書き出し
h1_ary = soup.find_all('h1')
sheet[f"E{i}"].value = h_join(h1_ary)
h2_ary = main_content.find_all('h2')
sheet[f"F{i}"].value = h_join(h2_ary)
h3_ary = main_content.find_all('h3')
sheet[f"G{i}"].value = h_join(h3_ary)
h4_ary = main_content.find_all('h4')
sheet[f"H{i}"].value = h_join(h4_ary)
# strongタグの文字を取得・書き出し
strong_ary = main_content.find_all('strong')
sheet[f"I{i}"].value = h_join(strong_ary)
# 記事内の文字数を取得・書き出し(段落の文字数をカウント)
main_content_p_ary = main_content.find_all('p')
char_count = 0
for p in main_content_p_ary:
char_count = char_count + len(p.get_text().strip())
sheet[f"J{i}"].value = char_count
# 画像の枚数を取得・書き出し
img_ary = main_content.find_all('img')
img_count = len(img_ary)
sheet[f"K{i}"].value = img_count
# 作成したExcelファイルを保存
workbook.save("result.xlsx")
ここからはソースコードの主要な箇所を解説していきます。
12行目のopenpyxl.Workbook()でExcelのワークブックオブジェクトを作成し、workbook変数に格納しています。
ワークブックとは.xlsxで始まるExcelファイルという認識で問題ありません。なのでここではworkbook変数にExcelファイルを作ったと言えます。
13行目は作成したworkbookに新たにシートを追加し、sheet変数に作成したシートを格納しています。
これ以降はsheetに対してスクレイピングした結果を記述していきます。
15〜25行目はシートの1行目にヘッダ項目を書き出しています。
sheet[‘セル番号’].valueに対して文字列を代入するだけで書き出せるので非常に直感的で良いです。
28行目のリストはスクレイピングするサイトの一覧です。ここでは「プログラミング 独学」検索した上位5件のサイトURLを記載しています。
39行目〜は各サイトに対してスクレイピングとシートへの書き出しを行っています。
40行目のrequests.get()にサイトのURLを渡すことで、そのサイトのhtmlを取得できます。
それをBeautifulSoup()に通すことで、レスポンスされてきたhtmlをプログラム内で利用しやすくしています。
46行目〜53行目の随所でsoup.find()していますが、これは引数に渡した文字列のタグの情報をhtmlから引っ張ってきています。
例えばsoup.find(‘title’)はhtml内の<title>情報を取得しています。さらにget_text()することで<title>のテキストを抽出しています。
49行目も同じくsoup.find()を使っていますが、2つ目の引数に辞書を渡しています。こうすることで「metaタグの中でname属性がdescription」のタグ情報を取得できます。
descriptionは<meta>のcontent属性に記述するので、51行目ではget_text()ではなdescription['content']としてcontent属性の値を取得しています。
61行目〜68行目は見出しタグを取得してシートに書き出しています。
見出しタグは1つの記事に複数配置される場合が多いので、find_all()を使って複数タグ情報をリスト形式で取得しています。
同じ容量で71行目ではキーワード(strongタグ)情報を取得しています。
75行目〜79行目はpタグを全て取得し、文字数をカウントして書き出しています。
82行目〜84行目はimgタグを全て取得し、画像数をカウントして書き出しています。
全てのサイトの情報を書き出し終わったら、最後にworkbook.save()にExcelファイル名を渡して保存しています。
このスクリプトの活用方法
あるテーマに沿った検索上位のSEO情報を一括でスクレイピングできるので、その内容から自身がどういった記事を執筆するのが良いかを分析・活用できます。
実際に競合の傾向を分析してみる
例えば今回出力したExcelを見るだけでも、このキーワードで上位を取っている記事の傾向を見ることが出来ます。
・文字数は最低10,000以上、2位より上は20,000字程度の大ボリューム記事で、見出し1~4までコンテンツ設計がされている
・1位と2位以下の記事では文字数以上に挿入画像数に差がある
・canonicalリンクは全記事とも指定
・記事タイトルの前半にターゲットキーワードである『プログラミング 独学』が入る
・4位以上は全て見出し1を指定している
・多くの見出し2にも『プログラミング 独学』を入れている
・各見出しから判断すると、主なコンテンツとしては『おすすめサイト(アプリ、ゲーム)』『おすすめ教本』といった学習ツールに加え、心理的な『挫折(壁)』、学習後のキャリアである『稼ぎ方』『転職』などが共通している。
などが分かります。勿論これらを踏襲すれば必ずしも上位を取れる訳ではありませんし、実際にはドメインパワーや外部リンクなどの複合的な理由も大きいでしょう。
ただ今回のスクリプトを使えば、狙いとしている上位ページの傾向や難易度の把握、自身で作成する際のページ構成の参考など、大まかですが様々なことが数分で把握できます。同じことは様々なツールでも手動でも可能ですが、効率性を考えると圧倒的に楽です。
検索条件やスクレイピングしたい件数はurlsリストを変更することで変更・調整できますので、是非ご活用ください。