アラカン"BOKU"のITな日常

文系システムエンジニアの”BOKU”が勉強したこと、経験したこと、日々思うこと。

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

毎回、同じような条件文を入力してGoogle検索してます。

 

その都度、検索結果を見てリンクを開くかどうかを、タイトルと説明文を見て判断しているわけです。

 

自分では法則性はわからないのですが、「タイトルと説明文のテキスト」と「確認対象にするかしないかの判定」をペアで機械学習させてみたら、Google検索結果から、自分が好みそうなリンクだけを選び出す自分の分身みたいなもんが作れるんじゃないか?

 

そんなことを、ふと思いつきました。

 

こういうパーソナルな用途で、ロジックメーカーみたいな形で機械学習を使うってのも結構面白いかもしれないです。

 

試してみようかと思いますが、とはいえ、一発ではできないので、ぼちぼちやります。

 

まず、検索結果から必要な情報だけを抜き取れないと学習データも作れませんから、そこからですね。

 

今回は検索結果からタイトル・URL・説明文を抜き取るところまで

 

今回は、とりあえず、学習させるためのデータとして、検索結果からタイトル・説明文と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()

 

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

 

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 span')

 

後は、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

 

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

 

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

 

最初、突き合わせをしててハマりました。

 

一応、何パターンかの条件でやってみて大丈夫そうだったのですが、HTMLに依存しているので、なんかの拍子に問題が発生する可能性はあります。

 

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