\ 年に1度のブラックフライデーセール! /

ラズパイでWEBスクレイピングーjupyter notebook

省電力なラズパイは簡単なデータ収集とデータ分析させるのにも適しています。WEBサイトから情報を持ってくるクローリング&スクレイピングをjupyter notebookを使って試してみました。

既に先人がたくさんの情報をWEBにアップしてくれているので、特別な書籍などは無くてもそれなりにできます。もちろん基本は知っていた方が良いので、興味が沸いたら有名な書籍を購入した方が良いと思います。

この記事は元々、Raspberry Pi 3BとまだRaspberry Pi OSがRaspbianと呼ばれていた頃の記事でした。その後、Raspberry Pi 4、Chromiumブラウザ バージョン104でも確認済みです。インストールとPythonコードは2022.9.21時点で修正してエラーなく実行できました。

この記事の主な流れ

今回の環境

はじめRaspberry Pi ノーマル3Bを使いました。プラス(+)が付かない旧型です。多少のWEBスクレイピングならスペック的にもそれなりですし、取得するデータもテキストベースですからスペースも必要ありません。更にLinux(Raspberry Pi OS)環境なら必要なライブラリ、アプリケーションは手に入ります。

その後、2022年にRaspberry Pi 4 64bit bullseyeで実行済みです。

今回の環境

  • Raspberry Pi OS 64bit bullseye(当初は2019-04-08-raspbian-stretch)
  • pandas
  • selenium
  • jupyter notebook
  • chromium-chromedriver

Raspberry Pi OSはliteでなければPython3やpip3は入っています。一部アップグレードして今回のプロジェクトで必要な他のライブラリをインストールしていきます。

事前にRaspberry Pi OSのセットアップは済ませてください。

インストールと設定

aptコマンドでインストールするのはpandasです。

sudo apt install python3-pandas

pipからインストールするものは以下です。pipはアップグレードしておきます。

sudo pip3 install --upgrade pip
sudo pip3 install jupyter
sudo pip3 install selenium

スクレイピングするjupyter notebookはLinuxもChromeも対応しています。しかし、Raspberry Pi OSではChromiumドライバであるchromium-chromedriverを別にインストールする必要があります。

Raspberry Pi OS 64bit bullseye環境で、aptに最新がありました。

aptコマンドでもイケた(bullseye)
sudo apt install chromium-chromedriver

Raspberry Pi OS 64bitのbullseye環境で、aptコマンドでもインストールできました。

以下のcommandでchromedriverがきちんとインストールできたか確認する。

which chromedriver

場所が表示されればOKです。/usr/bin/chromedriver

aptだとchromedriverの場所が異なっていたので、後ほどのPythonコードで修正します。

browser = webdriver.Chrome(executable_path="/usr/bin/chromedriver")

jupyter側の設定

ホームフォルダにスクレイピング用ディレクトリの新規作成しました。

mkdir ~/notebooks

jupyter notebookの設定ファイルを作成します。

jupyter notebook --generate-config

これで、home/pi/.jupyter/jupyter_notebook_config.pyに設定ファイルが出来上がります。

このjupyter_notebook_config.pyに3箇所を最下部へ追加する。(または既存の記述を修正)

c.NotebookApp.ip = '0.0.0.0'
c.NotebookApp.notebook_dir = '/home/pi/notebooks'
c.NotebookApp.port = 8888

パスワードの設定をします。

jupyter notebook password

このパスワードはChromiumブラウザからログインする際に使用します。

実行手順

ここからが本番です。

jupyter notebookを立ち上げます。コマンドで実行するかメニューの教育・教養カテゴリ内から起動します。

jupyter notebook

先程設定したパスワードを入れます。続けて、画像のように新しくnotebookを作ります。
New→Python3

実際の画面は以下です。

この枠内にあるボックスへコードを記述していきます。そしてRunボタンで実行させます。

終了するときは、左上のメニュー ファイル(File) → 閉じて終了(close and halt)から行います。(ブラウザを閉じない)

WEBスクレイピングしたコード

スクレイピングはたくさんのサイトで紹介されています。いつものごとく「オラに力を分けてくれ!」の先人達のコードを片っ端から読んで寄せ集め・・・いや、なんとか理解しつつまとめてみました。(無駄なコードは適時直してください)

今回、hatenaブックマークで任意の文字列(今回はRaspberry Pi )で検索し、その中で100以上ブックマークされている記事のURLを指定しています。

検索された記事のタイトル名、ブックマーク数、投稿日付、リンクURLをcsvとして書き出すプログラムです。

2022.9.21に修正しました。この時点で実行OKでした。

from selenium import webdriver
import pandas as pd
from bs4 import BeautifulSoup
import time

#hatenaへアクセス
url = "http://b.hatena.ne.jp/search/text?safe=on&q=Raspberry+Pi+python&users=100"
URL_HEAD=url.split('/search')[0]
p_url = 'https://b.hatena.ne.jp'

