数日間苦戦しておりました。
Web系をいじるのは慣れません。
ブログの検索順位を取得するツールをPythonで自作してみようとチャレンジしています。
前回は、Pythonの導入からGoogle検索するまでをやってみました。
今回はこの続きで、検索して得られたよくわからない文字列から、必要な部分のみ取り出すところを作っていきます。
しかし、これがなかなか上手くいきませんでした・・・
Web屋さんなら当たり前の知識がないので、問題の解決に2日もかかってしまいました・・・

時間かかり過ぎでしょ
ね。いい経験になりましたよ(汗)
今回の重要な点をまとめておくと、
- BeautifuSoupを使ってHTMLデータを解析
- タグ<a>で検索にヒットしたタイトルとURLを取り出す
- リクエストの際にヘッダーにブラウザ情報を入れないと正常なHTMLが返ってこない
これだけ読んでも何言ってるかわからないですね。
下で説明していきます。
Google検索した結果からタイトルとURLを取り出す
前回は、Google検索を実行した結果の文字列を取得しました。
取得した文字列から、欲しい部分(ヒットした記事のタイトルとURL)を抜き出す部分を作っていきます。
やり方は、調べたらだいたいみんな同じ構文を使っていたので、それを使用してみます。
BeautifulSoupライブラリのインストール
Google検索をし、ヒットした記事タイトルとURLを取得するには、
- Requests
- BeautifulSoup
のライブラリが必要です。
「Requests」は前回インストール済みなので、「BeautifulSoup」の方をインストールします。
「BeautifulSoup」はHTMLの構文を解析するために使用します。

ソースコード
検索結果からヒットした記事タイトルとURLを取得するソースコードです。
やり方は、いろいろなページで紹介されているやり方と同じです。
キーワード「理系夫婦」で10件検索してみます。
ソースコード:search_getTitleURL.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import requests as web import bs4 #検索キーワード keyword = '理系夫婦' #ひとまず上位10件まで検索結果を取得 url = 'https://www.google.co.jp/search?hl=ja&num=10&q=' + keyword #接続 response = web.get(url) #HTTPステータスコードをチェック(200以外は例外処理) response.raise_for_status() #取得したHTMLをパース soup = bs4.BeautifulSoup(response.text, 'html.parser') #検索結果のタイトルとリンクを取得 ret_link = soup.select('.r > a') title_list = [] url_list = [] for i in range(len(ret_link)): # タイトルのテキスト部分を取得 title_txt = ret_link[i].get_text() # リンクのみを取得し、余計な部分を削除する url_link = ret_link[i].get('href').replace('/url?q=','') title_list.append(title_txt) url_list.append(url_link) #検索結果を表示 for i in range(len(title_list)): print(title_list[i]) print(url_list[i]) print('') |
検索URL
url = ‘https://www.google.co.jp/search?hl=ja&num=10&q=’ + keyword
今回は上位10件のみ検索したかったので、「num=10」としましたが、100件検索したい場合はここの数字を「num=100」に変えればOK
HTTPステータスコードのチェック
きちんとページにアクセスできたかを知るため、HTTPステータスコードをチェックします。
参考のページ:PythonでWebページを取得できたかどうかのエラーチェックと安全な中止の仕方
response.raise_for_status()
こちらのコードでHTTPステータスコードをチェックし、正常(200番)以外の場合は例外処理をしてくれます。
この1行で済んでしまうなんて、便利!
BeautifulSoupでHTML解析
ここの部分のコードです。
1 2 3 4 5 |
#取得したHTMLをパース soup = bs4.BeautifulSoup(response.text, 'html.parser') #検索結果のタイトルとリンクを取得 ret_link = soup.select('.r > a') |
「BeautifulSoup」でHTMLタグ情報を解析しインスタンスを作成します。
Google検索結果ページのHTMLを「右クリック→ページのソースを表示」で見てみると、ヒットした記事タイトルとURLは

となっているので、class=”r”の下のaタグの情報を「select」で取得します。
このあたりはこのページを参考にしました。:PythonのrequestsとBeautifulSoupでGoogle検索結果から、タイトルとURLと説明文だけを抜き取る
あとは、抜き出したタイトルとURLをリストに入れて表示しています。
実行結果
では、上記のコードを実行してみましょう。
ほとんど、参考ページと同じコードなので、うまくいくはず!

