さくらのレンタルサーバを使ってスクレイピングをする方法をまとめます。
初めに言いますがページ遷移はカバーしていません。
eBay の商品情報を例としてページの要素を取得し、MySQL のデータベースに insert する一連の過程をまとめたいと思います。最後は CRON を使って定期実行させる設定も行います。
なので最低限 MySQL と CRON が使える「さくらのレンタルサーバ スタンダード」以上のプランを想定しています。
一応自分の忘備録としてまとめていますが、過程を追っていただければと思います。
- 実行環境の準備
- さくらのレンタルサーバを契約する
- Python3 のインストール
- 仮想環境の作成
- スクレイピングをしてみる
- データを保存する DB の作成
- Python からデータベースを操作する
- CRON で定期実行する
1. 実行環境の準備
さくらのレンタルサーバを契約する
まず始めるにあたってさくらのレンタルサーバを契約します。
冒頭でも書きましたが、データの保存と定期実行を行う前提なので MySQL と CRON が使える「さくらのレンタルサーバ スタンダード」以上のプランを使用します。
Python3 のインストール
サーバーへアクセスできる様になったら、Python3 をインストールして仮想環境を作成します。
さくらレンタルサーバのデフォルトの Python は Python2 なので Python3 を別途インストールする必要があります。下記の記事で手順を説明しています。
仮想環境の作成
Python3 のインストールが完了したら、任意の場所に仮想環境を作成します。
例として仮想環境「scraping_venv」を作成します。
% python3 -m venv scraping_venv %
仮想環境のパスに入り起動します。
% cd scraping_venv % source bin/activate.csh (scraping_venv) %
3. スクレイピングをしてみる
では早速、requests モジュールを使ってページの情報を取得してみます。
requests のインストール
Web ページの取得に便利な requests をインストールするためコマンド「pip3 install requests」を実行します。
(scraping_venv) % pip3 install requests
インストールが完了したら Python3 を起動しますが、仮想環境を起動しているのでコマンド「python」で 起動できます。
(scraping_venv) % python Python 3.9.0 (default, Jan 3 2021, 10:29:59) [GCC 4.2.1 20070831 patched [FreeBSD]] on freebsd9 Type "help", "copyright", "credits" or "license" for more information. >>>
eBay ページの取得
requests をインポートし、requests.get() で URL「https://www.ebay.com/b/Video-Game-Consoles/139971/bn_320033」のソースコードを取得します。
>>> import requests >>> r = requests.get('https://www.ebay.com/b/Video-Game-Consoles/139971/bn_320033') >>>
一旦変数 r に全部入ったので、r.text を実行するとソースコードが確認できます。
>>> r.text '<!DOCTYPE html><!--[if IE 9]><html class="ie9" lang="ja"><![endif]--><!--[if gt IE 9]><!--><html lang="ja"><!--<![endif]--><head><style>\n .font-marketsans body {\n font-family: "Market Sans", Arial, sans-serif;\n }\n</style><script>\n (function() {\n var useCustomFont = (\'fontDisplay\' in document.documentElement.style) ||\n (localStorage && localStorage.getItem(\'ebay-font\'));\n if (useCustomFont) {\n document.documentElement.classList.add(\'font-marketsans\');\n }\n })();\n</script><meta charset="utf-8"><link rel="'preconnect'" href="https://ir.ebaystatic.com" /><meta Property="og:description" Content="Shop eBay for great deals on ビデオゲームコンソール. You'll find new or used products in ビデオゲームコンソール on eBay. Free shipping on selected items." />
ソースコードを取得出来ることを確認できたので「exit()」を実行して一旦 Python のコンソールから出ます。
>>> exit() (scraping_venv) %
Beautiful Soup で HTML 要素抽出
ページのソースを取得することはできたので、今度はそのソースコードから具体的な HTML の要素を抽出していきます。
HTML の取り扱いに便利な BeautifulSoup4 をインストールするためコマンド「pip3 install beautifulsoup4」を実行します。
(scraping_venv) % pip3 install beautifulsoup4
インストールが完了したら再度 Python3 を起動して BeautifulSoup と requestsをインポートします。
(scraping_venv) % python3 >>> from bs4 import BeautifulSoup >>> import requests >>>
とりあえず eBay のページからサムネイル URL、商品名、商品ページ URL を取得したいと思います。
>>> r = requests.get('https://www.ebay.com/b/Video-Game-Consoles/139971/bn_320033') >>> soup = BeautifulSoup(r.text,'html.parser') >>> sitem = soup.find_all('li',class_='s-item') # クラス名が「s-item」の li 要素のリストを取得
Chrome のデベロッパーツールでページの構造を確認したところ、どうやらサムネイル URL、商品名、商品ページ URL は li 要素の中に含まれていて、その li 要素のクラス名が s-item だったので上記の様に取得しました。
取得した li 要素はリスト形式になっているので、for ループで各 li 要素からそれぞれの項目を抽出し、print していきます。
>>> for li in sitem: # 各 li 要素に対して処理を行う ... img = li.find('img') # li 要素内の img 要素を取得 ... img_src = img.get('src') # img 要素内の src 属性を取得 ... name = li.find('h3') # li 要素内の h3 要素を取得 ... name_text = name.text # h3 要素内の文字列を取得 ... link = li.find('a') # li 要素内の a 要素を取得 ... link_href = link.get('href') # a 要素内の href 属性を取得 ... print(img_src) ... print(name_text) ... print(link_href) ...
Enter を2度押下するとプログラムが実行されサムネイル、商品名、商品ページ URL が交互に表出されます。
... https://i.ebayimg.com/thumbs/images/g/Tl0AAOSwZpJgOul6/s-l300.jpg ソニー PS5 ブルーレイエディションコンソール ( ディスク版 ) - クリスマス前に配達 ! https://www.ebay.com/p/19040936896?iid=154349758236 https://i.ebayimg.com/thumbs/images/g/AD4AAOSw3YphYRwA/s-l300.jpg オリジナルNintendo EntertainmentシステムビデオゲームバンドルセットキットNESコンソールOG https://www.ebay.com/p/101801921?iid=333818163486 https://i.ebayimg.com/thumbs/images/g/910AAOSwV5FhgtgV/s-l300.jpg ソニー PS5 PlayStation 5 デジタル版コンソール-クリスマス配信前 ! https://www.ebay.com/p/25040975636?iid=154369068285 〜省略〜 https://ir.ebaystatic.com/cr/v/c1/s_1x2.gif Microsoft Xbox One Day One Edition - 500 ギガバイトコンソールキネクトボックスコントローラテスト済み https://www.ebay.com/itm/284613629401?hash=item42444b55d9:g:jBkAAOSwqldh5hbZ https://ir.ebaystatic.com/cr/v/c1/s_1x2.gif Nintendo Wii コンソール RVL-001 パワーリード 、 TVリード 、 センサーバー付き https://www.ebay.com/itm/165287981385?hash=item267bee7149:g:I00AAOSwibph5VVv https://ir.ebaystatic.com/cr/v/c1/s_1x2.gif カシオゲームカンフーファイトCG - 310 ハンドヘルドゲーム 1990 https://www.ebay.com/itm/125105279976?hash=item1d20db13e8:g:J-IAAOSwn8dh5cND >>>
無事情報の抽出が出来ることを確認できたので、一旦「exit()」で Python のコマンドプロンプトから出ます。
>>> exit() (scraping_venv) %
同じ処理を Python ファイルで実行
一括で処理を実行できる様に、これまで実行したコマンドをまとめて下記のように一つのファイル(ebay_scraping.py)にまとめました。
# ebay_scraping.py from bs4 import BeautifulSoup import requests r = requests.get('https://www.ebay.com/b/Video-Game-Consoles/139971/bn_320033') soup = BeautifulSoup(r.text,'html.parser') sitem = soup.find_all('li',class_='s-item') # クラス名が「s-item」の li 要素のリストを取得 for li in sitem: # 各 li 要素に対して処理を行う img = li.find('img') # li 要素内の img 要素を取得 img_src = img.get('src') # img 要素内の src 属性を取得 name = li.find('h3') # li 要素内の h3 要素を取得 name_text = name.text # h3 要素内の文字列を取得 link = li.find('a') # li 要素内の a 要素を取得 link_href = link.get('href') # a 要素内の href 属性を取得 print(img_src) print(name_text) print(link_href)
これを仮想環境「scraping_venv」直下にアップロードします。
そしてコマンド「python3 ebay_scraping.py」を実行します。
(scraping_venv) % python3 ebay_scraping.py https://i.ebayimg.com/thumbs/images/g/Tl0AAOSwZpJgOul6/s-l300.jpg ソニー PS5 ブルーレイエディションコンソール ( ディスク版 ) - クリスマス前に配達 ! https://www.ebay.com/p/19040936896?iid=154349758236 https://i.ebayimg.com/thumbs/images/g/GygAAOSwehBh5hlm/s-l300.jpg ソニー PSP-3000 コンソール キングダム ハートゲームコンソール モンスターハンターゲームソフト付き https://www.ebay.com/itm/313838198557?hash=item491236df1d:g:GygAAOSwehBh5hlm https://i.ebayimg.com/thumbs/images/g/AD4AAOSw3YphYRwA/s-l300.jpg オリジナルNintendo EntertainmentシステムビデオゲームバンドルセットキットNESコンソールOG https://www.ebay.com/p/101801921?iid=333818163486 〜省略〜 https://ir.ebaystatic.com/cr/v/c1/s_1x2.gif 新品 ソニー PS4 Playstation 4 コンソール 1 TBスリム-新品送料無料 https://www.ebay.com/p/13031982632?iid=255337489506 https://ir.ebaystatic.com/cr/v/c1/s_1x2.gif Nintendo GameCubeモデルNo. DOL -101 コンソールパーツと修理のみゲーム付き https://www.ebay.com/itm/165288586955?hash=item267bf7aecb:g:TIgAAOSwZf9h5cbT https://ir.ebaystatic.com/cr/v/c1/s_1x2.gif Nintendo GameCube リージョンスイッチ付き LED mod カスタムコントローラ付き https://www.ebay.com/itm/165288874148?hash=item267bfc10a4:g:u1cAAOSw3MJh5fWT (scraping_venv) %
無事サムネイル、商品名、商品ページ URL、が表出されました。ページに掲載される商品がタイミングによって違うので前回の実行時と若干内容が変わっています。
4. データベースの作成
ここまではただターミナル上に print してきましたが、これらの情報をデータベースに保存できる様にします。
さくらレンタルのコントロールパネルでデータベース作成
コントロールパネルのデータベースのセクションで「新規追加」をクリックします。
WordPress を使っている場合はそのデータベースが既にあると思いますが、何かを間違えて WordPress 用のテーブルに影響が出ると良くないので新規のデータベースを作ることをお勧めします。


