スクレイピング2 スクレイピングのやり方


Aidemy 2020/9/30

はじめに

 こんにちは、んがょぺです!バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます!
 今回は、スクレイピングの2つめの投稿になります。どうぞよろしくお願いします。

*本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。

今回学ぶこと
・スクレイピングの方法(前準備であるクローリングはスクレイピング1を参照)
・複数ページをスクレイピングする

スクレイピングする

スクレイピングの方法

・(復習)スクレイピングとは、Webページを取得し、そこから必要なデータを抜き出すことである。
・スクレイピングの方法は「正規表現(reモジュール)」を使う、または「サードパーティ製のライブラリを使う」の2種類があるが、今回はメジャーな方法である「サードパーティ製のライブラリを使う」方法でスクレイピングを行う。

HTML、XMLについて

・XMLはHTMLと同じWebページを直接構築するマークアップ言語である。HTMLよりも拡張性に優れる。
・HTML,XMLでは、<title><\title>のような感じで囲まれたテキストがあり、このうち全体を要素と言い、< title>のことをタグと言う。
・また<html lang="ja">のような表記もあり、これはlang属性がjaである、すなわち、言語は日本語であると言う意味である。
・今回スクレイピングで使う「BeautifulSoup」ライブラリでは、この要素名からタイトルなどを取得する。

BeautifulSoupでスクレイピング(解析準備)

BeautifulSoup(デコードしたWebページ,"パーサー")メソッドを使うことで、簡単にスクレイピングできる。
パーサーとは、文字列の解析(パース)を行うプログラムのことであり、特徴別に何種類かあり、そこから一つを指定する。例として、追加のライブラリが必要ない「html.parser」、高速に処理ができる「lxml」、XMLに対応する「xml」などがある。

#クローリングするrequestsとスクレイピングするBeautifulSoupをインポート
from bs4 import BeautifulSoup
import requests
#urlの取得
url=requests.get("https://www.google.co.jp")
#スクレイピング(デコードはrequestモジュールのurl.textで行う、パーサーは"xml"に指定)
soup=BeautifulSoup(url.text,"xml")

BeautifulSoupでスクレイピング(必要なデータを抜き出す)

・前項で行ったパースをしたデータからは、必要なデータを抜き出すことができる。方法は以下の二種類である。
・パース済みデータを変数soupに入れたとするとsoup.find("タグ名or属性名")でそのタグか属性を持つ要素を最初の一つだけ抜き出す。またfindの部分をfind_allとすれば指定した要素を全てリスト化して抜き出す。
・また、クラス属性からスクレイピングしたい時は、引数にclass_="クラス属性名"を加える。

・パース済みデータを変数soupに入れたとするとsoup.selected_one("CSSセレクタ")で、これを満たす要素を最初の一つだけ抜き出す。またselected_oneの部分をselectとすれば指定した要素を全てリスト化して抜き出す。
CSSセレクタとは、要素をCSSの表現で示す方法である。これを使えば、要素の中の要素を指定することもできる(ex)body要素の中のh1要素は"body > h1")。

・また、裏技ではあるが、Chromeの開発者ツールで要素やCSSセレクタをコピーできる。そのため、わざわざデコードしたデータを出力することなく、視覚的にわかりやすく欲しいデータを抜き出せる。

Google_title = soup.find("title") #<title>Google</title>
Google_h1 = soup.select("body > h1") #[] (body要素のh1要素がないので空リストが出力)

・上記のままだとGoogle_titleはtitleタグがついたまま出力されてしまうが、textを使うことで、このうちのテキストのみを取得できる。

print(Google_title.text) #Google

複数ページをスクレイピングする

・ここまでの方法だと1ページずつしかスクレイピングできない。複数ページをスクレイピングしたい時は、トップページなどにある他ページへのリンクから他ページのURLを取得し、繰り返し処理で全てのURLに対してスクレイピングを行えば良い。
・他ページのURLはトップページのURL + 要素のhref属性(各ページのリンク)で取得できる。

top="http://scraping.aidemy.net"
r=requests.get(top)
soup=BeautifulSoup(r.text,"lxml")
url_lists=[]
#他ページのURLをリンクから取得
#(方法は、まずaタグを全て取得し、そのそれぞれについてgetを使ってhref属性を文字コード化し、topURLとつなげることでURLとする)
urls = soup.find_all("a")
for url in urls:
    url = top + url.get("href")
    url_lists.append(url)

・他ページのURLが取得できたら、実際にスクレイピングする。先述の通り、繰り返し処理で全てのURLに対してスクレイピングを行えば良い。
・以下では、前項で取得した全ページから写真のタイトル(h3タグに記載されている)をスクレイピングして全て取得し、リストとして表示する。

photo_lists=[]
#前項で取得したページをエンコードしてから写真のタイトルをBeautifulSoupでスクレイピング
for url in url_lists:
    r2=requests.get(url)
    soup=BeautifulSoup(r2.text,"lxml")
    photos=soup.find_all("h3")
#スクレイピングして取得した写真のタイトルを、h3タグを抜いてリストに追加
    for photo in photos:
        photo_text=photo.text
        photo_lists.append(photo_text)

print(photo_lists) #['Minim incididunt pariatur', 'Voluptate',...(略)]

まとめ

・クローリングしたページをスクレイピングするときは、まずBeautifulSoupメソッドでパースする。
・パースしたデータからは任意のデータを抜き出せる。抜き出すにはfind()あるいはselected_one()を使う。
・抜き出したデータにtextをつけると、タグなどが省略され、要素のみ抽出できる。
・複数のページをまとめてスクレイピングする時は、トップページなどからリンクを抜き取り、ベースのURLとつなげることでクローリングできるので、それを個別にスクレイピングする。

今回は以上です。ここまで読んでくださりありがとうございました。