#概要
Pythonでのスクレイピングにより、競合など他社サイトに掲載されている商品データを収集し、
マーケティング・競合分析への活用のため、CSVファイルにまとめ、出力します
#対象ページ
スクレイピング対象は、以下のようなページです
- インテリアのECサイト
- チェア:カテゴリの商品一覧ページ
##対象データ
今回は、先述のページから
- 商品名
- 価格
- レビュー|評価値
- レビュー|投稿数
以上 4つの情報を、チェア:カテゴリの全商品分、取得します
#注意
- 記事内の「Webサイト/URL/データ」は全てダミーです
- 記事内のコードで、実際にスクレイピングする事は可能ですが、実在のサイトに対するスクレイピングは、サーバー負担への配慮、著作権/利用規約の十分な確認等が必要となります
#対象分析
対象から利用制限が指定されていないか、対象ページの構造はどうなっているか、等を分析/確認していきます
##利用制限
人様のサイトからデータを取得するにあたり、まずはそのサイトの「著作権/利用規約ページ」をしっかり確認した上で、以下のコードでアクセスに対する制限を確認
. . . . .
クローリングへの指示書である「robots.txt」解析のためのモジュールurllib.robotparser
をインポート
import urllib.robotparser
rp = urllib.robotparser.RobotFileParser()
robots.txtの読み込み
rp.set_url("https://demo-store.com/robots.txt")
rp.read()
request_rate
で、クローラーに対し遅延時間が指定されていないかの確認
req_rate = rp.request_rate("*")
print(req_rate)
None
遅延時間の指定は無し。とはいえ、相手サーバー負荷への配慮として、ロード遅延処理は必須
. . . . .
can_fetch
でURLの取得が許可されているかを確認
rp.can_fetch("*", "https://demo-store.com/")
True
True
が返され、URL取得の許可が確認できました
##ページ構造
Chrome|デベロッパーツールを用い、対象ページの構造を確認
1商品ごとにpd_box
というクラス名のパーツで囲われ、
その中に今回取得したい4つの商品情報が入っており、それぞれ以下のようにクラス名が付けられています
情報 | クラス名 |
---|---|
商品名 | pd_name |
価格 | pd_price |
レビュー:投稿数 | rev_count |
レビュー:評価値 | rev_rate |
##URLの規則性
対象ページのURLは以下(※ ダミーURLです)
https://demo-store.com/living/chair/?page=1
また、この「チェア:カテゴリ|商品一覧」は、全10ページで
10ページ目のURLはhttps://demo-store.com/living/chair/?page=10
となっており、
?page=XX
の箇所が、現在のページ数を表しているという事が分かりました
以上を踏まえ、スクレイピング実行のコードを考えていきます
#データ取得
実際にブラウザを起動・サイトを描画しながらスクレイピングする手法もありますが、今回はヘッダレスブラウザを用い、画面描写無しでサッサとスクレイピングしていきます
. . . . .
Selenium|Chromeブラウザをインポート
from selenium.webdriver import Chrome, ChromeOptions
from selenium.webdriver.common.keys import Keys
--headless
でオプション:ヘッドレスモードを有効化
options = ChromeOptions()
options.add_argument('--headless')
ChromeのWebDriverオブジェクトを作成
browser = Chrome(options=options)
後に商品情報を格納していく、空のリストを作成
names = []
prices = []
rev_rates = []
rev_counts = []
今回の対象は「商品一覧:10ページ分」つまり
https://demo-store.com/living/chair/?page=1
から
https://demo-store.com/living/chair/?page=10
までが対象です
よって?page={}
として、ページ数箇所を変数とし、format(i)
で変数箇所にi
を埋め込みます
i
にはfor
文で1から10までの数字を順に当てはめていきます
for i in range(1,11):
url = 'https://demo-store.com/living/chair/?page={}'.format(i)
ややこしいですがrange(1,11)
で、1から10までの数字が入ることになります
. . . . .
相手サーバーへの負荷配慮としてimplicitly_wait
でロードの際に3秒の間隔が空くように設定
browser.implicitly_wait(3)
「?page={}
箇所に連番が入ったURL」を取得
browser.get(url)
一覧ページでは、商品ごとにpd_box
で囲われていました
その中に、それぞれの商品名(pd_name
)や価格(pd_price
)が含まれている
よってpd_box
の中身を探し終えたら、次のpd_box
の中身を探し始める、という内容のfor
文とします
find_elements_by_class_name
で指定したクラス名の要素を取得し、リストとしてpd_boxes
に格納
pd_boxes = browser.find_elements_by_class_name('pd_box')
pd_box
1つあたりに対し、「pd_name/pd_price/rev_rate/rev_count」を探し、取得し、それぞれリストとして格納していく。完了したら次のpd_box
に対し同様の処理を行っていく
for pd_box in pd_boxes:
name = pd_box.find_element_by_class_name('pd_name').text
names.append(name)
price = pd_box.find_element_by_class_name('pd_price').text
price = price.replace("¥","").replace(",","")
prices.append(price)
rev_rate = pd_box.find_element_by_class_name('rev_rate').text
rev_rates.append(rev_rate)
rev_count = pd_box.find_element_by_class_name('rev_count').text
rev_count = rev_count.replace("(","").replace("件)","")
rev_counts.append(rev_count)
名前や価格を取得しつつ、「¥」や「件」などの不要文字列はreplace
により削除しています
. . . . .
取得したデータを確認
names
['Ultra Chair','Super Chair','Hyper Chair'...]
prices
['10000','20000','30000'...]
rev_rates
['5','5','5'...]
rev_counts
['26','36','46'...]
ちゃんとデータ取得できています
#CSV出力
取得したデータは現時点では個々のリストになっているので、データフレームとしてまとめます
import pandas as pd
df = pd.DataFrame()
リスト毎に列を作成
df['name'] = names
df['price'] = prices
df['rev_rate'] = rev_rates
df['rev_count'] = rev_counts
内容確認のため、データフレームの上から5行目までを表示
df.head()
|| name | price | rev_rate | rev_count |
|:--|:--|:--|--:|--:|--:|
1| Ultra Chair | 10000 | 5 | 26 |
2| Super Chair | 20000 | 5 | 36 |
3| Hyper Chair | 30000 | 5 | 46 |
4| Miracle Chair | 40000 | 5 | 56 |
5| Passion Chair | 50000 | 5 | 66 |
問題無くデータフレームになっているので、CSVファイルに変換します
df.to_csv('living_chair.csv', index=False)
CSVファイルが出力されました
#総括
他社サイトの商品情報をスクレイピングで収集し、CSVファイルにまとめました
- 各商品のレビュー投稿数を、販売数とある程度の相関があると仮定し、販売数予測の目安とする
- 価格帯ごとのレビュー評価(満足度)を分析する
など、競合分析において活用のできる、データファイルが取得できたかと考えます