はじめに
今までの要素を組み合わせて、せどり商品選定の自動化ワークフローの完全版を作成します。
ワークフロー完全版の全体図は下記となります。
<ワークフロー全体図>
本ワークフローを実行すると、下記ようなCSVファイルが生成されます。
<CSVファイルのサンプル>
CSVファイルの中身は、ChatGPTが選定した商品をYahoo!ショッピング、楽天市場、eBayで検索し、その結果が記録されています。CSVファイルの各カラムには下記の情報が記載されています。
- キーワード
各ECサイトで検索時に使用した単語 - 商品名
検索でヒットした商品のタイトル - 店舗名
出品店舗・ショップ名 - 商品説明
商品の短い説明文。説明が取得できない場合は空欄 - 価格
表示価格の数値。eBayはドル価格 - 検索サイト
どのECサイトの検索結果を示す(Yahoo/楽天/eBay) - 商品ページ
商品詳細ページのURL。 - 検索日時
その行(商品)を取得した時刻(JST)
ワークフローの動作概要
作成するワークフローの動作概要は下記となります。
事前に用意しておく情報
各サイトのAPI
本手順でワークフローを作成する前に、下記の情報を用意しておく必要があります。
- eBayのアクセストークン、リフレッシュトークン、認証コード
※認証コードは、ClientIDとClientを組み合わせてBase64コード - YahooショッピングのAPIキー
- 楽天市場のAPIキー
上記の情報の取得方法は下記を参照してください。
n8nでせどり商品選定の自動化③(各ECサイトのAPI取得) – リラックスした生活を過ごすために
ebayのアクセストークンを保存したCSVファイル
ebayのアクセストークンの有効期限は120分です。
アクセストークンはeBayのデベロッパーサイトにアクセスすれば取得可能ですが、ワークフローを実行する前に、毎回取得するのは手間が掛かります。
アクセストークンは、リフレッシュトークンを用いることで取得することも可能です。
ワークフロー内でebayのアクセストークンの有効期限を確認し、有効期限が切れそうな場合はリフレッシュトークンでアクセストークンを取得するようにしています。
アクセストークンの有効期限、アクセストークンをリフレッシュトークンで取得するための情報を下記のCSVファイルに保存します。
<CSVファイルのパス>
C:\せどり商品検索の自動化\アクセストークン\ebay_アクセストークン.csv
「ebay_アクセストークン.csv」には下記カラムで情報を記載してください。
- access_token:取得したアクセストークン
- expires_in:7200
- token_type:User Access Token
- token_acquired_at:取得した時刻
- auth_basic:Basic 取得した認証コード
- refresh_token:取得したリフレッシュトークン
「auth_basic」には認証コードを設定します。
認証コードを記入する際は「Basic VHN1~~」のように「Basic」を認証コードの前に付けてください。
<ebay_アクセストークン.csvのサンプル>
ワークフローの作成手順
「ebay_アクセストークン.csv」を「C:/せどり商品検索の自動化/アクセストークン/ebay_アクセストークン.csv」に配置した前提で進めます。
ワークフローの作成手順
ワークフローの作成手順は下記を参照してください。
n8nでせどり商品選定の自動化①(n8nの実行環境の構築) – リラックスした生活を過ごすために
「ebayトークン管理」の作成手順
1.「Add first step…」をクリックします
2.「Search nodes…」に「Read」を入力し、「Read/Write Files from Disk」をクリックします。
3.「Read Files(s) From Disk」をクリックする
4.追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:ebayアクセストークン読み込み1
- File(s) Selector:C:/せどり商品検索の自動化/アクセストークン/ebay_アクセストークン.csv
※ファイルパスは「¥」ではなく「/」で区切ります。
5.「ebayアクセストークン1読み込み」の「+」をクリックし「Search nodes…」に「Extract」を入力し、「Extract from File」をクリックします。
6.「Extract from CSV」をクリックします。
7.追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:ebay アクセストークン抽出1
- Add option:Header RowをOn
8.「ebay アクセストークン抽出1」の「+」をクリックし「Search nodes…」に「if」を入力し、「If」をクリックします。
9.Ifノードでは「ebay アクセストークンを取得した時刻から何分経ったか」を計算し、しきい値と比較してTrue/Falseで処理を分岐しています。
ebay アクセストークンの有効期限は120分です。現在の時刻とアクセストークンを取得した時刻の差分(取得からの経過時間)が110分以内であれば、Trueと判定しています。True側は後続処理に進みます。False側はリフレッシュトークンで新しいアクセストークン取得の処理に進みます。
追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:ebayアクセストークン取得日時の判定
- fx:{{ Math.floor((Date.now() – Date.parse($json.token_acquired_at)) / 60000) }}
- is less than or equal to
- 110
10.「ebayアクセストークン取得日時の判定」の「false」の「+」をクリックし「Search nodes…」に「http」を入力し、「HTTP Request」をクリックします。
11.HTTP Requestノードでは「ebayのリフレッシュトークンを使って access_token を再発行する」を行います。
追加したノードに下記を適用して「Back to canvas」をクリックします。
- ebayアクセストークン取得
- Method:POST
- URL:https://api.ebay.com/identity/v1/oauth2/token
- Authentication:None
- Send Header:ON
- Specify Headers:Using Fields Below
- Header Parameters
- Name:Content-Type
- Value:application/x-www-form-urlencoded
※「Add Parameter」をクリックすると項目を追加できます - Name:Authorization
- Value:{{ $json.auth_basic }}
- Send Body:ON
- Body Content Type:Form Urlencoded
- Specify Body:Using Fields Below
- Body Parameters
- Name:grant_type
- Value:refresh_token
※「Add Parameter」をクリックすると項目を追加できます - Name:refresh_token
- Value:{{ $json.refresh_token }}
12.「ebayアクセストークン取得」の「+」をクリックし「Search nodes…」に「code」を入力し、「Code」をクリックします。
13.ebayアクセストークンの取得時刻を設定します。
追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:ebayアクセストークン取得時刻を追加
- JavaScript:下記を記載
clientId、clientSecret、refreshTokenは事前に取得しておいてください。
// === 設定 ==========================
const clientId = 'XXXXXX-MySedori-PRD-XXXXX-XXXXXX';
const clientSecret = 'PRD-XXXXXX-XXXXX-XXXXXX-XXXXX-XXXXX';
const refreshToken = 'v^1.1#i^XXXXXXXXXXXXXXXXXX';
// ==================================
// 既存のデータ(HTTP Request のレスポンス)を取得
const inputData = items[0]?.json ?? {};
// JST時刻を付与(yyyy-MM-dd HH:mm:ss)
const jstTime = new Date(Date.now() + 9 * 60 * 60 * 1000)
.toISOString().replace('T', ' ').substring(0, 19);
// Basic 認証文字列を生成("Basic xxxxxx")
const auth_basic = 'Basic ' + Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
// 出力データを作成
const outputData = {
...inputData, // access_token / expires_in など元の応答
token_acquired_at: jstTime, // 取得時刻(JST)
auth_basic, // Basic 認証ヘッダ値
refresh_token: refreshToken // リフレッシュトークン
};
// 1件で返す
return [{ json: outputData }];
14.「ebayアクセストークン取得時刻を追加」の「+」をクリックし「Search nodes…」に「convert」を入力し、「Convert to File」をクリックします。
15.「Convert to CSV」をクリックします。
16.ebayアクセストークンと取得時刻をCSV形式に変換します。
追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:ebayアクセストークンのCSV形式に変換
- Options:Add option」をクリックして下記を追加
- Delimiter: ,
17.「ebayアクセストークンのCSV形式に変換」の「+」をクリックし「Search nodes…」に「write」を入力し、「Read/Write Files from Disk」をクリックします。
18.「Read File(s) From Disk」をクリックします。
19.CSV形式のデータを保存します。
追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:ebayアクセストークンの保存
- Operationdw」で「Write File to Disk」を選択
20.「ebayアクセストークンの保存」の右「●」をドラックして「ebayアクセストークン読み込み1」の左「●」でドロップし、線を繋げます。
以上で「ebayトークン管理」の作成手順は完了です。
「商品検索候補の生成」の作成手順
1.AI Agentによる商品選定のフローを作成します。
作成方法は下記を参照してください。
n8nでせどり商品選定の自動化②(AI Agentによる商品選定) – リラックスした生活を過ごすために
「Yahooショッピングの商品検索」の作成手順
1.「JSON形式のデータを配列に変換」の右「●」をクリックし「Search nodes…」に「loop」を入力し、「Loop Over Items(Split in Batches)」をクリックします。
2.ループ設定の変更はありません。
追加したノードの「Back to canvas」をクリックします。
3.不要な「Replace Me」ノードをクリックし「ゴミ箱」アイコンをクリックして削除します。
4.不要なループを削除します。
「Loop Over Items」の下から出ているループにカーソルを合わせて「ゴミ箱」をクリックします。
5.Yahooショッピングで商品検索を実行するためのノードを作成します。
「Loop Over Items」の下「+」をクリックし「Search nodes…」に「http」を入力し、「HTTP
Request」をクリックします。
6.YahooショッピングのAPI検索設定を行います。
追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:Yahoo API検索
- URLに下記を入力します。
https://shopping.yahooapis.jp/ShoppingWebService/V3/itemSearch?appid=【取得したYahoo API】&query={{ encodeURIComponent($json.キーワード) }}&results={{ $json.検索数 }}
※Yahoo APIの取得方法は前回の記事を参照してください。
以上で「Yahooショッピング」の商品検索の作成手順は完了です。
「楽天市場の商品検索」の作成手順
1.楽天市場で商品検索を実行するためのノードを作成します。
「Loop Over Items」の下「+」をクリックし「Search nodes…」に「code」を入力し、「Code」をクリックします。
2.楽天市場でAPI検索を行うための前処理を行います。
楽天市場のAPI検索で「iphone 12」を検索すると失敗します。
「iphone 12」を単語単位で分解すると「キーワード」+「スペース」+「数字」の形式になっています。この「キーワード」+「スペース」+「数字」の形式だと、楽天市場のAPI検索は失敗してしまいます。
楽天市場のAPI検索をする際は「スペース」を削除した「キーワード」+「数字」に変換する必要があります。
<失敗するキーワードの例>
- iphone 12
- Mx Anywhere 3
<成功するキーワードの例>
- iphone12
- MxAnywhere3
追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:楽天API検索用キーワード生成
- JavaScriptに下記を入力します。
// 楽天API用:「スペース+数字」問題の解決
const originalKeyword = $json.キーワード;
// 「アルファベット/カタカナ + スペース + 数字」を「アルファベット/カタカナ + 数字」に変換
const fixedKeyword = originalKeyword
.replace(/([a-zA-Z\u30A0-\u30FF])\s+(\d)/g, '$1$2') // Master 3 → Master3
.replace(/\s+/g, ' ') // 余分な空白を整理
.trim();
return items.map(item => ({
json: {
...item.json,
fixedKeyword: fixedKeyword
}
}));
// 楽天API用:「スペース+数字」問題の解決
const originalKeyword = $json.キーワード;
// 「アルファベット/カタカナ + スペース + 数字」を「アルファベット/カタカナ + 数字」に変換
const fixedKeyword = originalKeyword
.replace(/([a-zA-Z\u30A0-\u30FF])\s+(\d)/g, '$1$2') // Master 3 → Master3
.replace(/\s+/g, ' ') // 余分な空白を整理
.trim();
return items.map(item => ({
json: {
...item.json,
fixedKeyword: fixedKeyword
}
}));
3.楽天市場で商品検索を実行するためのノードを作成します。
「楽天API検索用キーワード生成」の「+」をクリックし「Search nodes…」に「http」を入力し、「HTTP Request」をクリックします。
4.楽天市場のAPI検索設定を行います。
追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:楽天API検索
- URLに下記を入力します。
https://app.rakuten.co.jp/services/api/IchibaItem/Search/20220601?format=json&keyword={{ encodeURIComponent($json.fixedKeyword) }}&hits={{ $json.検索数 }}&applicationId=【取得した楽天API】/
※楽天APIの取得方法は前回の記事を参照してください。
以上で「楽天市場の商品検索」の作成手順は完了です。
「ebayの商品検索」の作成手順
1.ebayでAPI検索を行うための前処理を行います。
「Loop Over Items」の下「+」をクリックし「Search nodes…」に「read」を入力し、「Read/write Files from Disk」をクリックします。
2.「Read Files(s) From Disk」をクリックします。
3.追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:ebayアクセストークン読み込み2
- File(s) Selector:C:/せどり商品検索の自動化/アクセストークン/ebay_アクセストークン.csv
4.「ebayアクセストークン読み込み2」の「+」をクリックし「Search nodes…」に「Extract」を入力し「Extract from File」をクリックします。
5.「Extract from CSV」をクリックします。
6.追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:ebay アクセストークン抽出2
- Add option:Header Row」を選択
7.ebayAPI検索で必要なキーワードとAPI情報を結合します。
「Loop Over Items」の下「+」をクリックし「Search nodes…」に「merge」を入力し、「Merge」をクリックします。
8.追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:ebayAPI検索用の情報生成
- Mode:Combine
- Combine by:Position
9.抽出したebayアクセストークンとキーワードを結合します。
「ebay アクセストークン抽出2」の「●」をドラックし「ebayAPI検索用の情報生成」の「Input2」にドロップします。
10.ebayで商品検索を実行するためのノードを作成します。
「ebayAPI検索用の情報生成」の「+」をクリックし「Search nodes…」に「http」を入力し、「HTTP Request」をクリックします。
11.ebayのAPI検索設定を行います。
追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:ebayAPI検索
- URLに下記を入力します。
https://api.ebay.com/buy/browse/v1/item_summary/search
- Send Query Parameters:On
- Name:q
- Value:{{ $json[‘keyword’] }}
- 「Add Parameter」をクリック
- Name:limit
- Value:{{ $json[‘検索数’] }}
- Send Headers:On
- Name:Authorization
- Value:Bearer {{ $json[‘access_token’] }}
※ebayAPIの取得方法は前回の記事を参照してください。
以上で「ebayの商品検索」の作成手順は完了です。
3サイトの検索結果の結合
1.各サイトのAPI検索で取得した情報をを結合します。
「Loop Over Items」の下「+」をクリックし「Search nodes…」に「merge」を入力し、「Merge」をクリックします。
2.追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:各サイトの検索結果のまとめ
- Number of Inputs:4
3.「Yahoo API検索」「楽天API検索」「ebayAPI検索」の「●」をドラックし「各サイトの検索結果のまとめ」のInput2~4に順々にドロップします。
4.取得した各サイトの検索結果を下記のフォーマットに整理するノードを作成します。
- キーワード、商品名、店舗名、商品説明、価格、価格サイト、商品ページ、検索日時
「各サイトの検索結果のまとめ」の「+」をクリックし「Search nodes…」に「code」を入力し、「Code」をクリックします。
5.追加したノードに下記を適用して「Back to canvas」をクリックします。
- コード名:取得情報の整理
- 「JavaScript」に下記を設定
const results = [];
// ---------- キーワード抽出ユーティリティ ----------
function pickKeywordFromJson(j) {
const str = v => (typeof v === 'string' ? v.trim() : null);
const cands = [
j['キーワード'],
j.keyword,
j.request?.query, // Yahoo等
j.request?.q, // eBay等
j.request?.params?.keyword, // 楽天等
j.request?.params?.q,
j.query,
j.q,
j.input?.keyword,
j.input?.['キーワード'],
];
for (const v of cands) {
const s = str(v);
if (s) return s;
}
// request が配列の場合の保険
if (Array.isArray(j.request)) {
for (const r of j.request) {
const s = str(r?.query || r?.q || r?.params?.keyword || r?.params?.q);
if (s) return s;
}
}
return null;
}
// 全アイテムを走査して最初に見つかったキーワードを採用
let keyword = null;
for (let i = items.length - 1; i >= 0; i--) { // 後ろから探す
const k = pickKeywordFromJson(items[i].json || {});
if (k) {
keyword = k;
console.log('Keyword found at index', i, ':', k);
break;
}
}
if (!keyword) keyword = 'N/A';
// ---------- 日本時間 ----------
const searchDatetime = new Date().toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' });
// ---------- 各APIの結果処理 ----------
let yahooProcessed = false;
let rakutenProcessed = false;
let ebayProcessed = false;
for (const item of items) {
const json = item.json || {};
// Yahoo
if (Array.isArray(json.hits)) {
console.log('Processing Yahoo data, hits:', json.hits.length);
yahooProcessed = true;
if (json.hits.length > 0) {
for (const hit of json.hits) {
results.push({
キーワード: keyword,
商品名: hit.name || '',
店舗名: hit.seller?.name || '',
商品説明: (hit.description || '').replace(/
/g, ' ').replace(/<[^>]*>/g, ''),
価格: hit.price ?? '',
検索サイト: 'Yahoo',
商品ページ: hit.url || '',
検索日時: searchDatetime,
});
}
} else {
results.push({
キーワード: keyword,
商品名: '',
店舗名: '',
商品説明: '',
価格: '',
検索サイト: 'Yahoo',
商品ページ: '',
検索日時: searchDatetime,
});
}
continue;
}
// 楽天
if (Array.isArray(json.Items)) {
console.log('Processing Rakuten data, items:', json.Items.length);
rakutenProcessed = true;
if (json.Items.length > 0) {
for (const wrapper of json.Items) {
const hit = wrapper.Item || {};
results.push({
キーワード: keyword,
商品名: hit.itemName || '',
店舗名: hit.shopName || '',
商品説明: (hit.itemCaption || '').replace(/
/g, ' ').replace(/<[^>]*>/g, ''),
価格: hit.itemPrice ?? '',
検索サイト: '楽天',
商品ページ: hit.itemUrl || '',
検索日時: searchDatetime,
});
}
} else {
results.push({
キーワード: keyword,
商品名: '',
店舗名: '',
商品説明: '',
価格: '',
検索サイト: '楽天',
商品ページ: '',
検索日時: searchDatetime,
});
}
continue;
}
// eBay
if (Array.isArray(json.itemSummaries)) {
console.log('Processing eBay data, items:', json.itemSummaries.length);
ebayProcessed = true;
if (json.itemSummaries.length > 0) {
for (const hit of json.itemSummaries) {
console.log('eBay item:', hit.title, hit.seller?.username, hit.price?.value);
results.push({
キーワード: keyword,
商品名: hit.title || '',
店舗名: hit.seller?.username || '',
商品説明: '', // eBay は説明未取得
価格: hit.price?.value ?? '',
検索サイト: 'eBay',
商品ページ: hit.itemWebUrl || '',
検索日時: searchDatetime,
});
}
} else {
results.push({
キーワード: keyword,
商品名: '',
店舗名: '',
商品説明: '',
価格: '',
検索サイト: 'eBay',
商品ページ: '',
検索日時: searchDatetime,
});
}
continue;
}
// 不明な構造のログ(参考)
if (Object.keys(json).length > 0) {
console.log('Unknown data structure keys:', Object.keys(json));
}
}
// どのAPIも処理されなかった場合のフォールバック
if (!yahooProcessed && !rakutenProcessed && !ebayProcessed) {
console.log('No API data found, create empty records.');
for (const site of ['Yahoo', '楽天', 'eBay']) {
results.push({
キーワード: keyword,
商品名: '',
店舗名: '',
商品説明: '',
価格: '',
検索サイト: site,
商品ページ: '',
検索日時: searchDatetime,
});
}
}
console.log('Total results generated:', results.length);
if (results[0]) console.log('Sample result:', results[0]);
return results.map(r => ({ json: r }));
6.各サイトに負荷を掛けないように待ち時間を設定します。
「取得情報の整理」の「+」をクリックし「Search nodes…」に「wait」を入力し、「Wait」をクリックします。
7.追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:待ち
- Wait Amount:2
8.検索条件の内容で繰り返し検索するようにします。
「待ち」の「●」をドラックし「Loop Over Items」の左「■」にドロップします。
以上で3サイトの検索結果の結合は完了です。
取得情報のCSVファイルへ保存
1.取得情報をCSVファイルに保存します。
「Loop Over Items」の上「+」をクリックし「Search nodes…」に「convert」を入力し「Convert to File」をクリックします。
2.「Convert to CSV」をクリックします。
3.追加したノードに下記を適用して「Back to canvas」をクリックします。
- コード名:取得情報をCSV形式に変換
- Add option:Delimiter
4.「取得情報をCSV形式に変換」の「+」をクリックし「Search nodes…」に「write」を入力し「Read/write Files from Disk」をクリックします。
5.「Write File to Disk」をクリックします。
6.追加したノードに下記を適用して「Back to canvas」をクリックします。
- ノード名:取得情報をCSV形式で保存
- 「File Path and Name」に下記を設定
C:/せどり商品検索の自動化/検索結果/せどり_分析_{{ $now.plus({hours: 13}).format('yyyy-MM-dd_HHmmss') }}.csv
以上で取得情報のCSVファイルへ保存は完了です。
ワークフローの実行
「Excute workflow」をクリックすると作成したワークフローを実行します。
実行後にエラーが発生しているノードが無いことを確認します。
実行が完了すると検索結果が下記ファイルに保存されます。
C:\せどり商品検索の自動化\検索結果\せどり_分析_yyyy_mm_dd_hhMMss.csv
<せどり_分析のサンプル>
以上です。
コメント