ヤフオクの商品説明に他の出品商品の画像を表示し、他の商品へ誘導しようと思いました。
しかし、imgタグを使って商品説明に表示できる画像の枚数には制限があります。
そこでpythonとヤフオクAPIを使い、複数の商品サムネイル画像を合成し1枚の画像にして商品説明に表示することにしました。
環境
- MacOS Sierra
- python3.5.2
- (Heroku上でも動作することを確認しています)
ソース
config.ini
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[yauc] search = http://auctions.yahooapis.jp/AuctionWebService/V2/search? appid = yourappid [image] # 任意のフォントファイルを指定する font = hiragino-kaku-gothic-w3.tcc # FTPサーバーにアップロードする場合は下記も設定する。 [ftp] ftp_host = ftp.********.lolipop.jp ftp_user = lolipop.jp-******** ftp_pass = ******** ftp_path = /path/to/upload/directory |
create-yauc-image.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# -*- coding: utf-8 -*- import configparser import codecs import sys import urllib import urllib.request # opener import urllib.parse # urlencode import json import io from PIL import Image from PIL import ImageDraw from PIL import ImageFont import wget import os import textwrap import datetime from ftplib import FTP def yaucapi_search(query, category, seller, f): """ 指定条件でのヤフオクAPIレスポンスを取得 @param query 検索キーワード @param category カテゴリコード @param seller 出品者のヤフオクID @param f 検索対象の指定 0x2 :「タイトル+ストア用検索キーワード」で検索 0x4 :「タイトル+本文」で検索 0x8 :「タイトルのみ」で検索 @return ヤフオクAPIレスポンス """ config = configparser.ConfigParser() # config.read('config.ini') config.readfp(codecs.open("config.ini", "r", "utf8")) url = config["yauc"]["search"] appid = config["yauc"]["appid"] params = urllib.parse.urlencode( {'appid': appid, 'output':"json", 'query':query, 'category':category, 'sort':'end', 'order':'a', 'seller':seller, 'f':f}) response = urllib.request.urlopen(url + params) return response.read().decode('utf-8').lstrip("loaded(").rstrip(")") def add_text(imgurl, title, price, endtime): """ 画像にテキストを追加する @param imgurl テキストを追加する元画像 @param title 商品名 @param price 現在価格 @param endtime 即決価格 @return テキスト追加後の画像 """ config = configparser.ConfigParser() config.readfp(codecs.open("config.ini", "r", "utf8")) font = config["image"]["font"] #外部 URL から読み込み filePointer = urllib.request.urlopen(imgurl) data = filePointer.read() filePointer.close() # f_name = wget.download(imgurl) #PILで加工 img = Image.open(io.BytesIO(data)) #キャンバスの作成 canvas = Image.new('RGB', (img.size[0]+40, img.size[1]+100), (255,255,255)) #キャンバスに貼り付け canvas.paste(img,(20,10)) img = canvas #テキストの挿入 draw = ImageDraw.Draw(img) draw.font = ImageFont.truetype(font, 10) title = textwrap.fill(title, 25) text_height = img.size[1]-80 def textHeight(line): return text_height + 14*line draw.text((5, textHeight(0)), title, (0, 176, 240)) draw.text((5, textHeight(3)), "現在価格:", (0, 0, 0)) draw.text((55, textHeight(3)), "{0:,d}".format(int(price.replace(".00","")))+"円", (254,103,135)) endtime = datetime.datetime.strptime(endtime, '%Y-%m-%dT%H:%M:%S+09:00') draw.text((5, textHeight(4)), "終了時刻:", (0, 0, 0)) draw.text((55, textHeight(4)), endtime.strftime('%y/%m/%d/ %H:%M:%S'), (254,103,135)) return img def merge_image(imgs, column, row): """ 複数の画像をcolumn x row のレイアウトで合成する @param imgurl テキストを追加する元画像 @param column 列の数 @param row 行の数 @return 合成後の画像 """ if len(imgs) != 0: width = imgs[0].size[0] height = imgs[0].size[1] canvas = Image.new('RGB', (width*column, height*row), (255,255,255)) print(width, height) else: canvas = Image.new('RGB', (173*column, 200*row), (255,255,255)) for i, img in enumerate(imgs): w = (width * i) % (width * column) h = height * int(i / column) print(w,h) canvas.paste(img,(w,h)) return canvas def do_json(s, column, row): """ ヤフオクAPIレスポンスからcolumn x row個の商品データを取得し、1枚の画像を生成する @param s ヤフオクAPIレスポンス @param column 列の数 @param row 行の数 @return 画像データ """ data = json.loads(s) item_list = [] numofitem = int(data["ResultSet"]["@attributes"]["totalResultsAvailable"]) # 検索結果の商品数が2つ以上ならListでレスポンスが得られるので、場合分け if numofitem > 1: item_list = data["ResultSet"]["Result"]["Item"] elif numofitem == 1: item_list.append(data["ResultSet"]["Result"]["Item"]) else: item_list = [] #空のディクショナリを作る imgs = [] for item in item_list: try: title = item["Title"] imgurl = item["Image"] price = item["CurrentPrice"] endtime = item["EndTime"] imgs.append(add_text(imgurl, title, price, endtime)) # 必要な商品数に達したらbreak if len(imgs) >= row * column: break; except Exception as e: print('=== エラー内容 ===') print('type:' + str(type(e))) print('args:' + str(e.args)) print('message:' + e.message) print('e自身:' + str(e)) return None # 個々の画像を clumn x row で並べて1枚の画像に合成 img = merge_image(imgs, column, row) return img def upload_image_ftp(imgdict): """ 画像をFTPサーバーにアップロードする @param imgdict 画像のファイル名と画像の辞書 {imgname:imgdata, ...} """ config = configparser.ConfigParser() config.readfp(codecs.open("config.ini", "r", "utf8")) ftp_host = config["ftp"]["ftp_host"] ftp_user = config["ftp"]["ftp_user"] ftp_pass = config["ftp"]["ftp_pass"] ftp_path = config["ftp"]["ftp_path"] ftp = FTP(ftp_host) #ホスト名 ftp.set_pasv("true") ftp.login(ftp_user, ftp_pass) #ログインIDとパス for imgname,img in imgdict.items(): if img is None: continue fp = io.BytesIO() img.save(fp, format='JPEG', quality=100, optimize=True) fp.seek(0) ftp.storbinary("STOR "+ftp_path+imgname, fp) #ホスト側のディレクトリ fp.close() ftp.close() if __name__ == '__main__': json_str = yaucapi_search("ノートパソコン", 2084039759, "yoursellerID", "0x04") img = do_json(json_str, 4, 2) img.save('img1.jpg') # FTPにアップロードする場合 は下記のコメントアウトを解除 # imgdict = {} # imgdict['img1.jpg'] = img # json_str = yaucapi_search("デスクトップ", None, "yoursellerID", "0x08") # img = do_json(json_str, 4, 2) # imgdict['img2.jpg'] = img # upload_image_ftp(imgdict) # 複数画像をアプロード可能 |
使い方
ソースの保存
上記2つのソースをそれぞれ任意の同一フォルダに保存してください。
ファイル名は下記のとおりとします。
- config.ini
- create-yauc-image.py
config.ini の修正
appid
Yahoo! JAPAN WebサービスのアプリケーションIDを設定します。
アプリケーションIDの取得方法は デベロッパーネットワークトップ > ご利用ガイド を参照してください。
font
フォントファイルへのパスを指定します。
OSにはフォントファイルが保存されていますので、お好みのフォントファイルをコピーしてconfig.iniと同じフォルダに保存してください。
ファイル名に日本語(2byte文字)が含まれている場合は、半角英数字(1byte文字)に変名しておいたほうがよいかもしれません。
Mac のフォントファイル格納場所
1 |
/System/Library/Fonts/ |
ここにフォントファイルがあります。
Windows のフォントファイル格納場所
フォントのインストール(Windows 10/8/7/Vista)を参考にしてください。
ftp_host
FTPサーバーへアップロードする場合は、FTPサーバー名を設定します。
ftp_user
FTPサーバーへアップロードする場合は、FTPサーバーのユーザー名を設定します。
ftp_pass
FTPサーバーへアップロードする場合は、FTPサーバーのパスワードを設定します。
ftp_path
FTPサーバーへアップロードする場合は、FTPサーバーのアップロード先ディレクトリを設定します。
create-yauc-image.py の修正
1 2 3 4 |
if __name__ == '__main__': json_str = yaucapi_search("ノートパソコン", 2084039759, "yoursellerID", "0x04") img = do_json(json_str, 4, 2) img.save('img1.jpg') |
の部分をお好みに修正します。
1 |
json_str = yaucapi_search("ノートパソコン", 2084039759, "yoursellerID", "0x04") |
ヤフオクAPIにリクエストし、そのレスポンスをJSON形式で取得します。
検索条件は下記の通りに指定します。
デベロッパーネットワークトップ > オークション > 検索 も参考にしてください。
- 第一引数:検索キーワード
- 第二引数:カテゴリID
- カテゴリIDの調べ方はヤフオクAPIのための親カテゴリIDの調べ方を参考にしてください。
- 第三引数:出品者のヤフオクID
- 第四引数:検索範囲
- 0x2 :「タイトル+ストア用検索キーワード」で検索
- 0x4 :「タイトル+本文」で検索
- 0x8 :「タイトルのみ」で検索
生成した画像を保存したい場合 img.save()
1 |
img = do_json(json_str, 4, 2) |
上記の例では、do_json で 4列x2行の合成画像を生成します。
1 |
img.save('img1.jpg') |
これで img1.jpg というファイル名で保存されます。
生成した画像を表示したい場合 img.show()
1 |
img.show() |
これで 生成した画像が表示されます。
FTPサーバーにアップロードする場合
1 2 3 4 5 6 7 8 9 10 11 12 |
if __name__ == '__main__': json_str = yaucapi_search("ノートパソコン", 2084039759, "yoursellerID", "0x04") img = do_json(json_str, 4, 2) img.save('img1.jpg') # FTPにアップロードする場合 は下記のコメントアウトを解除 imgdict = {} imgdict['img1.jpg'] = img json_str = yaucapi_search("デスクトップ", None, "yoursellerID", "0x08") img = do_json(json_str, 4, 2) imgdict['img2.jpg'] = img upload_image_ftp(imgdict) # 複数画像をアプロード可能 |
1 |
imgdict = {} |
FTPへアップロードするための情報を保存する辞書オブジェクトを定義します。
1 |
imgdict["img1.jpg"] = img |
辞書オブジェクトは、{ “画像ファイル名” : 画像オブジェクト } となるように保存します。
1 |
upload_image_ftp(imgdict) |
FTPサーバーにアップロードします。
実行
1 |
python create-yauc-image.py |
ターミナルから create-yauc-image.py を実行してください。
おわりに
私は、Herokuにデプロイして、1時間毎に実行するようにしています。そうすることで、常に最新の情報を商品説明に表示することができます。
yaucapi_searchをカスタマイズすることで、検索条件を増やすことができます。お試しいただけたらと思います。
参考
下記のサイトを参考にさせていただきました。ありがとうございます。