無事新たなデータベースが作成されたので phpMyAdmin へログインします。

phpMyAdmin でテーブル作成
ログインした後、先ほど作成したデータベースを選択するとテーブル作成の画面に遷移すると思います。
テーブル名を入力して「Go」をクリックします。

カラム名、形式、長さを入力して「Save」をクリックします。

これでテーブル作成は完了です。下記のように反映されていると思います。

これでデータベースとその中にテーブルが出来上がりました。
5. Python からデータベースを操作する
では Python プログラムで抽出した情報をそのままデータベースのテーブルに insert 出来るようにしていきます。
MySQLdb モジュールで操作する
まずは Python で MySQL を操作するために必要な MySQLdb モジュールを使える様、ピp3で「mysqlclient」をインストールします。
(scraping_venv) % pip3 install mysqlclient
インストールしたら Python を起動し、MySQLdb をインポートしてデータベースに接続します。
(scraping_venv) % python3 >>> import MySQLdb >>> conn = MySQLdb.connect(host='データベースサーバ', db='データベース名',user='ユーザー名',passwd='パスワード',charset='utf8mb4') >>>
そして試しに先ほど作成したテーブル「ebay_products」に select クエリを叩いてみます。
>>> c = conn.cursor() >>> c.execute('select * from ebay_products') 0 >>>
まだデータを何も入れていないので 0 と返ってきています。動作は特に問題なさそうです。
Python ファイルに追記する
では先ほど作成した ebay_scraping.py を編集します。
MySQLdb モジュールでデータベースに接続する部分と合わせて、データを print する代わりにテーブルへ insert する様変更します。
# ebay_scraping.py from bs4 import BeautifulSoup import requests import MySQLdb # 追記分 # 追記分↓ conn = MySQLdb.connect(host='データベースサーバー', db='データベース名',user='ユーザー名',passwd='パスワード',charset='utf8mb4') c = conn.cursor() # 追記分↑ r = requests.get('https://www.ebay.com/b/Video-Game-Consoles/139971/bn_320033') soup = BeautifulSoup(r.text,'html.parser') sitem = soup.find_all('li',class_='s-item') for li in sitem: img = li.find('img') img_src = img.get('src') name = li.find('h3') name_text = name.text link = li.find('a') link_href = link.get('href') # print(img_src) # print(name_text) # print(link_href) # 追記分↓ c.execute('insert into ebay_products values("'+img_src+'","'+name_text+'","'+link_href+'")') conn.commit() # 追記分↑
ではファイルを実行してみます。
(scraping_venv) % python3 ebay_scraping.py (scraping_venv) %
phpMyAdmin で対象のテーブルを開くとちゃんとデータが入っています。

