不動産鑑定士修習戦記ヨッチャム

鑑定及びデータサイエンスの勉強、並びに海岸に事務所を建てる

【データ収集】Webスクレイピングことはじめ

webサイトからデータとってくる単純作業を自動化(スクレイピング)していこうの巻
注意事項~具体的方法をざっくり説明するよ(5,900文字…?!?!


例のごとく、こうやって誰かに教える感じで書くと学習効果が高いので教える感じで書きます
調べてますが、理解に間違いあればすみません。教えて貰えるとありがたいです

スクレイピングは、鑑定業界ならどうするのが良いとかいうのはなく、方法は各自やりやすい方法でやれば、という感じであります
古い情報とかもいっしょくたにいっぱい転がってる中で、この記事書いてる2023/1/14時点でちょろっと触ってみてわかったことや躓いたことを書いていきます

※当然ながら、スクレイピング禁止されてるサイトではだめです
収集データを個人使用する場合も、著作権やマナー等注意事項を調べて軽く頭に入れるべき
あと、下記事件の概要は知っといた方がいいと思います
これがあるため、スクレイピングやる全員が、逮捕・勾留されるリスクを負っているとも言える
岡崎市立中央図書館事件 - Wikipedia

スクレイピング概要

目的

・特定のWebサイト上の欲しい情報(テキストデータ、画像データ等)を自動的に取得すること

手段

プログラムを用いて、
・ブラウザ(Chromeとか)を操作する
 ex. リンクをクリックしたり、テキストボックスに文字入力したり
・HTMLソースを取得する
・取得したHTMLソースから欲しい文字列をとってくる
 ex. リンク先になってるURLの取得、表示されている文字列の取得
・あと、画像等のファイルをダウンロードしたり

VBAPythonかはたまたその他言語か

結論: どれでもよ◎(迷ったらPythonか)
自分はPythonで始めたので、ここではPythonでやる場合について書きます

Excel士の人の場合、なんでもExcelに取り込んでVBAで操作するのが馴染みあるかと思うのですが、自分の場合は、VBA少しだけ書いてみたらJava経験あるプログラミング初心者には書きづらく…
取り込んだデータをあっちゃこっちゃ加工・分析するのにはPythonが良く、記述がとても簡潔で、Webや書籍に情報がたくさんあるので、Pythonでやることにしました
VBAでもPythonでも「Celenium」というライブラリを使ってGoogle Chromeを操作するのが一般的だと思います
VBA単体ではIEの操作はできてたけど、2022年でサポート終了した

必要なライブラリ

以下のライブラリをPythonの仮想環境にインストールして始めます
その他のライブラリは必要に応じて適宜

・Helium - Celeniumのラッパーライブラリ
Celeniumとは、ブラウザ操作するためのものだよ(HTMLソースの一部取得とかもできるけど、それは後述のBeautiful soupでやったほうがいいっぽい)
HeliumインストールするとCeleniumも入ってるし、Celeniumのメソッドとかもだいたい使えるからHelium入れといて損は無い
Celeniumより簡潔に書けるところがあるので、結局Celeniumのメソッド使うところも多々あるものの、積極的に使っていきたい
可読性も良い

Heliumについては、日本語の情報が少ないが、以下のサイトを読む。

まずここ
zenn.dev

公式
selenium-python-helium.readthedocs.io

CeleniumやBeautiful soupそれぞれの使い所。どうやって記述するかの参考になる
su-gi-rx.com


・Beautiful soup4
取得したHTMLソースから特定の文字列を抽出(抜き出したり)するやつ
「pip install bs4」でインストールできちゃったけど、正式なのは「beautifulsoup4」でした。危なかった…ちゃんと調べないと

pip install beautifulsoup4

IDEについて
「PyCharm」使ってます
Python専用で使いやすいです
大学生だと無料で使える

※仮想環境について
Pythonでは、まず仮想環境を作成し、それに上記ライブラリ(Celeniumとか)を適宜インストールし、そこでプログラムを実行します

方法

1.Chromeを立ち上げてドライバオブジェクト取得

Heliumのstart_chromeメソッド一発。戻り値にドライバ。


Chromeの操作をする場合、Chrome DriverとChrome本体それぞれのバージョンを合わせる必要がある。
基本的にはHeliumのインストール時にChrome Driverもついてくるので、なんもしなくてもいけることもあるらしいが、私はエラー出てだめだった。
実行してエラー出る場合、以下から、自分の使ってるChrome本体と同じくらいのバージョンのChrome Driverをゲットして、どこかにおいて、Pathを通す。または、Heriumインストール時に元々入ってたChrome Driverと置き換える。
chromedriver.chromium.org

Pathの通し方は、ターミナルからコマンド入力、またはWindowsの設定内「環境変数を変数」ウィンドウにて。

2.お好みの操作

・ブラウザ操作

クリックしたい箇所がテキスト(文字列)でできているなら、Heriumのclickメソッドが使える。
でも、テキストだけどうまくいかない、又は画像になってたりする場合は、Celeniumのメソッドを使って要素を指定した上でJavascriptでクリック等の操作をする。

下記は、要素の取得を行うメソッド。ID、Name、XPathCSSセレクタ等いろいろ条件にできる。
・find_elementメソッド 条件に当てはまる最初の要素を返す
・find_elementsメソッド 条件に当てはまる全ての要素をリストで返す

要素の探し方は、Chromeで対象のWebサイトを開いて、適当なとこで右クリック「検証」から、クリック等したい要素がHTMLのどこにあたるのかを探す。Chrome便利。

基本的には、Helium試す→ダメならCelenium。Helium使えるとこでは使うのが一番作業時間短い。

注意

(1)クリックはJavaScript使う
Celeniumでもクリック操作できるが、画面外の要素はエラー出て落ちる。
なので、Celeniumのクリックメソッドは使わずに、execute_scriptメソッドを利用しJavaScriptのクリック操作を行うこと。

(2)ウェイトかける
適宜ウェイトをかけてご迷惑にならないようにしよ、ってのと。(time.sleepメソッド)
画面遷移後に要素が表示されてないのに操作しようとしてエラーになることも?その場合もウェイト必要かも。
Heliumは、その要素が表示されるまで、10秒まで勝手に待つようになってた気がする。

(3)Celeniumはバージョンアップしてメソッドの記述変わってる
find_element_by_idメソッド等は、ネットや本でいっぱい使われてますが、今使用できないです。
今は、find_elementメソッドになっており、第一引数で何を使って要素を指定するのか(ID、XpathCSSセレクタ等)を書く。下記ソースコード一行目の「By.ID」は、HTMLのID。第二引数は、その値。

        element_check_logout = driver.find_element(By.ID, 'auto-logout')

        # チェックボックスにチェックが入っていなかったらチェックする
        if not element_check_logout.is_selected():
            driver.execute_script('arguments[0].click();', element_check_logout)

        time.sleep(NUM_SHOW_PAGE_NEED_SLEEP)
・HTMLソースの解析

ブラウザ操作で対象のページを表示させたあとは、Beautiful soupの出番

(1)HTMLソースをBeautiful soupオブジェクトにする
個人的に、全部の具材が入った寄せ鍋みたいなイメージ。ここからお好みの具をすくってくるぞ。

        html = driver.page_source
        soup = BeautifulSoup(html, "html.parser")

(2)Beautiful soupオブジェクトから必要な文字列等を抽出する
Beautiful soupオブジェクトからfind系メソッドかselect系メソッドで文字列抽出。基本的にはどっち使っても良いのだが…

find系: 要素名、属性名指定できる←可読性が良い
find_all() 全ての要素をリストで返す
find() 最初に見つかった要素1つだけ返す

select系: CSSセレクタ使える。←CSSセレクタは他に被ってるかとか気にせず一発で取れる(ただし、動的な何かが含まれる場合は工夫必要)
select() 全ての要素をリストで返す
select_one() 最初に見つかった要素1つだけ返す

        trs = soup.findAll("tr", bgcolor="#FFFFE0")


記述例

# --------------------------------------------------
# 株価を取得するメソッド
# --------------------------------------------------
def get_kabuka():
    list_kabuka = []

    driver = start_chrome('https://quote.jpx.co.jp/jpx/template/quote.cgi?F=tmp/stock_search')
    # ※要修正※
    # チェックボックスクリックが動作していないかも
    click('プライム')
    click('スタンダード')
    click('グロース')
    select(ComboBox('25件ずつ'), '100件ずつ')
    click(Button('検索開始'))
    time.sleep(NUM_SHOW_PAGE_NEED_SLEEP)

    while True:
        html = driver.page_source
        soup = BeautifulSoup(html, "html.parser")
        trs = soup.findAll("tr", bgcolor="#FFFFE0")

        for tr in trs:
            rows = []
            for cell in tr.findAll('td'):
                rows.append(cell.get_text().replace("\r\n", "")
                            .replace("\n", "")
                            .replace("\t", "")
                            .replace("\xa0", ""))
                # .replace(",", "")
            if rows:
                list_kabuka.append(rows)
        if Link('次のページ').exists():
            click(Link('次のページ'))
            time.sleep(NUM_SHOW_PAGE_NEED_SLEEP)
        else:
            break
    kill_browser()

    # csvファイルに書き込み
    with open(PATH_KABUKA, 'w', newline="", encoding="utf_8_sig") as f:
        writer = csv.writer(f)
        writer.writerows(list_kabuka)

    return list_kabuka

3.ブラウザ終わる

完。

kill_browser()

Pythonだとリストを簡単にcsvファイルにできるよ

まとめ

Helium、できなければCeleniumでブラウザ操作

Beautiful soupでHTMLの鍋から好きな具材を拾おう

サイトによってどうやって書いたら拾えるかは、いろいろ手段があるので考えようね