irobotbox-saihe
v1.1.0
Published
赛盒 irobot 登录、产品图上传、批量改价(allegro、Ebay)、CLI 与 SDK(baseUrl/商户号由调用方或环境显式提供)
Readme
irobotbox-saihe
saihe产品图上传(Node 18+)。
安装
在 monorepo 根目录执行 npm install(已配置 workspace irobotbox-saihe),或在本包目录单独执行 npm install。
本机单实例 Node 服务(推荐做法)
部署形态是**一台机器、一个 Node 进程(或单实例 PM2/systemd)**时,建议开启 sessionFile:
- 进程重启、发版后仍能尽量复用上次 Cookie,少重复登录、少打验证码。
- 路径请用
**path.resolve固定成绝对路径**(或__dirname相对项目目录),避免工作目录变了导致单例校验里sessionFile不一致。 - 会话文件含 Cookie,勿提交到 git(在仓库根
.gitignore里忽略saihe_session.json、*.publish.json或你的专用路径);文件权限按本机安全要求收紧。 - Publish SSO(Allegro 等):配置了
sessionFile时,默认会额外使用同目录、去掉扩展名后加.publish.json的文件持久化换票得到的.AspNetCore.Cookies。也可显式传publishSessionFile(绝对路径推荐),或传publishSessionFile: null关闭落盘。ERP 重新登录或resetAllegroPublishSession会删除该文件,避免误用过期 Publish 票。
若将来改为多机/多副本,再考虑改为不依赖本机文件、或集中存储会话;单机构造下 sessionFile 是最省心的默认项。
SDK 使用示例
多模块、同进程请用 **getSaiheIrobotClient** 单例,共享同一份 Cookie;不要各处 new SaiheIrobotClient。需要换账号时先调用 resetSaiheIrobotClient(),再带新 config 调用 getSaiheIrobotClient(config)。
初始化(应用启动或公共模块中只执行一次)
const path = require("path");
const {
getSaiheIrobotClient,
} = require("irobotbox-saihe");
const client = getSaiheIrobotClient({
baseUrl: process.env.SAIHE_BASE_URL, // 必填:赛盒站点根地址,勿硬编码
username: process.env.SAIHE_USERNAME,
password: process.env.SAIHE_PASSWORD,
customerId: process.env.SAIHE_CUSTOMER_ID, // 未设置时,登录/上传会要求提供或由 session 恢复
// 本机单服务建议固定绝对路径,例如:path.resolve(process.cwd(), "data/saihe_session.json")
sessionFile: path.resolve(process.cwd(), "saihe_session.json"),
});不建议在 getSaiheIrobotClient 内部自动 await 登录:该函数是同步的,无法完成异步登录;且进程内首次拉客户端就弹验证码/OCR 会拖慢所有引用方。
更合适的方式:
| 场景 | 做法 |
|------|------|
| 长驻服务启动 | await initSaiheIrobotClient(config),或 getSaiheIrobotClient(config) 后 await client.ensureErpSession() |
| 仅上传 | 可继续只 uploadImage:失效时内部会重登(与您以往用法一致) |
| Allegro Listing | ensureAllegroPublishSession / allegroListingSearch / allegroListingBatchUpdatePrice 等在需换 Publish 票时会先 ensureErpSession(默认工作台探测);buildAllegroBatchUpdatePricePayload(单条)、buildAllegroBatchUpdatePricePayloadMany(多条 listing)与 ALLEGRO_BATCH_SITE_IDS 见 allegroListing.js |
| eBay V2 Listing(ERP) | 仅用 ERP Cookie(baseUrl + sessionFile),不要 Publish SSO。buildDefaultListingListParams 组装列表筛选;client.ebayListingSearchPage / ebayListingRecordCount 拉列表;ebayBatchSetBuyItNowPrice / ebayCollectListingBasicIdsFromSearch 做批量 Buy It Now 改价(详见下文)。 |
ensureErpSession({ force: true }) / skipProbe: true 会跳过探测、直接走完整登录(验证码等)。详见 SaiheIrobotClient JSDoc。
eBay V2(ERP 批量改价)
与 Allegro 不同:接口在 /IrobotBox/EbayV2/,走 GET + query,响应多为 HTML content-type 包裹的 JSON。
const client = getSaiheIrobotClient({ /* …同初始化示例… */ });
await client.ensureErpSession();
const clientSku = "YOUR_CLIENT_SKU";
const count = await client.ebayListingRecordCount({
SearchValue: clientSku,
});
const page = await client.ebayListingSearchPage({
SearchValue: clientSku,
CurrentPage: "1",
pagesize: "20",
});
const ids = await client.ebayCollectListingBasicIdsFromSearch({
SearchValue: clientSku,
});
await client.ebayBatchSetBuyItNowPrice({
listingBasicIds: ids,
operatingvalue: "24.00",
chunkSize: 50,
skipSaveVerification: false,
throwOnBusinessFailure: false,
retryExcludeBusyListingIds: true,
});getSaiheIrobotClient:ebayBatchSetBuyItNowPrice按每个 chunk 单独走会话探测与重登重试,后半批失败时不会重复提交已成功的前面的块。非法chunkSize(非有限数字或小于 1)会静默回退为 50;单次 GET 过长时可自行减小chunkSize。设throwOnBusinessFailure: true(或放在最后一个参数的callOptions里)时,若EditBuyItNowPrice返回success: false会抛错(默认false,与仅解析 JSON 的旧用法兼容)。不要与retryExcludeBusyListingIds同时开启(先抛错则无法自动剔除)。retryExcludeBusyListingIds: true(或callOptions里):当服务端返回如ListingID:…的产品正在修改中!时,在本 chunk 内解析 msg 中的 ID、剔除后自动重试其余 listing;汇总结果里可有skippedBusyListingBasicIds。底层解析见parseListingBasicIdsFromEbayEditFailureMsg。- 直接使用
ebayBatchSetBuyItNowPrice(jar, baseUrl, …)(不经过 client)时不含 ERP 会话重试,但可传retryExcludeBusyListingIds(与本段逻辑一致);会话仍须自备。
其它文件里取同一客户端(无参即可)
const { getSaiheIrobotClient } = require("irobotbox-saihe");
async function main() {
const client = getSaiheIrobotClient();
const result = await client.uploadImage("2779085", "/path/to/need_upload/a.png");
console.log(result.oss.url);
}上传说明
- SKU 须为纯数字字符串(如
"2779085"),否则会抛错。 - 第二参数可为:本地文件路径、
Buffer(建议同时传uploadOptions.fileName)、或{ buffer, fileName, mimeType? }。 - 返回含
displayFileName、oss(含url)、save(后台SaveImage响应)。
// 从 need_upload 目录按文件名(与 CLI 一致时可只传文件名拼路径)
await client.uploadImage("2779085", path.join(process.cwd(), "need_upload", "pic.png"));
// 内存图片
await client.uploadImage("2779085", imageBuffer, {
fileName: "shot.png",
mimeType: "image/png",
});切换账号(例如多租户测试)
const { getSaiheIrobotClient, resetSaiheIrobotClient } = require("irobotbox-saihe");
resetSaiheIrobotClient();
const other = getSaiheIrobotClient({
username: "user2",
password: "secret2",
sessionFile: "/path/to/session2.json",
});CLI
npx saihe --help
# 或在本仓库内:node bin/cli.cjs --help- 无子命令:交互/环境变量登录,写入
saihe_session.json(或SAIHE_SESSION_FILE)。 npx saihe images <SKU> [index]:查产品图 Tab。npx saihe upload <SKU> <文件名>:从need_upload上传;会话失效时可用SAIHE_PASSWORD等自动重登。
SAIHE_BASE_URL 为必填;其余常用:SAIHE_SESSION_FILE、SAIHE_USERNAME、SAIHE_PASSWORD、SAIHE_CUSTOMER_ID、SAIHE_NO_OCR、SAIHE_CAPTCHA 等,见 bin/cli.cjs 中 --help 输出。
自测
npm run test:smoke
# 真机联调(需网络):见 test/sdk-smoke.cjs 内注释;eBay 列表可选环境变量 SAIHE_TEST_EBAY_CLIENT_SKU