browser = webdriver.Chrome(executable_path="/usr/bin/chromedriver")
browser.get(url)
 
data = browser.page_source.encode('utf-8')
soup = BeautifulSoup(data,'lxml')
outputData = pd.DataFrame(index=[],columns=['title', 'bookmarks', 'created', 'link'])
page = 1

while True:
    if not soup.find(text="次のページ") is None:
         #Pageのclass centerarticle-entry-data内
         posts = soup.find_all('ul', class_='centerarticle-entry-data')
         print('Starting to get posts… page: {}'.format(page))

         for post in posts :
            title = post.find(class_='centerarticle-users').find('a').get('title')
            print(title)
            bookmarks = post.find(class_='centerarticle-users').find('a').text
            print(bookmarks)
            created = post.find(class_='entry-contents-date').text
            print(created)
            link_s = post.find(class_='centerarticle-users').find('a').get('href')
            link = p_url + link_s
            print(link)
            series = pd.Series([title, bookmarks, created, link], index=outputData.columns)
           
           #データ蓄積
            outputData = outputData.append(series, ignore_index=True)
            print(outputData)
            print('title: {}'.format(title))
         else:
            span = soup.find(class_='centerarticle-pager-next')
            a = span.find('a')
            urls = a.get('href')
            #print(span)
            #print(a)
            #print(urls)
            clickNextPageBtn = URL_HEAD + urls
            browser.get(clickNextPageBtn)
            page += 1
            browser.implicitly_wait(5)
            data = browser.page_source.encode('utf-8')
            soup = BeautifulSoup(data, 'lxml')
            
            print("--- Moving to next page ---")
            print('page={}'.format(page))
            time.sleep(5)
    else:
        print("no pager exist anymore")
        break

#ファイル出力
outputData.to_csv('/home/ユーザー名/notebooks/hatena.csv')
print(outputData)
print("DONE")
#終了処理
browser.quit()
  • コメントアウトしてあるprint文は確認のために利用しました。タグ要素が取れていない時に使ってください。
  • 出力先は最初に作ったnotebooksというフォルダを指定します。

結果はこの通り。ソートはしていません。

CSVの結果画面

その後、はてなブックマークのHTMLタグが変更したのに合わせPythonコードを一部修正しました。

改めて出力したCSV
Rレッド

修正するだけでもPythonの良い勉強になりました。

ハマったところ

詰まったところは沢山あって全ては表現しきれません。非エンジニアとして基本の基本はある程度理解したかなーと思っても、少しの応用で躓く・・・。

中でも一番ハマったのがこれ。

AttributeError: 'NoneType' object has no attribute 'text'
AttributeError: 'list' object has no attribute 'text'

これは本当に参りました。上のNoneTypeは絞り込めずに値を取れなかった場合が多いです。そもそもそんな値が取れないヘンテコな場所だったりした当てが外れたパターンもありました。

もう一つのlistのエラーは一意(ユニーク)にならず複数の値があったりした場合です。

やはり文法は勉強しないとダメですね・・・。書き方のミスも多かったです。それに似たようなメソッドも違いを覚えないとなりません。find_all、find、selectなど。

今回は時間をかけてハマった?!ので、だいぶ身につきました。HTMLの要素を理解するのは大前提なものの、HTML、CSS、Python、Beautiful Soupでかなり実用的なことができるなーという印象です。

  • ※注意:WEBスクレイピングは逮捕者も出ています(不起訴だったけど)扱いによっては、サーバーに負荷を掛けすぎるという危険なこともあり責任重大です。cornなどで自動にする際には気をつけないとなりません。本格的に運用するなら、そういうセキュリティ面も考慮してください。
  • Amazonはスクレイピングは規約違反になります。

サイト側でブロックしていればエラーで取得できません。ラズパイダでもあまりにも悪質なスクレイピングなどのアクセスはブロックしています。

APIが公開されていないサイトなどで利用し、十分な時間間隔を空けて実行しましょう。

Pythonクローリング&スクレイピング ―データ収集・解析のための実践開発ガイド―

参考にした主なサイト:Beautiful Soup 4.2.0 Doc. 日本語訳 (2013-11-19最終更新) 

シェアする
  • URLをコピーしました!

Raspberry Pi 4、400、Zero2W

販売価格は、必ず販売サイトで確認してください。

\年に1度のブラックフライデーセール!/
Amazonで詳しくみる
\年に1度のブラックフライデーセール!/
Amazonで詳しくみる
RaspberryPi
¥15,987 (2022/11/29 14:24時点 | Amazon調べ)
\年に1度のブラックフライデーセール!/
Amazonで詳しくみる

この記事のコメント(承認後に公開)

コメントする

コメントは日本語で入力してください。名前は表示されます。メールアドレスは表示されません。

CAPTCHA

この記事の主な流れ