・・・・・・あれ?
なにも表示されません。なぜ??
検索にヒットした記事タイトルとURLが取り出せない・・・
なぜGoogle検索結果の記事タイトルとURLが取り出せないのか・・・?
原因追及の旅が始まりました。
他のHPなら取り出せる
まず疑ったのはselectのタグ指定がおかしいのかということ。
試しにh3タグを指定して
1 |
ret_link = soup.select('h3') |
として実行してみましたが、やはり何も表示されない・・・。
しかし、Google検索以外のページだと、h3タグが表示されていることが発覚!
例えば、Wikipediaのトップページのh3タグを抜き出してみると、

と、きちんとh3タグを取得できています。
じゃあ、なんでGoogle検索結果はうまく取得できないの??
Google検索結果のHTMLがおかしい
Google検索結果のタグが取得できないのは何故なのか?
ここで以下のソースコード
1 2 |
response = web.get(url) print(response.text) |
で、検索結果を取得したHTMLを全て表示させてみました。
すると、こんなHTMLだったのです!

本来(右クリック→ページのソースを表示)のHTMLなら

となっています。
そう、HTMLタグのclass名が違っていたのです!
だから記事タイトルとURLを取得できていないのか。
原因はわかりました。
ちなみに、この原因にたどり着くまでに1日かかりました。
そして原因の解決策を見つけるのに、さらに1日費やしました。
解決策
なんでHTMLタグのclassが変わってしまうのか。
その理由と解決策を調べても、なかなか見つけられませんでした。
文字化け? ⇒ 文字コードをいじってみる ⇒ 違った
など、苦戦。
しかし、やっと、やっと、解決策が見つかったのです(泣)
ブラウザを模擬する
Google検索結果のHTMLのclass名が変になってしまう件の解決方法は、以下のページが参考になりました。
ブラウザリクエストを偽造するためにPythonリクエストを使用する方法
Googleはブラウザからの閲覧なら正常なHTMLを返しているが、わけわからんプログラムからの閲覧にはHTMLの中身を変えているっぽいです。
なので、プログラム上でブラウザを模擬する必要があったのです。
そのブラウザの模擬方法は、参考ページにもあるように、headers情報の「User-Agent」を
ページをgetする際に 追加すればよいとのこと。
ソースコード
修正したソースコードは以下です。
ソースコード:search_getTitleURL2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
import requests as web import bs4 #検索キーワード keyword = '理系夫婦' #リクエストヘッダー headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36"} #ひとまず上位10件まで検索結果を取得 url = 'https://www.google.co.jp/search?hl=ja&num=10&q=' + keyword #接続 response = web.get(url, headers=headers) #HTTPステータスコードをチェック(200以外は例外処理) response.raise_for_status() #取得したHTMLをパース soup = bs4.BeautifulSoup(response.content, 'html.parser') #検索結果のタイトルとリンクを取得 ret_link = soup.select('.r > a') title_list = [] url_list = [] for i in range(len(ret_link)): # タイトルのテキスト部分を取得 title_txt = ret_link[i].get_text() # リンクのみを取得し、余計な部分を削除する url_link = ret_link[i].get('href').replace('/url?q=','') title_list.append(title_txt) url_list.append(url_link) #検索結果を表示 for i in range(len(title_list)): print(title_list[i]) print(url_list[i]) print('') |
8行目を追加したのと、14行目のgetの引数を追加しただけです。
実行結果
Requestsのヘッダーを追加して実行してみた結果は

うまくいきました!!!
これを表示するのに2日もかかるとは(涙)
ということで、今回分かった重要ポイントは
でした。
解決の糸口を見つけるための検索は難しいですね。
というのも、最初は「Python Google検索結果 HTML おかしい」とかで検索してましたが、まぁ欲しい情報はでてきません。
「Python requests HTML ブラウザと違う」で、やっと解決策が見つかりました。
ブログ検索順位取得ツールを作るための残りの作業は
- 自分のブログの検索順位を調べる
- 検索キーワードを一覧にしたファイルを読み込む
- 検索順位を調べた結果をCSVにまとめる
- グラフを作る
あたりがあります。
検索する重要部分はできるようになったので、あとはサクッとできてほしい。
んじゃ、また~
コメント