Google検索結果からH2タグを抽出する方法

Python学習【365日チャレンジ!】352日目のマスターU(@Udemy11)です。

国会議員って、あんまり危機感ないのか、それともただのバカなのか、国民の代表という感覚がない人が多いようですね。

夜遅くまで飲みにいったり、国会中に居眠りしたり、これだけメディアに攻撃される世の中になっているのに、国民に見られているとは思っていないようです。

そんな国会議員に何かを期待している人っているんでしょうか?

アンガーマネジメントの考え方の一つに、自分には変えることができなくて、あまり影響のない事柄に関しては、無視するか関わらないようにするというのがありますが、国会議員の行動は変えることはできないし、国会の居眠りも自分自身には関係ないので、関わらなければ怒りも起きませんので、極力、メディアを見ないというのも、怒りを抑える一つの方法には違いありません。

一定期間、インターネットを含めたメディア絶ちをしてみるのもストレスがたまらなくていいかもしれませんね。

それでは今日も、Python学習を始めましょう。

昨日の復習

昨日は、【GitHub Learning Lab】の【Introduction to GitHub】を学習しました。

最初はわけがわからないまま作業を進めましたが、課題をこなすうちになんとなく何をやっているのかわかるようになりました。

といってもGitとGitHubについての必要最小限の知識が必要ですので、本やWebでGitとGitHubのことを学習しておきましょう。

昨日の学習内容については、こちらの記事をごらんください。

今日は、GitHubから一旦離れて、先日作成していたscrape_t_u.pyのコードをカスタマイズして、Google検索結果ページの1ページめから、URL、タイトル、H2タグを抽出するコードを書いていきます。

完成コード

とりあえず、最初に完成したコードを記述しておきます。

import re
import urllib.parse

from bs4 import BeautifulSoup
import requests

search_query = input('キーワード:')

r = requests.get('https://www.google.co.jp/search?hl=jp&gl=JP&num=10&q=' + search_query)
html_soup = BeautifulSoup(r.content, 'html.parser')

url_results = []
for t in html_soup.select('.kCrYT > a'):
    u_result = re.sub(r'/url\?q=|&sa.*', '', t.get('href'))
    url_results.append(urllib.parse.unquote(u_result))

title_results = []
list_h2 = []
for i in url_results:
    search = requests.get(i)
    search_soup = BeautifulSoup(search.content, 'html.parser')

    try:
        titles = search_soup.find('title')
        title_results.append(titles.text)
    except:
        title_results.append('取得できませんでした。')

    try:
        h2 = search_soup.find_all('h2')
        base_h2 = []
        for a in h2:
            base_h2.append(a.text)
        list_h2.append(base_h2)
    except:
        list_h2.append('取得できませんでした。')

list_datas = []
for x, y, z in zip(url_results, title_results, list_h2):
    z = [item.replace('\n', '') for item in z]
    list_data = {'URL': x, 'TITLE': y, 'H2': z}
    list_datas.append(list_data)

print(list_datas)

h2を抜き出せばいいだけなので、最初は単純にURLやTITLEと同じようなコードで、find()h2をしてすればいいだけだと思っていました。

で、よく考えてみると、h2タグは、1つだけしかないtitleと違って、いくつも存在するので、コードを変える必要があることに気づきました。

そこからいろいろと考えて、最終的にこのコードになりましたが、あまりきれいなコードとは言えませんね。

パーツに分けてコードを見ていこうと思います。

Google検索結果からURLを取得する

これまでと同じように、Google検索結果からURLを取得するところまでは同じで、検索するキーワードをinput()で取得するようにしています。

import re
import urllib.parse

from bs4 import BeautifulSoup
import requests

search_query = input('キーワード:')

r = requests.get('https://www.google.co.jp/search?hl=jp&gl=JP&num=10&q=' + search_query)
html_soup = BeautifulSoup(r.content, 'html.parser')

url_results = []
for t in html_soup.select('.kCrYT > a'):
    u_result = re.sub(r'/url\?q=|&sa.*', '', t.get('href'))
    url_results.append(urllib.parse.unquote(u_result))

タイトルとH3タグを取得する

タイトルとH3タグを取得するコードは、それぞれにtry-exceptを使っています。

title_results = []
list_h2 = []
for i in url_results:
    search = requests.get(i)
    search_soup = BeautifulSoup(search.content, 'html.parser')

    try:
        titles = search_soup.find('title')
        title_results.append(titles.text)
    except:
        title_results.append('取得できませんでした。')

    try:
        h2 = search_soup.find_all('h2')
        base_h2 = []
        for a in h2:
            base_h2.append(a.text)
        list_h2.append(base_h2)
    except:
        list_h2.append('取得できませんでした。')

最初にタイトルを入れる空のリストtitle_resultsに加え、空のリストlist_h2を定義しています。

19行目から、先に取得したURLを元にデータを抽出するforループのコードになっていますが、20行目と21行目でURLからBeautifulSoupで中身を解析できるデータに変換しています。

23行目から27行目でタイトルを抜き出して、空のリストtitle_resultsに代入します。

29行目から36行目でh2を抽出しますが、find_allですべてのh2タグを抽出してリストになっているので、そのままではテキストを抽出できません。

一つ一つテキストを抽出するには、新しいリストbase_h2を作って抽出したh2のテキストを代入していき、そのリストをlist_h2に追加する必要がありました。

データの出力

最後は、抽出したそれぞれのリストを合わせて出力します。

list_datas = []
for x, y, z in zip(url_results, title_results, list_h2):
    z = [item.replace('\n', '') for item in z]
    list_data = {'URL': x, 'TITLE': y, 'H2': z}
    list_datas.append(list_data)

print(list_datas)

空のリストlist_datasを作成し、zip()を使って、辞書型データにしたものをリストlist_datasに入れていきます。

ポイントは、URLとTITLEとH2のリストのインデックス数が同じというところです。

titleh2も、先に抽出したURLにアクセスして取得しているデータなので、リストと文字列の違いはあるものの、インデックス数は、抽出したURLと同じ数になっています。

最後の44行目でlist_datasを表示しています。

まとめ

ほんとに簡単にできるなーと安易に考えていたのですが、複数のリストが入ったリストにする時点でかなり時間を取られたうえ、抽出した3つのリストを一つにまとめる時点でもかなり時間がかかってしまいました。

1つのURLに1つのタイトルに対してH2はいくつもあるので、このあたりの処理の仕方がポイントでした。

経験値を積み上げながら、引き出しを増やしていこうと思います。

それでは、明日もGood Python!