22 KiB
name, category, description
| name | category | description |
|---|---|---|
| miaoshou-collect-box | cross-border-ecommerce | Explore and interact with Miaoshou ERP's "通用采集箱" (Common Collect Box) — URLs, collection methods, import paths, and login automation. |
妙手ERP 通用采集箱 (Common Collect Box)
Overview
Miaoshou ERP (erp.91miaoshou.com) has a Common Collect Box (通用采集箱) at a fixed URL. This skill documents how to navigate to it, the collection methods available, and how to interact with the import/collection UI programmatically via DrissionPage.
Login
- URL:
https://erp.91miaoshou.com/auth/login - Credentials:
xiaochaoren2026 / [REDACTED] - CAPTCHA: Base64 inline image (
data:image/png;base64,...) rendered in.captcha-img- Unlike Dianxiaomi (which uses a separate PNG endpoint), Miaoshou embeds the captcha directly.
- Extract with JS:
document.querySelector('.captcha-img').src - Decode base64, save to file, run
ddddocr.classification() - Apply digit cleaning:
raw.translate(str.maketrans('oliOSsZz', '01105522'))
- Form selectors:
- Account:
css:.account-input - Password:
css:.password-input - Captcha text:
css:.captcha-text - Captcha UUID:
input[name="captchaUuid"](must be set/synced) - Submit:
css:.login-button
- Account:
- Success redirects to:
https://erp.91miaoshou.com/welcome - Cookie file:
~/.hermes/cookies/miaoshou_cookies.json(autoLoginToken is critical)
Common Collect Box URL
Direct link (works after login):
https://erp.91miaoshou.com/common_collect_box/index
Title: 妙手-产品采集
Collection Methods Discovered
The page exposes 6 collection methods as tab-like options:
| Method | Chinese Name | Notes |
|---|---|---|
| Link Collection | 链接采集 | Enter public product URLs (1688, Taobao, etc.). System scrapes the page. Requires publicly accessible pages — internal systems (like AtomK behind login) will NOT work. |
| Import Collection | 导入采集 | Bulk import via file upload (template-based). This is the viable path for transferring data from AtomK or other internal systems. |
| 1688 AI Selection | 1688Ai选品 | AI-assisted product selection from 1688 |
| Inventory Collection | 货盘采集 | Collect from inventory/supplier pallets |
| Keyword Collection | 关键词采集 | Search keyword-based batch collection |
| Whole-Store Collection | 整店采集 | Enter a store URL to collect all products |
| Plugin Collection | 插件采集 | Browser extension-based collection |
| Store Cross-Collection | 店铺互采 | Cross-store collection |
Import Collection (导入采集) — 4 Sub-Methods
When you click "导入采集", the page switches to ?fetchType=importCopy and shows 4 sub-tabs:
| Sub-Method | Chinese Name | What It Does |
|---|---|---|
| Import Link Collection | 导入链接采集 | Upload an XLS file with product URLs. Miaoshou scrapes each URL. |
| Excel Spreadsheet Import | Excel表格导入 | Upload a pre-structured Excel with full product data (details TBD). |
| Local Material Package | 本地素材包导入 | Upload a local asset package (images + data). |
| Jushuitan Material Package | 聚水潭素材包导入 | Import from Jushuitan ERP format. |
Import Link Collection Template (导入链接采集)
This is the most important one for AtomK-style workflows.
Template file: 导入产品链接模板.xls (downloadable via "下载导入模板" link in the modal)
File format: .xls (older Excel 97-2003, NOT xlsx) — verified April 2026. .xlsx triggers 解析文件数据错误.
CRITICAL: The template is strictly 5 columns. Any extra column causes failure.
| Column | Field | Required | Notes |
|---|---|---|---|
| A | 链接地址(必填) | ✅ Yes | Product detail page URL. Must be publicly accessible. Login-gated pages (like AtomK behind login) will fail. |
| B | 产品标题 | No | AI titles ARE preserved — verified. Overrides scraped 1688 title. |
| C | 价格(RMB) | No | AI prices ARE preserved — verified. Overrides scraped 1688 price. |
| D | 促销价(RMB) | No | Only used when publishing to Lazada. |
| E | 提示:促销价仅可用于采集到Lazada | No | Literal hint text — include this column to match the official template exactly. |
Empirically verified findings (April 2026):
- ✅ 5-column
.xlswith exact headers above →解析成功 N/0/N - ❌ 6+ columns (e.g., adding "产品描述") →
导入文件未识别到:【产品主编号】表头 - ❌ Adding "产品主编号" column →
解析文件数据错误 - ❌
.xlsxformat →解析文件数据错误 - ✅ AI title from XLS overrides scraped 1688 title in the final product
- ✅ AI price from XLS overrides scraped 1688 price
- ✅ Sheet name can be
WorksheetorSheet1(doesn't matter with correct 5-col headers) - ✅ Encoding can be
utf_16_leorutf-8(doesn't matter with correct 5-col headers)
Important: The error "导入文件未识别到:【产品主编号】表头" is a misleading catch-all for "your columns don't match the expected 5-column template". Do NOT add a "产品主编号" column — doing so triggers 解析文件数据错误. Always use the exact 5-column format. The system does not actually use or store a "产品主编号" from Excel; SKU must be filled later via the edit dialog.
Critical limitation: The "导入链接采集" method fundamentally relies on web scraping each product URL. If the URL requires authentication (e.g., AtomK product pages behind atomlisting.com login), Miaoshou cannot fetch the data. The 5-column XLS only passes the link + AI title + AI price; Miaoshou still scrapes the 1688 page for images, description, specs, etc.
File Upload Mechanics
When the import modal is open:
- The upload area is a hidden
<input type="file" class="jx-upload__input">inside a.pro-upload/.jx-upload--textcontainer. - Selector:
css:input[type=file]orcss:.jx-upload__input - Accepts:
.xls,.xlsx,.csv(but only.xlsworks reliably) - Use
file_input.input('/path/to/file.xls')to set the file path programmatically. - After upload, the file name appears in
.jx-upload-list li. - The confirm button is inside the modal dialog — search within
.jx-dialogfor buttons with text确认. - After clicking confirm, the modal closes and the file appears in the "已导入的文件列表" table. Wait ~15s for parsing, then refresh the page to check status.
- The page does NOT auto-update after confirm. You must navigate back to
?fetchType=importCopyor usepage.get()to refresh and see the parse result.
Complete Upload Flow (Verified April 2026)
# 1. Navigate to import page
page.get("https://erp.91miaoshou.com/common_collect_box/index?fetchType=importCopy")
time.sleep(10)
# 2. Click Excel import button
page.run_js("""
var all = document.querySelectorAll('span, div, button, a');
for (var i=0; i<all.length; i++) {
var txt = all[i].innerText || '';
if (txt.includes('Excel表格导入') && txt.length < 20) {
all[i].click(); break;
}
}
""")
time.sleep(5)
# 3. Upload file
file_inputs = page.eles('css:input[type="file"]')
file_inputs[0].input('/path/to/import.xls')
time.sleep(5)
# 4. Click confirm
page.run_js("""
var btns = document.querySelectorAll('button');
for (var i=0; i<btns.length; i++) {
if (btns[i].innerText && btns[i].innerText.trim() === '确认') {
btns[i].click(); break;
}
}
""")
# 5. Wait for backend parsing, then refresh to check result
time.sleep(20)
page.get("https://erp.91miaoshou.com/common_collect_box/index?fetchType=importCopy")
time.sleep(10)
# 6. Check result in page body text
body_text = page.run_js("return document.body.innerText;")
# Look for: '解析成功' or '解析失败' near the filename
Known Error Patterns
| Error Message | Meaning | Fix |
|---|---|---|
导入文件未识别到:【产品主编号】表头 |
Column count ≠ 5 or headers don't match | Ensure exactly 5 columns with headers: 链接地址(必填), 产品标题, 价格(RMB), 促销价(RMB), 提示:促销价仅可用于采集到Lazada. Do NOT add "产品主编号" — it's a misleading error. |
解析文件数据错误 |
Wrong format or added "产品主编号" | Use .xls (not .xlsx). Remove any "产品主编号" column. Ensure exact 5-column headers. |
解析失败 (with 0/N/N) |
URLs accepted but scraping failed | Linked pages are unsupported (e.g., COS-hosted custom HTML, login-gated pages). Use standard 1688/Taobao/Pinduoduo URLs. |
Collect Box Product Edit Dialog (采集箱产品编辑弹窗)
After a product is imported and claimed to a platform (e.g., Temu全托管), it appears in the 已认领 tab. Each row has an 编辑 button that opens a modal dialog for editing the product's full data.
This dialog is the key to filling AI-generated fields (SKU, description, keywords) that cannot be imported via the 5-column XLS template.
Dialog Structure
- Root dialog:
.jx-dialog.pro-dialog.collect-box-editor-dialog-V2(1880×953) - Editor body:
.collect-box-editor(1559×953) - Tabs: 基本信息, 产品属性, 销售属性, 产品图片, 产品视频, 认证说明, 物流信息, 货源链接
Critical Field Mappings (Verified April 2026)
The editor uses Vue.js with custom jx-input components. Direct .value assignment works but must be followed by event dispatching for Vue to sync state.
| Field | DOM Element | Selector Strategy | Notes |
|---|---|---|---|
| 产品标题 | input[type="text"] (multiple) |
Find first input whose .value contains the title text |
Title is pre-filled from import; usually does NOT need updating. |
| 产品主编号 (SKU) | input[type="text"] at index 1 |
editor.querySelectorAll('input')[1] |
Placeholder: 请输入产品主编号,不填将自动生成. This is the most reliable field to target. |
| 简易描述 | textarea at index 0 |
editor.querySelectorAll('textarea')[0] |
Plain text. Fills to Shopee/Wish/Joom/Mercado Libre/Ozon/Walmart product description. |
| 详细描述 | iframe at index 0 (TinyMCE-like) |
editor.querySelectorAll('iframe')[0] → contentDocument.body |
Rich text editor. Used for Lazada/速卖通/TikTok/Coupang/eBay/Allegro. Body is contenteditable. |
Vue State Sync (Mandatory)
Miaoshou uses Vue.js. Simply setting .value is not enough — the change must be propagated to Vue's reactive state. After setting any value, dispatch:
el.value = 'your-value';
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));
el.dispatchEvent(new Event('blur', {bubbles: true}));
el.dispatchEvent(new KeyboardEvent('keydown', {key: 'a', bubbles: true}));
el.dispatchEvent(new KeyboardEvent('keyup', {key: 'a', bubbles: true}));
Without this, clicking 保存修改 will silently discard your changes.
Opening the Edit Dialog Programmatically
Products are rendered in a virtual scroll table (.pro-virtual-table__row), not a standard <table>.
# 1. Navigate to claimed tab
page.get('https://erp.91miaoshou.com/common_collect_box/items')
# ... click 已认领 tab ...
# 2. Find the row by collect_box_id and click 编辑
page.run_js("""
var rows = document.querySelectorAll('.pro-virtual-table__row, .pro-virtual-scroll__row');
for (var i=0; i<rows.length; i++) {
var txt = rows[i].innerText || '';
if (txt.includes('3516358992')) { // your collect_box_id
var btns = rows[i].querySelectorAll('button');
for (var j=0; j<btns.length; j++) {
if (btns[j].innerText && btns[j].innerText.trim() === '编辑') {
btns[j].click();
break;
}
}
}
}
""")
time.sleep(10) # Dialog takes time to render
editor = page.ele('css:.collect-box-editor')
Filling Each Field
SKU (产品主编号)
editor.run_js(f"""
var editor = document.querySelector('.collect-box-editor');
var skuInput = editor.querySelectorAll('input')[1];
skuInput.value = {json.dumps(sku)};
skuInput.dispatchEvent(new Event('input', {{bubbles: true}}));
skuInput.dispatchEvent(new Event('change', {{bubbles: true}}));
skuInput.dispatchEvent(new Event('blur', {{bubbles: true}}));
skuInput.dispatchEvent(new KeyboardEvent('keydown', {{key: 'a', bubbles: true}}));
skuInput.dispatchEvent(new KeyboardEvent('keyup', {{key: 'a', bubbles: true}}));
""")
Simple Description (简易描述)
editor.run_js(f"""
var editor = document.querySelector('.collect-box-editor');
var ta = editor.querySelectorAll('textarea')[0];
ta.value = {json.dumps(description)};
ta.dispatchEvent(new Event('input', {{bubbles: true}}));
ta.dispatchEvent(new Event('change', {{bubbles: true}}));
ta.dispatchEvent(new Event('blur', {{bubbles: true}}));
""")
Rich Description (详细描述 — iframe)
html_content = f'<p><span style="font-size: 12.0pt;">{description.replace(chr(10), "</span></p><p><span style=\\"font-size: 12.0pt;\\">")}</span></p>'
editor.run_js(f"""
var editor = document.querySelector('.collect-box-editor');
var iframe = editor.querySelectorAll('iframe')[0];
var doc = iframe.contentDocument || iframe.contentWindow.document;
var body = doc.querySelector('body');
body.innerHTML = {json.dumps(html_content)};
body.dispatchEvent(new Event('input', {{bubbles: true}}));
""")
Saving
page.run_js("""
var btns = document.querySelectorAll('button');
for (var i=0; i<btns.length; i++) {
if (btns[i].innerText && btns[i].innerText.includes('保存')) {
btns[i].click();
break;
}
}
""")
time.sleep(5)
Verification
After saving, re-open the edit dialog and read back the values to confirm persistence:
verify = editor.run_js("""
var editor = document.querySelector('.collect-box-editor');
var inputs = editor.querySelectorAll('input');
var textareas = editor.querySelectorAll('textarea');
var iframes = editor.querySelectorAll('iframe');
var result = {};
if (inputs.length > 1) result.sku = inputs[1].value;
if (textareas.length > 0) result.desc = textareas[0].value;
for (var i=0; i<iframes.length; i++) {
try {
var doc = iframes[i].contentDocument || iframes[i].contentWindow.document;
var body = doc.querySelector('body');
if (body) { result.rich_desc = body.innerText; break; }
} catch(e) {}
}
return result;
""")
# verify.sku should match, verify.desc should contain AI text
AtomK → Miaoshou Batch Import Script
A production-ready end-to-end script exists at /home/ubuntu/auto_miaoshou_import.py:
What it does:
- Logs into AtomK API, fetches claimed products + their AI-generated listings
- Generates a 5-column
.xlsfile (utf_16_leencoding,Worksheetsheet name) - Launches headless Chromium, loads Miaoshou cookies
- Navigates to
?fetchType=importCopy, clicksExcel表格导入 - Uploads the
.xlsfile, clicks确认 - Refreshes the page after 20s to verify
解析成功 - Logs results and updates state file
State tracking: /home/ubuntu/.hermes/miaoshou_import_state.json
- Tracks already-imported
product_ids to avoid duplicates - Updated after each successful run
Cron job: miaoshou-atomk-auto-import (job_id: 2b6587d6895b)
- Schedule:
0 * * * *(every hour on the hour) - Batch size: 6 products per run
- Logs to:
/home/ubuntu/.hermes/miaoshou_import.log
Usage:
# Manual run
python3 /home/ubuntu/auto_miaoshou_import.py
# Check cron status
hermes cron list
| Scenario | Viable? | Recommended Path |
|---|---|---|
| AtomK product pages are public | ❌ No | Even public AtomK HTML pages (hosted on Tencent COS) fail with 解析失败 0/3. Miaoshou's scraper is hardcoded for domestic e-commerce platforms (1688, Taobao, Pinduoduo), not custom HTML pages. |
| AtomK product pages require login | ❌ No | Same as above — plus authentication barrier. |
| 5-column XLS import (link + AI title + AI price) | ✅ Yes | 解析成功. Titles and prices from Excel override scraped 1688 data. Verified: AI title Romantic Heart... appears instead of 1688 original. |
| 5-column XLS + extra columns (desc, SKU, images, EAN, etc.) | ❌ No | Triggers 导入文件未识别到:【产品主编号】表头. Adding "产品主编号" triggers 解析文件数据错误. |
| ".xlsx" format | ❌ No | Triggers 解析文件数据错误. Must use .xls (xlwt). |
| Full AI data via dual-browser automation | ✅ Yes | Proven workflow (April 2026): 1. Import via 5-col XLS (link + AI title + AI price) 2. Claim product to target platform 3. Open collect box edit dialog 4. Auto-fill SKU, 简易描述, 详细描述 (rich text) via DrissionPage + JS 5. Save and verify Reference script: /home/ubuntu/miaoshou_atomk_bridge.py |
| Direct platform upload (bypass Miaoshou) | ⚠️ Partial | Generate Temu/AliExpress CSV from AtomK API → upload to platform directly. Bypasses Miaoshou entirely but loses Miaoshou's inventory/order management. |
Page Structure Notes
- Left sidebar contains:
通用功能,产品采集,公用采集箱,AI工作台,侵权检测,货盘中心, etc. - Supported platforms displayed as tags: 1688, 义乌小商品城, 浙宝网, Vvic, 搜款网, 网商园, 货捕头, etc.
- Bottom action bar:
采集并自动认领,采集并自动发布 - A modal/popup may appear on first visit with collection settings — dismiss with "我知道了".
Browser Setup (DrissionPage)
from DrissionPage import ChromiumPage, ChromiumOptions
co = ChromiumOptions()
co.set_browser_path('/home/ubuntu/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome')
co.set_argument('--headless=new')
co.set_argument('--no-sandbox')
co.set_argument('--disable-dev-shm-usage')
co.set_argument('--window-size=1440,900')
co.set_user_agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36')
co.set_local_port(get_free_port())
page = ChromiumPage(addr_or_opts=co)
Pitfalls
- Cookie expiration: The saved cookie (autoLoginToken) expires relatively quickly. Re-login with captcha is often needed.
- Base64 captcha session: Must extract the captcha image from the same browser session (via JS
document.querySelector('.captcha-img').src) — do NOT userequeststo fetch it separately, or the captcha UUID will mismatch. - Tab clicking: The collection method tabs (链接采集, 导入采集, etc.) are
<span>elements inside radio-button groups, not standard<button>or<a>tags. Standard.ele('xpath://*[contains(text(), "导入采集")]').click()may fail. Use JS click viapage.run_js()or search for the actual<button>inside the tab component. - Import dialog: Clicking "导入链接采集" opens a modal dialog. The template download link "下载导入模板" triggers a browser download to the default Downloads folder. In headless mode, the file goes to
/home/ubuntu/Downloads/导入产品链接模板.xls. - XLS format only: The import link template is
.xls(Excel 97-2003). Using.xlsxwill likely fail. - "暂无当前模块权限": Some accounts may see "You don't have permission for this module" if the collect box feature is not enabled for the sub-account. Contact the main account admin to enable.
- SPA navigation: Clicking menu items may not trigger full navigation. Use
page.get('https://erp.91miaoshou.com/common_collect_box/index?fetchType=importCopy')for direct access. - Link scraper limitation: The 导入链接采集 method requires publicly accessible product detail pages. Any page behind authentication (AtomK, internal ERPs) will result in empty/failed collection.
Next Exploration Steps (when needed)
- ✅
Click the "导入采集" tab and inspect the file upload input(Done) - ✅
Download the template to understand required columns(Done — 5-column.xls: link, title, price, promo_price, hint) - ✅
Analyze "Excel表格导入" template for full-data import(Done — the XLS template is corrupt/unreadable; full-field bulk import is not viable. The working path is 5-col import + edit-dialog automation.) - ✅
Automate the file upload and submission(Done — upload viafile_input.input()+ confirm button in modal + page refresh to check result.) - ✅
Automate the edit dialog post-import fill(Done — SKU, 简易描述, 详细描述 all verified saving correctly.) - ✅
Build end-to-end automation(Done — script at/home/ubuntu/auto_miaoshou_import.pyfetches AtomK API data, generates 5-col XLS, uploads via browser, and tracks state. Cron jobmiaoshou-atomk-auto-importruns hourly.) - ✅
Set up cron job for hourly batch import(Done — jobmiaoshou-atomk-auto-importruns at0 * * * *, imports 6 products per run, skips already-imported IDs via/home/ubuntu/.hermes/miaoshou_import_state.json.) - 🔴 Future: Extend edit-dialog automation to fill 产品图片 (replace 1688 images with AI-generated ones from AtomK
platform_fields.pictures), 产品属性 (material, shape, brand), and 关键词 fields. - 🔴 Future: Build batch loop that processes multiple
collect_box_ids end-to-end (import → claim → edit → save). - 🔴 Future: Investigate if
快速上货(Quick Listing) offers a more direct API or form for bulk AI data injection, bypassing the collect box entirely.