ウマいオールド・ウイスキーの落札相場をPythonでスクレイピングして調査してみよう
こんにちは、葉隠しんの(@Singularity1217)です。
今回は、PythonのBeautifulSoupライブラリを使用してスクレイピングを行い、ヤフオクにおけるオールドボトル・ウイスキーの相場を調べました。
※オマケ情報のみ有料しておりますが、メインとなる内容はすべて読めます。お楽しみください。
オールドボトル・ウイスキーとは、現行品名と名前は同一であるものの、年代の古い(30~40年以上前!)もので、現代のものとは異なるウイスキーです。
細かいウンチクは省きますが、特に1989年以前の、税制上『特級』と表示があるものは一味違うことが多いです。
もっとも保管状況が悪いものを当ててしまうと、悪い意味で一味違うのですが、、、
本記事では、ジョニーウォーカー・黒 ①1980年代前半頃のボトルと、②1980年代後半のボトルの1本あたりの落札相場情報を求めます。
(よく見ると、現行品のものとラベルが異なります。)
下記のような人たちにおススメです。
・Pythonを勉強していて、BeautifulSoupを使ったコードを書いてみたい人
・スクレイピングした結果をどうアクションにつなげるか?事例をみたい人
・プログラミングは良いから、落札相場が知りたい人(結果は4章です。)
1.スクレイピングをしてみよう
まずはスクレイピングするのに適したurlを見つけます。
今回は落札履歴データベースで、『ジョニーウォーカー』,『黒』,『特級』で検索したページをスクレイピングします。
デフォルトで100件ほど表示されます。
続いて検索するページのhtmlのソースコードを覗いてみましょう。
画像が小さいので分かりづらいですが、①件名と②落札価格は、それぞれ下記タグ&クラスで囲まれていることが分かります。
①件名: <a class="Product__titleLink" (以下略)>~~~</a>
②落札価格: <span class="Product__label">~~~</span>
(ここら辺はhtmlを一度、Progateなどで勉強しておくと分かりやすいです。)
対象とするページ、検索対象の文章が、囲まれているhtmlのタグとクラスが分かったので、早速BeautifulSoupを駆使してスクレイピングしてみましょう。(コード全体は、こちらに投稿しています。)
from bs4 import BeautifulSoup
import requests
import pandas as pd
#ヤフオクの落札履歴データベースから、'ジョニーウォーカー + 黒 + 特級'で検索した
#ページより、スクレイピングする。urlは長いため省略。
url =''
result = requests.get(url)
soup = BeautifulSoup(result.text, 'html.parser')
#出品している件名と、落札価格を、スクレ―ピングする。
#スクレ―ピングしたリストを確認して、求めている年代のウイスキ―サンプルを抽出する。
name_html_list = soup.find_all('a', class_='Product__titleLink')
price_html_list = soup.find_all('span',class_='Product__priceValue')
data = pd.DataFrame(columns=['price'])
for i,j in zip(name_html_list,price_html_list):
price = j.get_text()
price = price.strip('円')
price = int(price.replace(',',''))
temp = pd.Series([price],index =data.columns, name = i.get_text())
data= data.append(temp)
実際にスクレイピングした結果は、下記です。
Indexの列に件名、Priceの列に落札価格がそれぞれ入っています。
スクレイピングしたデータには、複数のボトルが入っていたり、容量が異なったりしています。
どうやらサンプリングしたデータをもとにしても、1本あたりの値段は見えてこなそうですね。工夫する必要がありそうです。
2.対象となるサンプルデータを抽出してみよう
本コードの目的である、ジョニーウォーカー・黒 ①1980年代前半頃のボトルと、②1980年代後半のボトルの1本あたりの落札相場情報を求めるべく、データ抽出していきます。
まず①と②を分ける条件として、容量差があります。
こまかいウンチクは省きますが、容量(760ml)=1980年前半頃、容量(750ml)=1980年後半頃ものと言われています。
次に、スクレイピングしたデータを扱う上での問題として、複数本(あるいは他のウイスキーボトル)をまとめた落札価格データが含まれていることがあげられます。
これを取り除かないと、1本あたりの相場値段を見誤ってしまいます。
そこでスクレイピングしたデータをもとに、①と②、それぞれの1本あたりの値段をざっくりと求め、フィルターにしました。(①は5000円以下、②は3000円以下)
価格でフィルターをかけた後も、1本以外のデータが含まれている場合は、価格条件を調整する必要があります。
#欲しい年代のボトルは、760ml。このため、件名に760mlが
#入っているもののみをスクリーニングする。
filter2 = '760'
data_2 = data[data.index.str.contains(filter2)]
#複数のボトルがセットになっている出品があるため、
#おおよそ一本あたりの相場でスクリーニングする。
data_2 = data_2[data_2['price'] <=5000]
filter3 = '750'
data_3 = data[data.index.str.contains(filter3)]
data_3 = data_3[data_3['price'] <=3000]
3.アウトプットを確認しよう
さっそく、サンプルしたデータ群から①1980年代前半頃のボトルと、②1980年代後半のボトルの1本あたりの落札相場情報を調べてみましょう。
今回は落札価格の相場を調べるには、どんなデータがあれば意思決定に使えるか?を考えつつ、出力し結果を眺めてみます。
下記は今回使ったコードは下記の通り。
print('水準1:',filter2)
print('平均値:', int(data_2.mean()))
print('中央値:', int(data_2.median()))
print('最高値:',int(data_2.max()))
print('最安値:', int(data_2.min()))
print('不偏標準偏差S:',int(data_2.std()))
print('\n')
print('水準2:',filter3)
print('平均値:', int(data_3.mean()))
print('中央値:', int(data_3.median()))
print('最高値:',int(data_3.max()))
print('最安値:', int(data_3.min()))
print('不偏標準偏差S:',int(data_3.std()))
出力結果は下記です。
水準1: 760
平均値: 3405
中央値: 3591
最高値: 5000
最安値: 890
不偏標準偏差S: 1069
水準2: 750
平均値: 2176
中央値: 2150
最高値: 3000
最安値: 1211
不偏標準偏差S: 732
4.入札しようかな?結果を意思決定に使おう
今回は、平均値・中央値と、最高値と最安値が分かれば、入札に参加するか、あるいは高値更新されたときに追いかけるか?意思決定できそうですね。
平均値と中央値はそれぞれ、下記となりました。
①1980年代前半頃のボトル・・・平均落札価格は3405円、中央値は3591円
②1980年代後半のボトル・・・平均落札価格は2176円、中央値は2150円
中央値と平均値がほぼ同値なので、極端に高いものや安いものは少なさそうです。結果から、より年代の古い①は約3500円、②は約2200円ということがわかりました。
この結果は、古い方のほうがさらに希少性があり根強いファンがいると思われるので想定通りです。(とはいえ、40年以上前のボトルなので、保管状況が悪いものを引いてしまったときの『鉄&トマトジュース』を楽しむことになるリスクはさらに高いです。)
個人的には①と②、そして現行版を比較すると楽しいです。
ハイボールにすると超豪華な味わいになります。
興味がわいた人には、是非両方落としてトライして欲しいです。
最後まで読んでいただきありがとうございました。
気が付くとプログラミングの勉強をしているのに、なぜかウイスキーが飲みたくなりましたか。わたしも、この文章を書きながらウイスキーが飲みたくなりました。
ここだけの話ですが、ウイスキーの肴には無印良品の『甘のしイカ』が最高です。なんと100円で買えるのですよ。
ちなみに購入のオマケは、抽出したデータのエクセルファイルへの出力に関してです。
(ソースコード等のGithubのリンクはこちら)
ここから先は
¥ 100
ご支援いただけると、とっても嬉しいです!