これで eBay からデータを取得してデータベースへ保存するところまで出来ました。
6. CRON で定期実行する
作成したプログラムを定期的に実行する上で便利なのが CRON です。さくらのコントロールパネルから設定できるのでこの際やってみましょう。
コントロールパネル左下の「スクリプト設定」>「CRON設定」を開き「スケジュール追加」をクリックします。

設定画面が開くので実行コマンドと実行日時を設定します。毎日 21:00 に実行する設定にします。

「実行コマンド」欄は今回の場合「cd 実行ファイルのパス; Python3 の絶対パス 実行ファイル名」の形で下記の様に入力します。
cd www/notemite/scraping_venv; /home/ユーザー名/local/python/bin/python3 ebay_scraping.py
Python3 の絶対パスはコマンド「which python3」で確認できます。
% which python3 /home/ユーザー名/local/python/bin/python3
「保存する」をクリックして CRON 設定は完了です。
これで毎日 21:00 に ebay_scraping.py が実行され、取得したデータがデータベースのテーブルに insert されていきます。
複数処理を順に実行したい場合
余談ですが、設定できる CRON の数には限りがあるので、一つの処理につき一つの CRON を設定するとすぐ使い切ってしまいます。
なので例えば process_A.py、process_B.py、process_C.py という順番で実行したいプログラムがあった場合、まず CRON 設定の実行コマンドに下記を記述します。
cd www/notemite/scraping_venv; /bin/sh multiple_process.sh
これで CRON からは multiple_process.sh が実行されるので、個別のファイルと同じディレクトリに multiple_process.sh というファイルを作成し下記のように記述します。
#!/bin/sh /home/ユーザー名/local/python/bin/python3 process_A.py && /home/ユーザー名/local/python/bin/python3 process_B.py && /home/ユーザー名/local/python/bin/python3 process_C.py
これによって CRON によって multiple_process.sh 呼び出され、まず process_A.py を実行、処理が成功したら process_B.py、さらにそれが成功したら process_C.py という具合に実行することができます。