作ったもの
のポンタポイントでのお試し引換券交換対象商品一覧からポイントの交換効率(利率)を計算して得順に並び替えて静的ページを生成するPythonプログラムを作成しました。(画像は1月時点の交換商品です)
まとめと反省
-
スクレイピング初心者なので拙いところがたくさんあると思います。
-
本当はこのpythonプログラムを毎日自動で走らせるような仕組みを作りたかった…
- なぜかherokuにpushできなくて断念。これとか参考にしてもダメ…
- 交換したい日に狙い定めてローカルで実行してコミットしなきゃ反映されない
-
一応無事にそれなりの利率で交換できました。
-
公式ページに載っていても実際には既に交換終了だったりして、一番欲しかったもの(別の酒)はもらえませんでした
-
結論:普通にLawsonの公式アプリを使いましょう。
プログラムの説明
作ったプログラム(+生成されたhtmlページ、試行錯誤したipynb)はgithubに置いていますが、大規模なプログラムでもないので以下で説明していきます。
若干適当に作ってんなみたいなのは許してください
アドバイス等ありましたらドンドンお願いします
import requests, bs4
import datetime
url = 'http://www.lawson.co.jp'
today = datetime.datetime.today()
# redirect
before_redirect_info = requests.get(url + '/ponta/tsukau/otameshi/')
bs4Obj_br = bs4.BeautifulSoup(before_redirect_info.text, 'lxml')
meta_refresh = bs4Obj_br.select('meta')[0]
meta_cont = meta_refresh.attrs["content"]
redirect_url = meta_cont.split("URL=")[1]
今日までの交換対象商品をlawson公式サイトから取りたいので、urlとtoday変数に格納。
お試し引換券のサイトは毎月変わるので、遷移前のページのmeta refreshからリダイレクト先を取ってきてredirect_urlという変数に代入します。
# 現在の引き換え可能商品取得 + 利率追加
info_ar = requests.get(url + redirect_url)
info_ar.encoding = info_ar.apparent_encoding # ISO-8859-1が帰ってくる不具合をケア
bs4Obj_ar = bs4.BeautifulSoup(info_ar.text, 'lxml')
item_list_w_tag = bs4Obj_ar.find_all(class_="col-2 heightLineParent")[0].select("li")
item_list_w_tag_required = []
rate_list = []
for item_w_tag in item_list_w_tag:
if not "円引券" in str(item_w_tag):
date = item_w_tag.select("dd")[0].text
date_parsed = datetime.datetime.strptime(date, '%Y.%m.%d')
if today > date_parsed:
# 利率計算
txt = item_w_tag.find_all(class_="smalltxt")[0].text
price_str = ''.join(c for c in txt if c.isdigit())
price_int = int(price_str)
point_str = item_w_tag.select("dd")[1].text[:-1]
point_int = int(point_str)
rate = price_int / point_int
rate_list.append(rate)
# 利率タグ追加
bs4_tag_obj = item_w_tag.select("dl")[0]
tag = bs4Obj_ar.new_tag("dt")
tag.string = "利率"
bs4_tag_obj.append(tag)
tag2 = bs4Obj_ar.new_tag("dd")
tag2.string = "{0:.4f}".format(rate)
bs4_tag_obj.append(tag2)
# 画像のPATHを絶対PATHに
img = item_w_tag.select("img")[0]
img.attrs["src"] = url + img.attrs["src"]
item_list_w_tag_required.append(item_w_tag)
交換商品ページをスクレイピングしていきます。商品はcol-2 heightLineParent
というクラスの中に
その配列要素でforループ回して、毎月ある食パンと牛乳の〇〇円引券を最初のif文で弾いてます。
その後発券開始日dateを取ってきて今日より後のものは弾きます。
その後利率を計算して別のリストに入れて並び替えに備えます。
今回は抜き取ったhtmlをそのまま使ってhtmlを作成するので、利率タグを作っておくのと、画像PATHを絶対PATHにしておきます。
# 利率順に並び替え
zipped = zip(rate_list, item_list_w_tag_required)
zipped_sorted = sorted(zipped, key=lambda x:x[0], reverse=True)
rate_list, item_list_w_tag_sorted = zip(*zipped_sorted)
item_list_w_tag_sorted = list(item_list_w_tag_sorted)
# とりあえずのアレ
print("利率 商品名")
for item_w_tag in item_list_w_tag_sorted:
print(item_w_tag.select("dd")[-1].text, item_w_tag.select("p")[0].text)
利率順に並び替えていきます。二つの配列を同時に同じように並び変えるためにzipを用います。
# htmlにしてみる
file = open('test.html', 'w', encoding="utf-8")
html_head = """
<html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ポンタポイントローソン引き換えポイント効率順</title>
<style>
body {
background: #f0f7ff;
}
ul.bluetable {
display: table;
width:95%;
}
ul.bluetable > li:nth-child(2n+1) {
clear: both;
}
ul.bluetable > li {
display: table-cell;
float: left;
width: 43%;
height: 35em;
font-size: 18pt;
padding: 0.5em 0.5em;
margin: 0.5em 0.5em;
border: double 5px #4ec4d3;
}
</style>
<body>
<ul class="bluetable">
"""
file.write(html_head)
for item_w_tag in item_list_w_tag_sorted:
file.write(str(item_w_tag))
file.write("</ul></body></html>")
file.close()
最後にhtml出力します。足りないタグを補って、超初心者のcssも書いておいて出力します。
以上です。