国境大好き芸人

旅行と語学ととプログラミング。陸路で国境を越えるのが生きがいです。

PythonでGoogleの検索結果をスクレイピングする方法

f:id:stinkydofu:20180825174020p:plain

Googleの検索結果からタイトル、URL、ディスクリプションを取り出す

Pythonを使って、Googleの検索結果を取り出したいと思います。

Googleの検索結果をスクレイピングすることで、例えば

・自分のサイトの表示順位を定点で観測する
・上位サイトのキーワードを抽出して分析する

なんてことが可能になります。
SEO目的で使えそうですね。

この記事では、用途はさておき、Pythonを用いてスクレイピングする方法を解説します。

プログラミング初心者にもわかりやすいように、丁寧に説明していきたいと思います!

※とはいえ、自分もPython(を含むプログラミング)初心者なので、
間違っている表現があればご指摘頂ければ助かります。

なお、Jupyter Notebookを使う前提で書いています。

requests、BeautifulSoup、pandasのimport

モジュールをインポートします。

import requests as web
import bs4
import pandas as pd

Googleで検索したい語句を指定

web.getでGETリクエストをします。
(あまり理解できていないのですが、web.get で指定したURLにアクセスするイメージですかね。)

num=100 はGoogleの検索結果を100件まで表示することを意味します。
100件も必要なければ、num=50 など、件数を指定すれば良いと思います。

list_keywd = ['上海', 'ホテル']
gotten = web.get('https://www.google.co.jp/search?num=100&q=' + ' '.join(list_keywd))

HTMLをパース、取り出したいタグを指定する

HTMLをパースします。

# HTMLをパース
soup = bs4.BeautifulSoup(gotten.text, "html.parser")

ここで、soupを表示してみると、Google検索結果のHTMLが格納されていることがわかります。

f:id:stinkydofu:20180825185131p:plain

さて、我々が欲しいのは検索結果のタイトル、URL、ディスクリプションですので、
それぞれがHTMLのどのタグで囲まれているのかを確認して、以下のように取得します。

タイトルとURLは

<h3 class="r">

というタグの中に入っているので、そのように指定します。
ディスクリプションは

<span class="st">

というタグの中に入っているので、class名を指定します。

# 検索結果のタイトルを取得
title = soup.find_all('h3', class_ = 'r')

# 検索結果のURLを取得
url = soup.find_all('h3', class_ = 'r')

# 検索結果のディスクリプションを取得
dscr = soup.find_all(class_ = 'st')

f:id:stinkydofu:20180825185644p:plain

すると、titleというリストの中に、検索結果の上から順に

<h3 class="r">

の中身が全て入っていることがわかります。
もちろんこのままだと使えないので、次に定義する関数で、HTMLタグなどの不要な文字列を取り除く処理をします。

不要な文字列を取り除く関数を定義する

まずは、試しに title[0] を表示しましょう。title リストの中に入っている0番目の要素のみを表示します。
すると、こうなっているはず。

f:id:stinkydofu:20180825190829p:plain

取り出したいのは日本語のタイトルだけなので、不要な文字列を取り除きましょう。
ここで使うのは、find、replaceなども文字列操作メソッドです。

少しトリッキーな使い方をしているかもしれませんが・・・

def titleGetter(title_element):
    
    # str 形式にする
    title_text = str(title_element)
    
    # 最初の '>' を見つけて、それ以降をスライスする
    title_text = title_text[title_text.find('>') + 1: title_text.find('>') + 1000]
    
    # 2番目の '>' を見つけて、それ以降をスライスする
    title_text = title_text[title_text.find('>') + 1: title_text.find('>') + 1000]
    
    # 不要なタグを置換する
    title_text = title_text.replace('<b>', '').replace('</b>', '').replace('</a>', '').replace('</h3>', '')
    
    return title_text

URLも、同じような関数を定義して、不要な文字列を処理します。

def urlGetter(url_element):
    
    # str 形式にする
    url_str = str(url_element)
    
    # 最初の 'href' を見つけて、それ以降をスライスする
    url_str = url_str[url_str.find('<a href="/url?q=') + 16: url_str.find('<a href="/url?q=') + 1000]
    
    # 最初の '>' を見つけて、それ以前をスライスする
    url_str = url_str[: url_str.find('>') ]
    
    # 不要な文字を置換する
    url_str = url_str.replace('"', '')
    
    return url_str

ディスクリプションも同様。

def dscrGetter(dscr_element):
    
    # str 形式にする
    dscr_str = str(dscr_element)
    
    # 最初の '>' を見つけて、それ以降をスライスする
    dscr_str = dscr_str[dscr_str.find('>') + 1: dscr_str.find('>') + 1000]
    
    # 不要なタグを置換する
    dscr_str = dscr_str.replace('<br/>', '').replace('\n', '').replace('</span>', '').replace('</b>', '').replace('<b>', '')
    
    return dscr_str

for文でリスト内のすべての要素に対し文字列処理をほどこす

先ほど定義した関数

  • titleGetter
  • urlGetter
  • dscrGetter

をHTMLから取得したリスト内のすべての要素に作用させます。

title に格納されている要素に対し、titleGetter を作用させて、不要な文字列を取り除く。

title_list = []
for i in title:
    j = titleGetter(i)
    title_list.append(j)

url に格納されている要素に対し、urlGetter を作用させて、不要な文字列を取り除く。

url_list = []
for i in url:
    j = urlGetter(i)
    url_list.append(j)

dscr に格納されている要素に対し、dscrGetter を作用させて、不要な文字列を取り除く。

dscr_list = []
for i in dscr:
    j = dscrGetter(i)
    dscr_list.append(j)

リストをDataFrameに変換して、見やすくする

pd.DataFrame を用いて、リストをDataFrame に直します。
さらに、renameを使って、列名を定義しましょう。

df = pd.concat([pd.DataFrame(title_list).rename(columns = {0: 'タイトル'}),\
                pd.DataFrame(url_list).rename(columns = {0: 'URL'}),\
                pd.DataFrame(dscr_list).rename(columns = {0: 'ディスクリプション'})], axis = 1)

するとこんなふうに、タイトル、URL、ディスクリプションを並べた、いい感じのテーブルが作れます!

f:id:stinkydofu:20180825191930p:plain

参考記事:
PythonのrequestsとBeautifulSoupでGoogle検索結果から、タイトルとURLと説明文だけを抜き取る - アラカン"BOKU"のITな日常