#ツール紹介
ズバリ!新規性はJANコードを入力にAPIで情報を取ってくるとこです
せどりちゃんねるというタイトルで運営しております
ここでは特定のECサイトに対して自動リサーチをかけた結果をブラウザで閲覧できます
つまり電脳せどりそのものを自動化するツールとなっています.
通常,電脳せどりは人手で行うものですが,近年,本ツールのように電脳せどりを自動化するツールが出現してきました.
本せどりちゃんねるは私が株式会社Falcomさんから委託を頂き私個人で作成したものです.
表の見方
JAN | JANコード |
ASIN | ASINコード |
MR | モノレートにおける商品リンク |
Image | 商品の写真 |
DELTA | DELTA tracerにおける商品リンクと商品名 |
FABER | 仕入れ価格(この例ではFABER仕入れですが仕入先は動的に変わります) |
Amazon | 出品価格(本ツールではAmazon出品を想定しリサーチ時のAmazonにおける出品価格を提示) |
DIF | 価格差(仕入れ価格 - 出品価格)(-ほど利益が取れるってこと) |
R_DIF | 実利益(DIFからAmazonに出品した際の手数料10%を差し引いたもの) |
BR | 利益率(-実利益 / 仕入れ価格) |
R | 仕入れ店舗における商品リンク |
A | 出品店舗(Amazon)における商品リンク |
CG | 商品のカテゴリ |
Rank | Amazonにおけるカテゴリ別商品ランキング(尚,本インタフェースではRank順に仕入れ商品をソートしています |
ちなみにRankが10000をきる商品はほぼ即売れしてくれます
使い方としては,上から順に見て
RankとBRだけ見て即仕入れ!ではなく,
念のため,モノレートまたはDELTA tracerで
このように過去から現在における売れ行きをチェックして良さげなら仕入れる!
という流れです
この例では非常に良い売れ行きなので即仕入れ決定です!
仕入れ前にちゃんと商品の仕入れ価格と出品価格が合っているのか念のため
RとAのリンクで確認をとります.
Amazonの方は表示価格が若干安くなって(リサーチした瞬間とは変わって)しまいましたが
価格に間違いがなかったことを最後に確認してあとは購入!!
#大まかな流れ
以下をShellScriptで自動実行させてます
尚,本ツールでは「楽天」「ビックカメラ」「キャラアニ」「ケーズデンキ」等ほぼ全てのECサイトをリサーチ・インタフェースに反映可能となっています.
このQiitaにおける例では仕入先をFABERとします.
内容 | ファイル名 | Pythonのバージョン | |
---|---|---|---|
1 | 仕入れ先店舗の全商品のURL集合を,Seleniumでブラウザ操作させて取得 | 1_faber.py | 3.7 |
2 | 取得したURL(商品ページ)集合を入力に各商品価格,商品名,JANコードをWeb Scrapingで取得 | 2_search_jan.py | 3.7 |
3 | JANコードを入力にAmazon Product APIでAmazon上での出品価格,ASINコード,カテゴリ,カテゴリ別ランキング,商品ページリンク等を取得 | 3_api.py | 2.7 |
4 | 1-3で取得した全商品情報を用いて,UI(せどりちゃんねる,HTML)を生成. モノレート,デルタトレーサー,へのリンク等を追加 |
4_so.py | 3.7 |
#コード
###1.Seleniumを使った全商品URL取得と画面遷移
#coding:utf-8
PURPLE = '\033[35m'
RED = '\033[31m'
CYAN = '\033[36m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
UNDERLINE = '\033[4m'
import time
import sys
import random
import requests
from datetime import datetime
from selenium import webdriver
# Selectタグが扱えるエレメントに変化させる為の関数を呼び出す
from selenium.webdriver.support.ui import Select
from selenium.webdriver.chrome.options import Options
#ターゲットとなるECサイト・商品一覧1ページ目のURL
URL = 'https://shop.faber-hobby.jp/products/list.php?name=SALE1&disp_number=52&isStock=yes'
f = open('out.csv','w')
b = webdriver.Chrome('./chromedriver')
b.get(URL)
time.sleep(1)
flag = 0
while True:
classes = b.find_elements_by_class_name('itemname')
print(len(classes))
for i in list(classes):
a = i.find_elements_by_css_selector("a")
name = str(a[0].text.replace(',',''))
url = str(a[0].get_attribute("href"))
print(OKBLUE+UNDERLINE+url+ENDC)
print(name)
f.write(name+','+url+'\n')
q = b.find_element_by_class_name('navi')
a = q.find_elements_by_css_selector("a")
for i in a:
name = str(i.text)
url = str(i.get_attribute("href"))
if name == '次へ>>':
flag = 1
i.click()
else:
flag = 0
if flag ==0:
break
else:
time.sleep(1)
continue
f.close()
###2.Web Scrapingで商品名・価格・JANコードを抽出
#coding:utf-8
PURPLE = '\033[35m'
RED = '\033[31m'
CYAN = '\033[36m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
import requests
from time import sleep
a = open('out.csv','r')
b = open('out2.csv','w')
for i in a:
LINE = i.rstrip().split(',')
name = LINE[0]
url = LINE[1]
r = requests.get(url)
content = r.text
try:
price = content.split('<span id="price02_default" itemprop="price" content=\'')[1].split('\'')[0].replace(',','')
print ('【Price】-->¥'+price)
jan = content.split('<dd itemprop="gtin13">')[1].split('</dd>')[0]
print (OKGREEN+'【JAN】-->'+jan+ENDC)
b.write(jan+','+name+','+price+','+url+'\n')
except:
print ('Fault')
sleep(1)
a.close()
b.close()
###3. Amazon Product API でAmazon上の情報を取得
そもそもAmazonはスクレイピングを利用規約で全面禁止してるのでAPIを使う必要があります
#coding:utf-8
PURPLE = '\033[35m'
RED = '\033[31m'
CYAN = '\033[36m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
from amazon.api import AmazonAPI
from amazon.api import LookupException, AsinNotFound
from time import sleep
import codecs
import re
import requests
import shutil
import csv
ACCESS_KEY = "ここにACCESS_KEYを入れます"
SECRET_ACCESS_KEY = "ここにSEACRET_ACCESS_KEYを入れます"
ASSOCIATE_TAG = "ASSOCIATE_TAGを入れます"
error = 0
amazon = AmazonAPI(ACCESS_KEY, SECRET_ACCESS_KEY, ASSOCIATE_TAG, region="JP")
def download_img(url, file_name):
r = requests.get(url, stream=True)
if r.status_code == 200:
with open('image/'+ file_name, 'wb') as f:
r.raw.decode_content = True
shutil.copyfileobj(r.raw, f)
def amazon_api(JAN,name,price,url,counter):
try:
product = amazon.lookup(ItemId=JAN, IdType="EAN", SearchIndex="All")
if isinstance(product, list):
print 'NO amazon'
else:
asin = product.asin
title= product.title
amazon_price= product.price_and_currency[0]
group = product.product_group
rank = product.sales_rank
if amazon_price is None:
amazon_price = 0
reviews = product.reviews[1]
print 'ASIN: '+ OKBLUE +str(asin) + ENDC
print title
print 'price: '+str(amazon_price)
print 'group: '+str(group)
print 'ranking: '+str(rank)
image_url = 'http://images-jp.amazon.com/images/P/'+asin+'.09.THUMBZZZ.jpg'
image_name = asin + '.jpg'
#download_img(image_url, image_name)
mono_url = 'http://mnrate.com/item/aid/'+ asin
dif = int(price) - int(amazon_price)
r_dif = int(amazon_price)*0.1 + int(dif)
br = - r_dif/int(price)*100
print 'BR: '+PURPLE+ str(int(br)) +ENDC
amazon_url = 'https://www.amazon.co.jp/s/ref=nb_sb_noss?__mk_ja_JP=カタカナ&url=search-alias%3Daps&field-keywords=' + JAN
#save(JAN,asin,mono_url,price,amazon_price,dif,r_dif,br,url,amazon_url,group,rank)
strings = str(JAN)+','+str(asin)+','+str(mono_url)+','+str(name)+','+str(price)+','+str(amazon_price)+','+str(dif)+','+str(int(r_dif))+','+str(br)+','+str(url)+','+str(amazon_url)+','+str(group)+','+str(rank)+'\n'
b.write(strings)
except Exception as e:
#print e
if 'ASIN(s) not found:' in e:
counter = 7
print 'ASIN(s) not found:'
counter = counter +1
if counter > 1:
print 'Not found'
else:
sleep(0.5)
amazon_api(JAN,name,price,url,counter)
JAN = 0
count = -1
a = open('out2.csv','r')
b = open('out3.csv','w')
b.write('JAN,ASIN,MONO,NAME,PRICE,amazon_PRICE,DIF,R_DIF,BR,URL,amazonURL,Category,Ranking\n')
for line in a:
count = count + 1
LINE = line.rstrip().split(',')
JAN = LINE[0]
name = LINE[1]
price = LINE[2]
url = LINE[3]
counter = 0
print '\n\n'
if count >= 1:
print OKGREEN + str(count) + ENDC
print 'JAN: '+str(JAN)
amazon_api(JAN,name,price,url,counter)
sleep(0.3)
a.close()
b.close()
###4. UI作成
PythonでHTMLをはかせてます
使ってない部分(コメントアウト)がかなりあるので汚いです・・・
# coding: utf-8
PURPLE = '\033[35m'
RED = '\033[31m'
CYAN = '\033[36m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
import os
import csv
import sys
import codecs
from urlparse import urlparse #URL --> Domain
from time import sleep
import requests
import random
from operator import itemgetter #sort by factor
a = open('out3.csv','r')
b = open('data/page.html','w')
#b.write('<meta name="viewport" content="initial-scale=0.7">')
b.write('<div class="all">')
b.write('<head>\n')
b.write('<meta charset="utf-8">\n')
b.write('<link rel="shortcut icon" href="fig/icon.png" type="image/vnd.microsoft.icon">\n')
b.write('<TITLE>せどりちゃんねる</TITLE>\n')
b.write('<link rel="stylesheet" type="text/css" href="css.css">\n')
b.write('<script src="Java.js"></script>\n')
b.write('</head>\n')
b.write('<audio id="sound-file" preload="auto">\n<source src="fig/line.mp3" type="audio/mp3">\n</audio>\n')
#b.write('<div class="zentai">\n')
#b.write('<div class="title">\n')
#b.write('<div class="photo-show">\n<a href="https://line.me/R/ti/p/%40dnn4495i"><img height="36" border="0" alt="友だち追加" src="https://scdn.line-apps.com/n/line_add_friends/btn/ja.png"></a>\n')
#b.write('<div class="photo-show">\n<img src="fig/nth-of-type(1).png" width="200" height="200">\n<img src="fig/nth-of-type(2).png" width="200" height="200">\n<img src="fig/nth-of-type(3).png" width="200" height="200">\n<img src="fig/nth-of-type(4).png" width="200" height="200">\n<img src="fig/nth-of-type(5).png" width="200" height="200">\n<img src="fig/nth-of-type(6).png" width="200" height="200">\n<img src="fig/nth-of-type(7).png" width="200" height="200">\n<img src="fig/nth-of-type(8).png" width="200" height="200">\n</div>\n')
#b.write('<div class="title">')
b.write('<div class="pic">\n\
<img src="fig/falcom_logo.png" width="200" align="middle" alt="">\n\
</div>')
#<div class="front_amazon">\n\
#<marquee behavior="alternate" loop="-1"><font size="20" color="green"><img src="fig/icon2.png" width="90" height="90">\n</marquee>\n</div></div>\n')
#b.write('<marquee><font color="white" face="Comic Sans MS" size="4">Developed by Shuto K in 2017.</marquee>\n')
b.write('<div class="TITLE"><img src="fig/sedori.png" width="400" align="middle" alt=""></div>\n')
b.write('<div class="LINE">\n\
<a href="https://line.me/R/ti/p/%40dnn4495i"><img height="25" border="0" alt="友だち追加" src="https://scdn.line-apps.com/n/line_add_friends/btn/ja.png" width="70"></a>\n\
</div>\n'
)
b.write('<div class="QR">\n\
<img src="http://qr-official.line.me/L/KkQXNkcwpf.png" width="70">\n\
</div>\n'
)
b.write('<div class="LINE_here"><font size="2" color="white" style="font-weight:bold">LINE@はこちら!!↑</font></div>\n')
#b.write('<p width=500px><font size="4" color="white" width=500>\n\
#<br>We collect informations from online stores and compare these with Amazon. \n\
#<br>DIF means defference of the price between the online store and Amazon. \n\
#<br>R_DIF means real difference excepted commission in the case of selling on Amazon. \n\
#<br>Beneficial rate, Benefit is calculated by dividing R_DIF with the price.\n\
#<br>The interface provide you with beneficial information to resell on Amazon market.\n')
#b.write('<marquee><img src="fig/icon.png" width="30" height="30"><font color="white" size="3">Welcome to SedoriChannel<img src="fig/icon.png" width="30" height="30">Here, We compare the price of many items between "Rakuten ichiba" and "Amazon" and show items, which you should procure as soon as posssible, by sorting its beneficial rate from large to small.</marquee>\n')
b.write('</div></p>\n')
out_list = []
count = 0
for line in a:
count = count + 1
if count != 1:
LINE = line.rstrip().split(',')
count_list = len(LINE)
if count_list == 13 and LINE[12]!='None':
LINE[12] = int(LINE[12])#change +- of Beneficial_rate to sort from small to large
out_list.append(LINE)
out_list.sort(key=itemgetter(12))
b.write('<body bgcolor="#003366">\n')
#b.write('<div style="width:1605px; border-style:solid;border-width:1px;">\n')
#b.write('<div style="height:700px; width:1700px; overflow-x:scroll; position:relative;">\n')
#b.write('<div style="height:700px; width:1700px; overflow-x:scroll; position: absolute; top: 330px; left: 50px;">\n')
b.write('<div style="height:900px; width:1400px; overflow-x:scroll; position: relative; top:10px; left:50px;">\n')
b.write('<table border="5" cellspacing="0" bgcolor="white" width=1400 style="position: relative; top:0px; left:0px;">\n')
#b.write('<colgroup>\n\
#<col style="width:20px">\n\
#<col style="width:150px">\n\
#<col style="width:140px">\n\
#<col style="width:70px">\n\
#<col style="width:100px;>\n\
#<col style="width:400px">\n\
#<col style="width:120px">\n\
#<col style="width:120px">\n\
#<col style="width:80px">\n\
#<col style="width:80px">\n\
#<col style="width:85px">\n\
#<col style="width:60px">\n\
#<col style="width:60px">\n\
#<col style="width:100px">\n\
##<col style="width:100px">\n\
#</colgroup>\n')
b.write('<thead>\n')
b.write('<tr style="height:80px">\n')
b.write('<td align="center" bgcolor= "#d3d3d3">✔︎</td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold">JAN</td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold">ASIN</td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold"><img src="fig/mono.png" width="50"></td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold">Image</td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold"><img src="fig/delta.png" width="150"></td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold"><img src="fig/faber_logo.png" width="80"></td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold"><img src="fig/amazon2.png" width="80"></td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold">DIF</td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold">R_DIF</td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold">BR</td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold"><img src="fig/faber_logo.png" width="50"></td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold"><img src="fig/amazon.png" width="50"></td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold">CG</td>\n\
<td align="center" bgcolor= "#d3d3d3" style="font-weight:bold">Rank</td>\n')
#<td width=80 align="center" bgcolor= "#00ff80">EVAL</td>\n<td width=80 align="center" bgcolor= "#00ff80">NEW</td>\n<td width=80 align="center" bgcolor= "#00ff80">USED</td>\n')
b.write('</tr>\n')
b.write('</thead>\n')
#b.write('</table>\n')
#b.write('<div style="height:800px; width:1755px; overflow-x:scroll; position: absolute; top: 380px; left: 40px;">\n')
#b.write('<table position="center" border="5" cellspacing="0" bgcolor="white" width=1755>\n')
#b.write('<colgroup>\n\
#<col style="width:28px">\n\
#<col style="width:156px">\n\
#<col style="width:136px">\n\
#<col style="width:95px">\n\
#<col style="width:96px">\n\
#<col style="width:280px">\n\
#<col style="width:145px">\n\
#<col style="width:145px">\n\
#<col style="width:80px">\n\
#<col style="width:80px">\n\
#<col style="width:85px">\n\
#<col style="width:100px">\n\
#<col style="width:100px">\n\
#<col style="width:100px">\n\
#<col style="width:100px">\n\
#</colgroup>\n')
set_JAN = set()
counter = 0
for line in out_list:
JAN = line[0]
ASIN = line[1]
mono = line[2]
name = line[3]
#rev = line[9]
#eva = line[5]
price = line[4]
A_price = line[5]
dif = line[6]
R_dif = line[7]
BR = line[8]
url = line[9]
A_url = line[10]
group = line[11]
rank = line[12]
check = 0
#set_JAN = set()
if rank == 'None':
rank = 0
if int(rank) < 1000000 and JAN not in set_JAN:
check = 1
#new = line[13]
#used = line[14]
counter = counter + 1
mono_str = '<input type="button" onclick="window.open(\''+str(mono)+'\',\'_blank\')"value="MR" target="_blank" style="background-color:gold; font:11pt MS ゴシック; width:40px; height:40px" onmouseover="this.style.background=\'gray\'"onmouseout="this.style.background=\'gold\'">\n'
#mono_str = '<input type="button" onclick="location.href=\''+str(mono)+'\'"value="Link" target="_blank" style="b ackground-color:#ffff99" onmouseover="this.style.background=\'#99ccff\'"onmouseout="this.style.background=\'#ffff99\'"> \n'
url_str = '<input type="button" onclick="window.open(\''+str(url)+'\',\'_blank\')" value="R" style="background-color:gold; font:11pt MS ゴシック; width:40px; height:40px" onmouseover="this.style.background=\'gray\'"onmouseout="this.style.background=\'gold\'">\n'
A_url_str= '<input type="button" onclick="window.open(\''+str(A_url)+'\',\'_blank\')" value="A" style="background-color:gold; font:11pt MS ゴシック; width:40px; height:40px" onmouseover="this.style.background=\'gray\'"onmouseout="this.style.background=\'gold\'">\n'
b.write('<tr>\n')
if check == 1:
b.write('<td align="center" ><p><a onClick="sound()"><input type="checkbox"></a></p></td>\n')
#else:
#b.write('<td align="center" bgcolor="gray"><p><a onClick="sound()"><input type="checkbox"></a></p></td>\n')
if check == 1:
b.write('<td align="center" >'+str(JAN)+'</td>\n')
#else:
# b.write('<td align="center" bgcolor="gray">'+str(JAN)+'</td>\n')
if check == 1:
b.write('<td align="center" >'+str(ASIN)+'</td>\n')
#else:
# b.write('<td align="center" bgcolor="gray">'+str(ASIN)+'</td>\n')
if check == 1:
b.write('<td align="center" >'+str(mono_str)+'</td>\n')
#else:
# b.write('<td align="center" bgcolor="gray">'+str(mono_str)+'</td>\n')
if check == 1:
#image_name = ASIN + '.jpg'
#path = 'data/image/'+image_name
#if os.path.isfile(path) is not True:
# image_name = 'No-image.jpg'
b.write('<td align="center" height="60px"><img src=\'http://images-jp.amazon.com/images/P/'+ASIN+'.09.TZZZZZZZ.jpg\' width="60" height="50"></td>\n')
if check == 1:
if len(str(name)) > 100:
name = '{:.100}'.format(name)
b.write('<td width="300px"><a href="'+'https://delta-tracer.com/item/detail/jp/'+str(ASIN)+'" target="_blank">'+str(name)+'</a></td>\n')
#b.write('<td>'+str(name)+'</td>\n')
#else:
# b.write('<td bgcolor="gray">'+str(name)+'</td>\n')
if check == 1:
b.write('<td align="right"><font color="crimson" style="font-weight:bold" size="4">¥'+str(price)+'</td>\n')
#else:
# b.write('<td align="right" bgcolor="gray">'+str(price)+'</td>\n')
if check == 1:
b.write('<td align="right"><font style="font-weight:bold" size="4">¥'+str(A_price)+'</td>\n')
#else:
# b.write('<td align="right" bgcolor="gray">'+str(A_price)+'</td>\n')
if check == 1:
b.write('<td align="right" >'+str(dif)+'</td>\n')
#else:
# b.write('<td align="right" bgcolor="gray">'+str(dif)+'</td>\n')
if check == 1:
b.write('<td align="right" >'+str(R_dif)+'</td>\n')
#else:
# b.write('<td align="right" bgcolor="gray">'+str(R_dif)+'</td>\n')
if check == 1:
b.write('<td align="center" bgcolor= "#ffdead" style="font-weight:bold">'+str(int(float(BR)))+'</td>\n')
if check == 1:
b.write('<td align="center" >'+str(url_str)+'</td>\n')
#else:
# b.write('<td align="center" bgcolor="gray">'+str(url_str)+'</td>\n')
if check == 1:
b.write('<td align="center" >'+str(A_url_str)+'</td>\n')
#else:
# b.write('<td align="center" bgcolor="gray">'+str(A_url_str)+'</td>\n')
if check == 1:
b.write('<td align="center" >'+str(group)+'</td>\n')
#else:
# b.write('<td align="center" bgcolor="gray">'+str(group)+'</td>\n')
if check == 1:
b.write('<td align="right" ><font color="crimson" style="font-weight:bold" size="4">'+str(rank)+'</td>\n')
#else:
# b.write('<td align="right" bgcolor="gray">'+str(rank)+'</td>\n')
#if check == 1:
# b.write('<td align="right" >'+str(rev)+'</td>\n')
#else:
# b.write('<td align="right" bgcolor="gray">'+str(rev)+'</td>\n')
#b.write('<td align="center" >'+str(eva)+'</td>\n')
#b.write('<td align="center" >'+str(new)+'</td>\n')
#b.write('<td align="center" >'+str(used)+'</td>\n')
b.write('</tr>\n')
set_JAN.add(JAN)
#print jan
#print name
b.write('</div>\n')
b.write('</table>\n')
b.write('</div>\n')
#b.write('</div>\n')
#b.write('<font face="Comic Sans MS" size="5" color="white">Presented by Falcom Inc.</font>\n')
b.write('<div class="shuto"><marquee><font color="white" face="Comic Sans MS" size="4">Developed by Shuto Kawabata in 2017. All rights reserved.</marquee></div>\n')
b.write('</body>')
#b.write('</div><!--zentai-->\n')
b.write('</div><!--all-->\n')
a.close()
b.close()