Python Webスクレイピング

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

年が開けて2週間が経ちましたが、なかなか正月気分が抜けません。

コマーシャルで杏さんが唐揚げを食べながらおいしそうにビールを飲む映像を見ていると、無性にビールを飲みながら、山盛りのからあげを食べたくなり、もも肉を6枚買ってからあげを作りました。

市販されているから揚げ粉とゆずをまぶして自分で衣を付けた唐揚げを作ったのですが、圧倒的に市販されているから揚げ粉を使ったからあげのほうがジューシーでおいしかったので、これからは無理をせずに市販のから揚げ粉を使うことを決心しました。

当たり前ですが、さすがにいろいろと試された結果の商品だけはありますね。

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

昨日の復習

昨日は、Google検索の1ページめにヒットしたページのURLを抽出しました。

Google検索で「Google検索の結果からURLを抽出する」と調べてヒットするページで紹介されているGoogle仕様と、現在のGoogleの仕様が変更されているようで、必要なタグのクラスがややこしくて、抽出するのにかなり時間がかかってしまいました。

Googleの仕様が変わったのか、div要素のクラス名が変わってしまっていて、紹介されているコードでは抽出できませんでした。

HTMLコードを読み解くのにも時間がかかったし、余分なURLをどうするかを考えるのにもちょっと頭を使いました。

今日は、抽出したURLにアクセスして、省略されていない完全なタイトルを抽出します。

全体コード

今回のコードは、ヒットしたURLを抽出したときにアンカーの#が含まれている場合は、#%23に変換されて取得されるので、ヒットしたURLにアクセスできません。

他のエラーも起こっていたので、なにぶん穴だらけのコードだということをご理解ください。

こちらが全体のコードです。

import time

from bs4 import BeautifulSoup
import lxml.html as lx
import re
import requests

search_query = '鬼滅の刃 映画感想'

r = requests.get('https://www.google.co.jp/search?hl=jp&gl=JP&num=10&q=' + search_query)
html_l = r.text.encode()
root = lx.fromstring(html_l)

url_results = []
for t in root.cssselect('div.kCrYT a'):
     u_res = re.sub(r'/url\?q=|&sa.*', '', t.get('href'))
     u_result = re.sub(r'/search\?gl=JP&ie=UTF-8&q=.*', '', u_res)
     if u_result != '':
          url_results.append(u_result)
          print(u_result)

title_results = []
for i in url_results:
     t_html = requests.get(i)
     t_soup = BeautifulSoup(t_html.text, 'lxml')
     title = t_soup.find('title')
     print(title.text)
     time.sleep(2)

出力結果

Python Google検索を抽出した結果

ちなみに実際にGoogleでした画像がこちら

Google検索の結果ページ

矢印のリンク先にアクセスして、省略されているタイトルもきちんと取得できています。

鬼滅の刃 映画感想で検索するとうまく抽出できるのですが、Udemyで検索するとどうもうまく抽出できませんでした。

ヒットしたURLの抜き出しがうまくいかなかったり、アクセス先が存在しなかったりしてエラーが起こってしまうようなので、この先tyr-exceptなどを使った例外処理のコードも加える必要があります。

とりあえず、パートに分けてコードを確認してみます。

インポートするライブラリ

import time

from bs4 import BeautifulSoup
import lxml.html as lx
import re
import requests

timeBeautifulSouplxmlrerequestsです。

timeは、抽出したURLへのアクセスが不正なアクセスにならないよう、時間を開けてアクセスするために使います。

BeautifulSouplxmlは、取得した値の解析に使い、reは正規表記、requestsはHTTPでデータを取得するために使います。

URLの取得

search_query = '鬼滅の刃 映画感想'

r = requests.get('https://www.google.co.jp/search?hl=jp&gl=JP&num=10&q=' + search_query)
html_l = r.text.encode()
root = lx.fromstring(html_l)

url_results = []
for t in root.cssselect('div.kCrYT a'):
     u_res = re.sub(r'/url\?q=|&sa.*', '', t.get('href'))
     u_result = re.sub(r'/search\?gl=JP&ie=UTF-8&q=.*', '', u_res)
     if u_result != '':
          url_results.append(u_result)
          print(u_result)

こちらのコードは昨日のURLを抽出するコードと同じですが、変数をu_resu_resultに変更して、検索ワードを鬼滅の刃 映画感想にしています。

タイトルの取得

for i in url_results:
     t_html = requests.get(i)
     t_soup = BeautifulSoup(t_html.text, 'lxml')
     title = t_soup.find('title')
     print(title.text)
     time.sleep(2)

22行目からがURLにアクセスして、タイトルを取得するためのコードになります。

22行目でforループで取得したurl_resultsを回します。

23行目でリストにあるURLにアクセスして値を取得して、24行目のBeautifulSoupでオブジェクトを作り、25行目でオブジェクトからtitleタグを抜き出し、26行目でタイトルタグのテキスト部分だけを出力しています。

出力後は2秒まって、次のループに進んでいます。

まとめ

最初に書きましたが、このコードは例外には対応していないので、エラーが起こればきちんと値を取得することができません。

エラーが起こったときにもプログラムが最後まで処理ができるように、例外に対応できるコードにする必要があります。

また、今回のコードでは同じような処理をするBeautifulSouplxmlを使っているので、どちらか一方に統一したほうがいいのかもしれません。

明日は、もう少しこのコードを見やすくわかりやすいコードに作り変えていきたいと思います。

それでは、明日もGood Python!