"BOKU"のITな日常

還暦越えの文系システムエンジニアの”BOKU”は新しいことが大好きです。

PythonのrequestsとBeautifulSoupでGoogle検索結果から、タイトルとURLと説明文だけを抜き取る

今回は、Google検索結果からタイトル・説明文とURLをぬきとって、CSVに整形して出力するところまでやります。 

 

手作業ではなく、pythonで一括処理します。 

 

pythonのrequestsとbeautifulsoupというモジュールを使います。

なんとなく、かなり簡単にかけそうではありますので。

Requests: 人間のためのHTTP — requests-docs-ja 1.0.4 documentation

kondou.com - Beautiful Soup 4.2.0 Doc. 日本語訳 (2013-11-19最終更新)

 

問題はセレクタに与える条件です。 

Google検索結果のページを「ソースを表示」してみるとわかります。 

超複雑なHTMLになっていますので。

f:id:arakan_no_boku:20180117002311j:plain

これを地道に読むのは、ちょっと嫌かな・・。 

こういう時は、Google Chromeデベロッパーツールを使うに限ります。 

検索結果画面のリンクのところにマウスカーソルを置いて右クリックメニューから「検証」を選びます。

f:id:arakan_no_boku:20180116000149j:plain

 

そうすると、デベロッパーツールが立ち上がり、該当箇所のURLが表示されて、対応する画面を反転して示してくれます。

f:id:arakan_no_boku:20180116000409j:plain

こうやって探すと、比較的見つけやすいです。 

どうやら、タイトルとURLは、「class='r' のDIVタグ以下の aタグ」、説明文は、「class='s' 以下にある span タグ」で取得できそうです。

 

pythonで検索実行しタイトル・URL・説明文を抜き取る

 

機械学習にかける準備として、元にするCSVデータファイルを作成するところまで、とりあえずやります。 

まずは、ソース全文です。

 

import requests as web
import bs4
import csv

# キーワードを使って検索する
list_keywd = ['機械学習','統計']
resp = web.get('https://www.google.co.jp/search?num=100&q=' + ' '.join(list_keywd))
resp.raise_for_status()

# 取得したHTMLをパースする
soup = bs4.BeautifulSoup(resp.text, "html.parser")
# 検索結果のタイトルとリンクを取得
link_elem01 = soup.select('.r > a')
# 検索結果の説明部分を取得
link_elem02 = soup.select('.s > .st')

if(len(link_elem02) <= len(link_elem01)):
    leng = len(link_elem02)
else:
    leng = len(link_elem01)    

# CSVファイルを書き込み用にオープンして整形して書き出す
with open('g_output.csv','w',newline='',encoding='utf8') as outcsv:
    csvwriter = csv.writer(outcsv)
    csvwriter.writerow(['タイトル・説明','URL'])
    for i in range(leng):
        # リンクのみを取得し、余分な部分を削除する
        url_text = link_elem01[i].get('href').replace('/url?q=','')
        # タイトルのテキスト部分のみ取得
        title_text = link_elem01[i].get_text()
        # 説明のテキスト部分のみを取得/余分な改行コードは削除する
        t01 = link_elem02[i].get_text()
        t02 = t01.replace('\n','')
        disc_text = t02.replace('\r','')
        csvwriter.writerow([title_text + disc_text,url_text])
    outcsv.close()

 

ひとつ、おことわり。 

自分は、IDLEでソースを表示させた状態で「F5」キーで実行する方法が好きなので、条件はソースに直書きしてます。 

でも、コマンドラインから実行するなら、そこは入力させるか、パラメータで渡すようにしたほうが良いと思います。 

あと、ポイントだけ補足説明します。  

num=100の指定で検索結果を100件までリストします。 

resp.textでHTML全体が取得できるので、それをBeautifulSoupでパースします。 

そのうえで、class='r'の下のaタグ、class='s'の下のspanタグの内容を取得しています。

# 取得したHTMLをパースする
soup = bs4.BeautifulSoup(resp.text, "html.parser")
# 検索結果のタイトルとリンクを取得
link_elem01 = soup.select('.r > a')
# 検索結果の説明部分を取得
link_elem02 = soup.select('.s > .st')

 

後は、aタグのリンクの部分(href=・・)を、get('href')で取り出して、そのままだと余分な「/url?q=」が頭にくっついているので、消してます。

link_elem01[i].get('href').replace('/url?q=','') 

タイトルと説明文は、get_text()で取得します。 

そうしないと、<em>とか<strong>とかの修飾タグが取得できてしまって邪魔なので、純粋なテキスト部分だけを抜き取るわけです。

link_elem01[i].get_text()

link_elem02[i].get_text()

 あと、説明文には適当な位置に改行がはいっていて邪魔なので、それを消します。

t02 = t01.replace('\n','')
disc_text = t02.replace('\r','')

そうして、タイトルと説明文を連結してCSVに書き出しているだけです。 

出力したCSVはこんな感じです。

f:id:arakan_no_boku:20180117001545j:plain

一応、イケてるみたいです。 

 

ちょっとだけ補足です

 

ご存じの方は多いと思いますが、Google検索は同じキーワードでも、検索結果が環境によって最適化されています。

なので、通常のブラウザで検索した時と、pythonのプログラムから検索した時とでは、当然のように同じ検索条件でも抽出されるものも並び順も違います。 

これを意識せずにやると、結果の確認のところでハマります。

自分も、ハマりました。 

なお、上記は、HTMLの書き方に依存しているので、なんかの拍子にGoogleさんが仕様を変えて問題が発生する可能性は常にあります。

そんときはご容赦くださいね。 

が、まあ、今日のところはこんなもんです。