Google検索結果ページをスクレイピング【Python x BeautifulSoup】
この記事では、PythonでGoogle検索結果をスクレイピングして、特定のサイトの検索キーワードに対する検索順位の抽出を行います。また、簡単にスクレイピングを可能とするBeautifulSoupの使い方を説明します。
▼ Pythonを使うのがはじめてな方は、こちらの書籍で基本的な使い方を学んでおくと良いでしょう。
▼ こちらの本は、Beautiful Soup4のクローリングをはじめ、pandasやmatplot、OpenPyXLなどを使ってデータ解析までを解説したスクレイピングの書籍となります。分かりやすくておすすめです!
スクレイピングとは
スクレイピングとは、英語のscrapingで「こすること」「削ること」の意味があります。Webでスクレイピングといった場合は、Webサイトの状態をかき集め(クローリング)、その中から必要なデータを抽出(スクレイピング)することになります。
Pythonでは、Webスクレイピングを簡単に行えるようにしてくれるツールのひとつに、BeautifulSoupというライブラリがあります。BeautifulSoupを使ってWebスクレイピングを行うには、次の流れで作業していきます。
- urllibでスクレイピングしたいサイトのHTMLをダウンロードする
- BeautifulsoupでHTMLをパースしてオブジェクト化する
- Beautifulsoupで目的のデータを抽出する
それでは、さっそくBeautifulSoupをインストールし、BeautifulSoupの簡単な使い方を説明していきます。
BeautifulSoupのインストール
まずは、BeautifulSoupをpipでインストールします。この記事では、Python3を使用しますのでpip3でインストールしました。BeautifulSoup最新版はbeautifulsoup4ですので、次のようにしてインストールします。
$ pip3 install beautifulsoup4
サイトタイトルを抽出してみよう
まずは大雑把なイメージをつかむために、適当なサイトをスクレイピングして、titleタグの文字を抽出してみましょう。
import urllib.request
from bs4 import BeautifulSoup
url = "https://101010.fun/posts/world-ios-android-share-2021.html"
req = urllib.request.Request(url)
with urllib.request.urlopen(req) as res:
html = res.read()
soup = BeautifulSoup(html, 'html.parser')
title = soup.find('title').get_text()
print(title)
BeautifulSoupを使うことで、このように驚くほど簡単にtitleタグの文字を抽出できました。それでは、BeautifulSoupの使い方をもう少し詳しくみていきましょう。
BeautifulSoupの使い方
BeautifulSoupの使い方を説明します。
HTMLをオブジェクト化(パースパースツリー)
urlib などでHTMLファイルをダウンロードしたら、BeautifulSoupでパースパースツリーを作成しオブジェクト化します。soup = BeautifulSoup(html, 'html.parser')
この soup オブジェクトを使って必要なタグを検索、抽出していきます。
特定のタグを見つける
たとえば、パースパースツリーの中からaタグを検索したい場合は、soup.find_all('a')のようにします。もし、aタグが見つかれば、返り値としてその結果が配列で返されます。
for a_tag in soup.find_all('a'):
h2 = a_tag.select("h2")
if len(h2) > 0:
print(h2.get_text())
この例は、aタグの子要素のh2タグのテキストにアクセスしてます。
属性の値を取得
a タグの href 属性の値を取得したい場合は次のようにします。for a in soup.find_all('a'):
href = a.get('href')
CSSクラスへアクセス
soup.find_all("a", class_="hoge")
親要素へアクセス
parent で親要素へ parents で複数の親要素へアクセスできます。parent = h2.parent
print(parent.get_text())
兄弟要素へアクセス
next_sibling や previous_sibling で兄弟要素の前後へアクセスできます。next_sibling = h2.next_sibling
print(next_sibling.get_text())
previous_sibling = h2.previous_sibling
print(previous_sibling.get_text())
パースパースツリーを変更する
BeautifulSoupでは、パースパースツリーの変更もできます。
soup = BeautifulSoup("<a>Hoge</a>")
soup.a.append("Fuga")
aタグのテキストはHogeFugaとなります。
▼ BeautifulSoupについてより詳しく知りたい方はこちら。 kondou.com - Beautiful Soup 4.2.0 Doc. 日本語訳 (2013-11-19最終更新)
▼ また、pandasやOpenPyXL、twintなどを使ったスクレイピング関連の記事も書いてます。
Google検索結果をスクレイピング
それでは、BeautifulSoupを使ってGoogle検索結果をスクレイピングしてみましょう。次の手順でプログラムを組んで、検索キーワードに対する指定サイトの検索順位を抽出してみます。
- urllibで検索結果のHTMLをダウンロード
- HTMLをBeautifulSoupでパースツリー化
- 特定のURLが検索結果に含まれているかチェックしり
- 検索結果に見つからなければ最大5ページまで手順を繰り返す
以上の仕様で作ってみたプログラムがこちらとなります。
Pythonプログラム
# Created by Toshihiko Arai.
# https://101010.fun/programming/python-beautifulsoup-googlerank.html
import urllib.request
from urllib.parse import quote
from bs4 import BeautifulSoup
import time
keyword = 'ios android シェア'
target = 'https://101010.fun/posts/world-ios-android-share-part1.html'
user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36"
def get_search_html(keyword, page):
start = "&start=" + str(page * 10) # 次ページstart=10
url = 'https://www.google.com/search?q=' + quote(keyword) + start
headers = {'User-Agent': user_agent}
req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req) as res:
body = res.read()
return body
def get_page_rank(soup, page):
res_rank = 1
for a_tag in soup.find_all('a'):
h3_tag = a_tag.select("h3")
if len(h3_tag) > 0:
if a_tag.get('href').startswith(target) == True:
# print(h3_tag[0].get_text())
# print(a_tag.get('href'))
return res_rank + page * 10
res_rank += 1
return -1
rank = -1
max_page = 5
for page in range(max_page):
html = get_search_html(keyword, page)
soup = BeautifulSoup(html, 'html.parser')
title_text = soup.find('title').get_text()
print(title_text)
rank = get_page_rank(soup, page)
page += 1
if rank != -1:
break
time.sleep(3) # アクセス制限対策
if rank != -1:
print("順位: {}位".format(rank))
else:
print("見つかりませんでした")
もし、検索結果に対象ページが含まれていれば、次のようなに検索順位が標準出力されるでしょう。
ios android シェア - Google 検索
順位: 2位
プログラム中の検索キーワードや対象ページのURLを変更して、いろいろ試してみてください。このプログラムをさらに改造すれば、Rank TrackerのうようなSEOツールが作れるでしょう。そのためには、検索キーワードを別ファイルで管理したり、実行結果をエクセルへ書き出したりすれば良いです。ぜひご活用ください。