まえおき
Amazon中国輸入で相乗り出品に手をだしてみました。(最近、色々と中途半端に手を出しています)
しかし、商品リサーチが予想以上に手間でした。。
これって絶対時給にすると損してるよな。と思い、できるところはシステム化しようと思い立ったのがキッカケです。
ヒューマン作業だと目ぼしい商品を一覧から見つけて、そこから商品詳細ページに遷移して、さらにFBA手数料ページを行き来して利益率を計算したり、グラフを確認したりと、一商品あたりに費やす時間が以外とかかるんですよね、、
できるところはシステム化してしまいましょう!
システム概要
■あらかじめピックアップしたASINリストから特定の条件に合致する商品のみ抜き出します。
※ASINリストをピックアップする手法は簡単です。後述してます。
■商品を絞り込むための条件は以下に定めました。
1. 一定の商品価格以上の商品(元値が低いと利益率が悪いため)
2.評価が一定以上の商品
3.直近の出品者数のが複数人いる商品(独占商品であるかのおおまかな判定)
4. 商品重量が2キロ未満(手数料の関係で2キロと決め打ち)
5. 30日間の販売数が一定数以下なら不要
6.予測利益率が一定以上の商品
利益額 = 販売価格 - 仕入れ単価 - FBA手数料 - 輸入経費)
利益率 = 利益額 / 販売価
※条件1, 2は検索時にソートしてしまっても問題ありません。
条件が合致した商品のリンク(Amazonの商品詳細ページ)をファイルに書きだします。
ピックアップした商品リンクを辿って最終チェックをしてください。
※ブランドチェックや独占商品など、画像をチェックしないといけないような項目はシステム化できないので以降はヒューマン作業となります。
事前準備
Keepa API
Keepa APIキーの発行が必要となります。これはプログラム側で使用します。
Amazon中国輸入をやってる人であればKeepa導入は済んでいる?と思うので詳細はここでは割愛しますが、Keepa APIキーの発行まで丁寧に詳細説明してくれてる動画 + サイトをシェアしておきます。
・Keepa導入方法参考動画
・Keepa導入方法参考サイト
ASINを抜き出す
あらかじめリサーチする商品のASINをAmazonの商品リストページから抜き出してファイルにまとめます。
ファイルにまとめたASINのリストをプログラムで読み込んで対象を絞っていくという流れになります。
ASINは抜き出せれば方法は問いませんが私は「AutoPagerize」+ 「ezASIN powered by eLister Pro」を使用しましたのでご紹介しておきます。
AutoPagerize
このツールでページャを一括表示します。
通常、商品一覧ページはページャで区切られてます。そのままでは10P分のASINを一括でを取得できません。
キャプチャだと10P分ありますが、これを一括表示してくれるのが「AutoPagerize」です。
AutoPagerizeはクロームの拡張アプリとなります。
・クロームwebストア
・概要 + 導入参照リンク
ezASIN powered by eLister Pro
このツールは表示されているページの商品のASINを抜き出してくれるツールです。
ツール名的に有料っぽいですが無料で使用できます。
こちらもクローム拡張アプリとなりますので導入しておきます。
・クロームwebストア
・概要 + 導入参照リンク
それぞれ有効な状態にしておきます。
抜き出したASINをファイルに保存
適当な検索ワードで商品検索を実施します。
ページを下までスクロールすれば「AutoPagerize」が稼働し、「page2」として次の検索結果ページが続いて表示されました。
検索結果のページャ数分だけ表示しきったら「ezASIN」を使用してページに表示されているASINを一括でコピーします。
右上にある「ezASIN」アイコンを押下しましょう。(黄色枠)
そうすると赤枠で囲んだダイアログが表示されます。
これでASINが一括コピーされたので、テキストファイルに張りつけて保存しましょう。
ファイル名は任意ですがここでは「asinlist.txt」としておきます。
B01LLES2VW
B00JTHF84S
B01J79JUNM
B01J79JX0W
B01J79K7PC
B01J79K388
B01J79JZAU
B01J79K5XQ
B01KRROGKA
B00BOP5PY6
・
・
・
後ほど実装するPHPファイルと一緒にサーバにアップしますが、一旦準備としては以上となります。
ここまで書き起こすのに結構な文字数を要しましたが、必要なツール類が揃ってしまえばほぼ準備自体に時間はかかりません。
商品の検索結果が多い場合、若干、一括表示に時間がかかりますがその場合は区切ってしまえばよいかと思います。
実装
プログラムはPHPで実装しました。
また殴り書きなのとセンスの問題で美しいソースコードではないのでそこはご了承ください。
ソース
実行ファイルは「keepa_api_sample.php」とし以下に保存しました。
/var/www/html/amazon-sample/keepa_api_sample.php
また、前段で触れたASINのリストファイル(asinlist.txt)は以下に保存しました。
/var/www/html/amazon-sample/io/asinlist.txt
全体
以下「keepa_api_sample.php」の内容となります。
<?php
// API キー
const API_KEY = "KeepaAPIキーを入力してください";
// API リンク
const API_URL = "https://api.keepa.com/product";
// 一回のバッジ実行で何行まで指定
const MAX_ROW = 80;
// ASINをコピペしたファイルを指定
const ASIN_LIST_FILE_PATH = "/var/www/html/amazon-sample/io/asinlist.txt";
// アウトプットするファイル名指定 ※可変にしないと実行の度に重複してしまいます。そのため定数でなく変数にしてます。
$output_file_path = "/var/www/html/amazon-sample/io/output" . date("YmdHis") . ".txt";
// ASINをコピペしたファイルからASINを配列で取得
$asin_list = returnTargetAsin();
// Keepa APIリンク組み立て
$target_asins_text = implode(",", $asin_list);
$url = API_URL . "?key=". API_KEY . "&domain=5&stats=90&rating=1&asin=" . $target_asins_text;
// Keepa API接続
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 1);
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,true);
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
$response = curl_exec($ch);
curl_close($ch);
// Keepa APIから戻り値取得 + 変換
$productsArray = json_decode($response, true)["products"];
if (empty($productsArray)) {
var_dump("トークン切れ");
exit();
}
// Keepaから取得した商品リストから絞り込む
filterAsinItem($productsArray, $output_file_path);
// 処理したファイル行を処理
$fp2 = file(ASIN_LIST_FILE_PATH);
foreach ($asin_list as $key => $value) {
// ファイル対象行削除
unset($fp2[$key-1]);
file_put_contents(ASIN_LIST_FILE_PATH, $fp2);
}
var_dump("処理完了!");
exit();
/**
* asinlist.txtからAsinリストを処理できる形にします
*/
function returnTargetAsin() {
// 処理
}
/**
* Keepaから取得した商品から条件に合致する商品をリンク化してテキストにアウトプットします
*
* @param array $items KeepaAPIから取得した商品のリスト
* @param string $output_file_path 対象となった商品をリンクとして書き出す際のファイルパス
*/
function filterAsinItem($items, $output_file_path) {
// 処理
}
2つのfunction(returnTargetAsin + filterAsinItem)は別途以下で内容張り詰けます。
※長くて見づらいため記載分けました。
returnTargetAsin
/**
* asinlist.txtからAsinリストを処理できる形にします
*/
function returnTargetAsin() {
$asin_list = array();
if (file_exists(ASIN_LIST_FILE_PATH) && is_file(ASIN_LIST_FILE_PATH)) {
$file = fopen(ASIN_LIST_FILE_PATH, "r");
$i = 0;
while (!feof($file)) {
// 指定の行以上は処理しない
if ($i >= MAX_ROW) {
break;
}
// 改行コードを削ってコードを取得
$line = fgets($file);
$asin_code = str_replace("\n", '', rtrim($line));
// 対象データと行数を保持しておく
$i++;
// 行末など、改行のみの場合があるため念のためチェック
if (empty($asin_code)) {
continue;
}
$asin_list[$i] = $asin_code;
}
fclose($file);
}
return $asin_list;
}
filterAsinItem
/**
* Keepaから取得した商品から条件に合致する商品をリンク化してテキストにアウトプットします
*
* @param array $items KeepaAPIから取得した商品のリスト
* @param string $output_file_path 対象となった商品をリンクとして書き出す際のファイルパス
*/
function filterAsinItem($items, $output_file_path) {
$res = "";
$importCost = 700; // 輸入コスト(一旦決め打ち)
foreach ($items as $product) {
try {
// 商品重量が2キロ以上は不要
if ($product["packageWeight"] >= 2000) {
continue;
}
// サイズチェック
// 縦(ミリでくるのでセンチに変換)
$packageHeightCenti = $product["packageHeight"] / 10;
// 横(ミリでくるのでセンチに変換)
$packageWidthCenti = $product["packageWidth"] / 10;
// 高さ(ミリでくるのでセンチに変換)
$packageLengthCenti = $product["packageLength"] / 10;
$size = $packageHeightCenti * $packageWidthCenti * $packageLengthCenti / 6000;
// 縦 * 横 * 高さ / 6000 >= 2 にならない大きさの商品は不要
if ($size >= 2) {
continue;
}
// 新品商品価格の履歴
$new_product_price = $product["csv"][1];
$new_product_price = $new_product_price[count($new_product_price)-1]; //最新
// 商品価格が1600円以下なら不要
if ($new_product_price <= 1600) {
continue;
}
// 30日間の販売数
$salesRankDrops30 = $product["stats"]["salesRankDrops30"];
// 90日間の販売数
//$salesRankDrops90 = $product["stats"]["salesRankDrops90"];
// 30日間の販売数が4以下なら不要
if ($salesRankDrops30 <= 4) {
continue;
}
// 販売価格
$sellePrice = $new_product_price;
// 仕入れ額(仮) ※ここでは甘めに1/3くらいを設定
$prediction_purchase_cost = floor($sellePrice / 3); // 切り捨て
// FBA手数料
$selleFee = 30; // 一旦決め打ち
$totalFbaFee = $product["fbaFees"]["pickAndPackFee"] + $product["fbaFees"]["storageFee"] + $selleFee;
// 予測利益額(利益額 = 販売価格 - 仕入れ単価 - FBA手数料 - 輸入経費)
$prediction_profit = $sellePrice - $prediction_purchase_cost - $totalFbaFee - $importCost;
// 予測利益率(利益率 = 利益額 / 販売価格)
$prediction_profit_par = ($prediction_profit / $sellePrice) * 100;
// 甘めに見積もった利益率が20%を下回るようなら不要
if ($prediction_profit_par < 20) {
continue;
}
// 新品の出品者の数の履歴
// 5日?間隔のデータを取得
$count_new = $product["csv"][11];
$new_product_seller_count_1 = empty($count_new[count($count_new)-1]) ? 0 : $count_new[count($count_new)-1]; //最新
//$new_product_seller_time_1 = ($count_new[count($count_new)-2] + 21564000) * 60;
$new_product_seller_count_2 = empty($count_new[count($count_new)-5]) ? 0 : $count_new[count($count_new)-5];
//$new_product_seller_time_2 = ($count_new[count($count_new)-6] + 21564000) * 60;
$new_product_seller_count_3 = empty($count_new[count($count_new)-11]) ? 0 : $count_new[count($count_new)-11];
//$new_product_seller_time_3 = ($count_new[count($count_new)-12] + 21564000) * 60;
// 直近の出費者の数をチェック
if ($new_product_seller_count_1 > 1 || $new_product_seller_count_2 > 1 || $new_product_seller_count_3 > 1) {
// nothing
} else {
continue;
}
// 評価の履歴 評価は0〜50の整数です(たとえば、45 = 4.5スター)
$rating = $product["csv"][16];
$rating_1 = $rating[count($rating)-1]; //最新
// 直近の評価が3.5以下なら不要
if ($rating_1 <= 3.5) {
continue;
}
// 結果
$res .= $product["title"] . "\n";
$res .= "https://www.amazon.co.jp/dp/" . $product["asin"] . "\n\n";
} catch (\Throwable $e) {
continue;
}
}
// 対象リストをファイルへ書き出しする
if (empty($res) === false) {
var_dump($res);
$fp = fopen($output_file_path, "a");
fwrite($fp, $res);
fclose($fp);
}
}
説明
実行 / 確認
コンソールからPHPコマンドで実行、もしくはcronで実行します。
実行するとoutput_file_pathで指定したファイルパスにテキストが生成されますので絞り込んだ商品が確認できます。
$output_file_path = "/var/www/html/amazon-sample/io/output" . date("YmdHis") . ".txt";
一度に処理できるASINについて
KeepaAPIの仕様上、一度に取得できる商品数が100件までとなってます。
またAPIの消費ポイントの都合で一回の実行につき80件を指定してます。
※適宜値に変更してください
const MAX_ROW= 80;
KeepaAPIの仕様把握については以下サイト様にお世話になりました。
KeepaAPIについて
APIトークン制なので実行を短時間で連続実行すると一時的に取得できなくなります。
トークンは分単位で5トークン回復します。
一商品あたり、取得する商品の項目情報により商品するポイントは異なるようです。
自身のAPIキーや所有トークンはKeepaサイトにログインして確認できます
プログラム内で指定するAPIキーもここから確認できます。
※以下画像の黒く塗りつぶされているところにAPIキーが表示されてます。
const API_KEY = "KeepaAPIキーを入力してください";
備考
トークンを無駄に消費しないように、一度検索したことのあるASINは再度検索しない。など実装もひと手間いれるだけで実装できます。
今回は端折りましたが、機会があればこちらもご紹介していこうと思います。
商品の対象条件についてもまだまだ絞れる気がしますがしますが、とりあえず今回はメジャーなところまでとしました。
今回は備忘録として自分用に残したというのが第一目的となっております。
プログラムの結果についての責任は持てませんので自己責任で参考とするようお願いいたします。