--- name: atomk-bulk-claim description: Automatically log into AtomK, claim products from Product Pool, generate Temu/AliExpress data, and download CSV with 800x800 images using Node.js Playwright. --- # AtomK Product Claim & Temu Data Generation Automates logging into the AtomK system (atomlisting.com), claiming products from the Product Pool (产品池), generating Temu listing data via AI, and exporting CSV with 800x800 images. ## Critical Environment Facts - **DrissionPage is NOT installed** — do NOT use it - **Use Node.js Playwright** at `/home/ubuntu/.hermes/hermes-agent/node_modules/playwright` - **Use `atomlisting.com` domain** — `bt109atomk.sh3.ikuai7.com` login silently fails - Login credentials: admincao / Tt123456! - `sharp` npm package required for image resizing (`npm install sharp`) - Set `NODE_PATH=/home/ubuntu/.hermes/hermes-agent/node_modules` when running scripts - Use `ignoreHTTPSErrors: true` for atomlisting.com ## Execution Steps ### 1. Setup ```bash killall -9 chrome chromium chrome-headless-shell 2>/dev/null cd /home/ubuntu/.hermes/hermes-agent && NODE_PATH=/home/ubuntu/.hermes/hermes-agent/node_modules node script.js ``` ### 2. Login Navigate to `https://atomlisting.com/login` (NO www, HTTPS only). Fill inputs[0] with username, inputs[1] with password, then `await inputs[1].press('Enter')` — do NOT click the login button. The form has `method="get"` and clicking the button triggers a GET redirect to `login?` instead of the JavaScript-powered `POST /api/v1/auth/login`. Pressing Enter on the password field triggers the correct JS handler. ### 3. Claim Products 1. Navigate to `https://atomlisting.com/products` (use `waitUntil: 'domcontentloaded'`) 2. Select category: `await page.selectOption('select', { label: '家居百货' })` 3. Click refresh button: `text=刷新` 4. Find claim buttons: `page.$$('text=认领并编辑')` 5. For each button: - Extract product ID using regex `/^[A-Z0-9]{6,8}$/` from card text - Click button, wait for URL to contain `/editor/` - Extract editor ID from URL - Navigate back to products, re-select category ### 2a. Searching for Existing Products (Product Lookup) AtomK has **two separate product views**: | Page | URL | Contains | |------|-----|----------| | **Product Pool** (`产品池`) | `https://atomlisting.com/products` | Unclaimed products available for claiming | | **My Products** (`我的产品`) | `https://atomlisting.com/my-products` | Products already claimed by current account | **Search strategy:** - Use **product name prefix** (e.g. `88NeoHab`, `11Chughalf`) rather than the full SKU (`88NeoHab-PO-211-16060374487670113`). The full SKU often returns no results because AtomK indexes by product code, not the full platform SKU. - If a product is **not found** in My Products, check the Product Pool — it may not have been claimed yet. - The search input may not be visible immediately on page load; wait for the SPA to render. ```javascript // Search in Product Pool await page.goto('https://atomlisting.com/products'); await page.waitForTimeout(3000); const searchInput = page.locator('input[placeholder*="搜索"]').first(); await searchInput.fill('88NeoHab'); // prefix, not full SKU await searchInput.press('Enter'); await page.waitForTimeout(5000); ``` ### 4. Generate Platform Data (Temu / AliExpress / etc.) For each claimed product: 1. Navigate to `https://atomlisting.com/editor/{id}` 2. Click platform tab button first — available platforms: `button:has-text("Temu")`, `button:has-text("速卖通")`, `button:has-text("亚马逊")`, `button:has-text("TikTok Shop")`, `button:has-text("SHEIN")`, `button:has-text("Ozon")`, `button:has-text("沃尔玛")` 3. Click `button:has-text("AI 生成")` — the button text becomes `AI 生成 速卖通 上架信息` after platform selection 4. Wait for generation (poll button text until no longer contains "生成中") 5. Extract generated data: - Title: `input[placeholder*="标题"]` or `input[placeholder*="产品标题"]` - Description: `textarea[placeholder*="描述"]` or `textarea[placeholder*="产品描述"]` - Price: `input[type="number"]` - Tags: `input[placeholder*="关键词"]` or `input[placeholder*="标签"]` - Image URLs: `img[src*="cos"]` (both cos.ap-hongkong and cos.ap-nanjing sources, exclude logo/icon) - Dimensions: inputs with placeholders for 重量/长/宽/高 **AliExpress CSV format** (similar to Temu but different category defaults): ``` Product name,Category path,Price,Quantity,Product description,Package weight,Package length,Package width,Package height,Keywords,Image URLs,Product code ``` Use "Luggage & Bags" as category for 箱包 products. ### 5. Download & Resize Images ```javascript const sharp = require('sharp'); const { execSync } = require('child_process'); // Download execSync(`curl -sL -o "${tempFile}" "${url}"`, { timeout: 30000 }); // Resize to 800x800 const resized = await sharp(tempFile) .resize(800, 800, { fit: 'contain', background: { r: 255, g: 255, b: 255, alpha: 1 } }) .jpeg({ quality: 90 }) .toBuffer(); ``` ### 6. Generate CSV Temu standard format: ``` Product name,Category path,Price,Quantity,Product description,Package weight,Package length,Package width,Package height,Keywords,Image URLs,SKU,Product code ``` CSV fields must be escaped: if value contains `,`, `"`, or `\n`, wrap in `"` and double any `"`. ## Critical Pitfalls - **Login form GET trap**: The login form has `method="get"` — clicking the "登 录" button submits a GET request to `login?` and stays on the login page. Always press Enter on the password field to trigger the JS `POST /api/v1/auth/login` handler instead. - **Available categories in Product Pool**: "全部分类", "汽摩配", "玩具母婴", "箱包" (bags-luggage), "服饰配饰", "美妆个护", "服饰", "美容健康", "默认分类", "文具电子", "家居百货", "运动户外". Use `page.selectOption('select', { label: '箱包' })` for bags/luggage. - **Platform tabs in Editor**: After claiming, the editor supports multiple platforms. Click the platform tab FIRST (e.g., `速卖通`, `Temu`, `亚马逊`, `TikTok Shop`, `SHEIN`, `Ozon`, `沃尔玛`), THEN click AI generate. The AI generate button text changes to reflect the selected platform (e.g., "AI 生成 速卖通 上架信息"). - **Image sources include both regions**: Generated product images may come from both `cos.ap-hongkong.myqcloud.com` (user uploads) AND `cos.ap-nanjing.myqcloud.com` (1688 source images). Filter with `img[src*="cos"]` instead of just hongkong. - **Product ID parsing**: Don't use line position (lines[0]). Use regex `/^[A-Z0-9]{6,8}$/` to find the 6-8 char alphanumeric product code. First line can be "暂无图片" or image count. - **Editor ID validation**: Must be numeric (`/^\d+$/`). Some claimed products lead to non-editor pages. - **Stale element references**: After clicking a claim button, the page navigates. Re-find elements after each navigation back to products. - **AI generation timeout**: Each product takes 1-3 minutes. Use generous polling (50 iterations × 3 seconds = 150 seconds max). - **Background processes**: For 20+ products, use `terminal(background=true, notify_on_complete=true)` with timeout > 600s. - **Playwright waitUntil**: Use `domcontentloaded` not `networkidle` for heavy pages — faster and more reliable. - **Suppress alerts**: Use `page.addInitScript(() => { window.alert = function() {}; window.confirm = function() { return true; }; })` to prevent blocking dialogs. - **sharp module path**: Must set `NODE_PATH` environment variable or require will fail with "Cannot find module 'sharp'". - **HTTPS certificate errors**: atomlisting.com has a cert mismatch. Set `ignoreHTTPSErrors: true` at BOTH `chromium.launch()` AND `browser.newContext()` levels. - **Download blocking**: Cannot use `page.goto()` for image URLs that trigger downloads. Use `curl` via `execSync` instead. ## Archive Output ```bash cd /tmp && tar -czf temu_batch_20.tar.gz temu_batch_listing_final.csv temu_batch_images_800x800/ ```