SuperAPI AI Directory

linkfox-walmart-wmtwin

Coding & development

View repository

Updated 10-16 06:23

About this skill

Master Wo (WMTwin) Automated Login and Competitor Search

This skill provides automated login, API calling and competitor search capabilities for WMTwin (Master Wo), a Walmart seller tool platform. It handles authentication flow and competitor product search with automatic data decoding.

Core Concepts

Master Wo (WMTwin) is a Walmart seller tool platform. This skill provides automated login, API calling, and competitor search capabilities, including:

Login and Authentication

  • Automated login management: Detects login status and automatically executes the login flow
  • Graphic captcha: Requires manual recognition; the system will display the image to the user
  • SMS verification code: Sent automatically; the user provides the verification code to complete login
  • Session persistence: Saves the session after successful login to avoid repeated logins
  • Multi-account support: Each phone number manages its session independently

Competitor Search

  • Keyword search: Search for competitors on the Walmart platform by keyword
  • WFS filtering: Search only Walmart Fulfillment Services products
  • Sales range: Filter products by minimum/maximum sales
  • Paginated queries: Supports paginated retrieval of large amounts of data
  • Automatic decoding: All encoded characters are automatically converted to real data
  • Automatic login: Detects login status and automatically guides the user to log in when not logged in
  • Session management: Automatically saves and loads login status, supports multiple accounts

Authentication Flow

1. 尝试密码登录
   ├─ 成功 → 保存session,完成
   └─ 失败 (code: 1101) → 需要验证码登录

2. 获取图形验证码
   └─ 展示图片给用户,等待人工识别

3. 发送短信验证码
   └─ 使用图形验证码答案调用发送API

4. 短信验证码登录
   └─ 用户提供短信验证码,完成登录

5. 保存Session
   └─ Session保存在 /tmp/linkfox_wmtwin_sessions/{phone}.json

Important API Rules

Response Format

Master Wo's API response format is special and requires attention:

Success response:

{
  "code": 1,           // 注意:1表示成功,不是0!
  "msg": "成功",
  "data": {...}
}

Failure response:

{
  "code": 1101,        // 其他code表示失败
  "msg": "错误信息",
  "data": null
}

Conditions for determining success:

def is_success(result):
    return result.get('code') in [0, 1] and result.get('msg') in ['成功', '操作成功']

Common Error Codes

Code Meaning Handling method
1 Success Normal processing
1101 Environment anomaly, captcha login required Execute the SMS login flow
1008 Incorrect verification code Obtain the verification code again
1020 Incorrect SMS verification code Check the verification code or resend it

API Endpoints

Authentication APIs

Endpoint Method Description
/api/v1/auth/login POST Password login
/api/v1/auth/captcha GET Obtain graphic captcha
/api/v1/auth/sms-code POST Send SMS verification code
/api/v1/auth/sms-login POST SMS verification code login

See references/api.md for detailed API documentation.

Usage

Step-by-Step Login

# 步骤1: 开始登录,获取验证码
python3 scripts/wmtwin_login.py login 13699998888 111111

# 系统会保存验证码图片: /tmp/linkfox_wmtwin_captcha.png
# 用户查看图片并提供答案(例如:24)

# 步骤2: 提供验证码,发送短信
python3 scripts/wmtwin_login.py continue 24

# 系统发送短信到用户手机
# 用户提供短信验证码(例如:123456)

# 步骤3: 完成登录
python3 scripts/wmtwin_login.py continue sms 123456

# 登录成功,session保存在:
# /tmp/linkfox_wmtwin_sessions/13699998888.json

Check Login Status

python3 scripts/wmtwin_login.py check 13699998888

Call API

# GET请求
python3 scripts/wmtwin_login.py api 13699998888 /user/info

# POST请求
python3 scripts/wmtwin_login.py api 13699998888 /order/create POST '{"item":"test"}'

Working with Session

Session Storage

  • Location: /tmp/linkfox_wmtwin_sessions/{phone}.json
  • Format: JSON containing cookies, headers, and timestamp
  • Auto-load: Automatically loaded when calling APIs

Session Structure

{
  "cookies": {
    "wal": "encoded_session_token"
  },
  "headers": {
    "User-Agent": "...",
    "Content-Type": "application/json"
  },
  "saved_at": "2024-04-28T16:28:08.987745"
}

Cookie Handling

Important: Master Wo returns duplicate cookie names, which requires special handling:

# 正确方式:避免重复cookie错误
cookies_dict = {}
for cookie in session.cookies:
    cookies_dict[cookie.name] = cookie.value  # 自动覆盖重复项

Password Encryption

The password is transmitted using RSA encryption:

  • Algorithm: RSA 1024-bit + PKCS1 v1.5 padding
  • Encoding: Base64
  • Transport: HTTPS
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64

PUBLIC_KEY = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEICVdtxqOCBwHN9a/+YxeXz/B
ZGfduADPfV9dUTW+hGVpIcXU6kBkUdlhVPPdO6n7irK7dxD56m1xG1EmV2RICsvy
W2Y7JVyRRVhun92urbw7TtBcMCCB5SzLI+x1LBUr98SMkMNRQxcnYPkrPj0qGI4v
MC52dJ7z3n6aMf3XoQIDAQAB
-----END PUBLIC KEY-----"""

def encrypt_password(password):
    public_key = RSA.import_key(PUBLIC_KEY)
    cipher = PKCS1_v1_5.new(public_key)
    encrypted_bytes = cipher.encrypt(password.encode('utf-8'))
    return base64.b64encode(encrypted_bytes).decode('utf-8')

Data Decoding

Strings returned by the Master Wo API often use encoded characters in the Unicode U+0100–U+024F range (which may look like garbled text in some environments). This skill automatically decodes them via scripts/wmtwin_complete_decoder.py ; examples in the documentation uniformly use U+XXXX code points for description, without directly displaying the original encoded glyphs.

Encoding Ranges

Master Wo uses 4 encoding ranges and supports two different encoding schemes:

Encoding range Unicode Mapping Purpose Scheme
323 Single character Decimal point . Price decimal point General
324-333 10 characters Digits 0-9 Simple numbers (review count, etc.) API scheme
334-385 52 characters A-Z, a-z Seller name, company name API scheme
528 Single character Decimal point . Price decimal point Documentation scheme
529-538 10 characters Digits 0-9 Numbers Documentation scheme
539-564 26 characters Uppercase A-Z Uppercase letters Documentation scheme
565-590 26 characters Lowercase a-z Lowercase letters Documentation scheme

Decoding Examples

# 编码示例
'U+0146' (326) → '2'                    # 评论数 (324-333)
'U+0152U+015FU+0156U+0150-U+0152U+0165U+015DU+015FU+0152U+0160U+0160' → 'ERIC-EXPRESS'      # 卖家名 (334-385)
'$U+0146U+0145U+0145U+0144U+0143U+0148U+0172+' → '$2110.4k+'           # 销售额 (323+324-333)
'U+0213' (531) → '2'                    # 数字 (529-538)
'U+021FU+022CU+0223U+021D-U+021FU+0232U+022AU+022CU+021FU+022DU+022D' → 'ERIC-EXPRESS'    # 卖家名 (539-564)
'$U+0213U+0212U+0212U+0211U+0210U+0215U+023F+' → '$2110.4k+'          # 销售额 (528-590)

Using the Decoder

Complete decoder: scripts/wmtwin_complete_decoder.py

# 解码JSON文件
python3 scripts/wmtwin_complete_decoder.py input.json -o output.json

# 从标准输入解码
cat input.json | python3 scripts/wmtwin_complete_decoder.py - -o output.json

Use in code:

from scripts.wmtwin_complete_decoder import decode_json, decode_json_file

# 方法1: 解码JSON对象
import json
with open('input.json') as f:
    data = json.load(f)
decoded_data = decode_json(data)

# 方法2: 直接解码文件
decoded_data = decode_json_file('input.json', 'output.json')

Decoded Fields

The decoder recursively decodes all string fields in the JSON, including:

Basic fields:

  • number_of_reviews: Review count
  • additional_offer_count: Seller count
  • sales_volume: Sales volume
  • sales_amount: Sales revenue

Seller fields (sellers):

  • display_name: Seller display name
  • name: Company name
  • seller_reviews: Seller review count
  • seller_rating: Seller rating

Sales trend (sales_trends):

  • sales_amount.label: Sales revenue label (e.g. $2110.4k+)
  • sales_volume.label: Sales volume label (e.g. 197.0k+)
  • month_sales_growth: Monthly growth
  • gross_profit: Gross profit
  • gross_profit_margin: Gross margin

Data Sources

Different data sources may use different encoding schemes:

  • API real-time data: Uses the 323-385 range (Scheme A)
  • Reference file: Uses the 528-590 range (Scheme B)
  • Decoder support: Supports both schemes

Verification

Verify whether decoding is complete:

# 检查是否还有编码字符
encoded_ranges = [(323, 323), (324, 333), (334, 385), (528, 590)]

def has_encoded_chars(text):
    if not isinstance(text, str):
        return False
    for char in text:
        code = ord(char)
        for start, end in encoded_ranges:
            if start <= code <= end:
                return True
    return False

# 检查解码后的数据
import json
with open('decoded.json') as f:
    data = json.load(f)

# 递归检查所有字符串字段
def check_decoded(obj):
    if isinstance(obj, dict):
        return all(check_decoded(v) for v in obj.values())
    elif isinstance(obj, list):
        return all(check_decoded(item) for item in obj)
    elif isinstance(obj, str):
        return not has_encoded_chars(obj)
    return True

is_fully_decoded = check_decoded(data)
print(f"完全解码: {is_fully_decoded}")

In Conversation Usage

When the user mentions 沃师傅 or related keywords, this skill is automatically triggered. Follow these steps:

  1. Check login status:

    from scripts.wmtwin_login import load_session
    session = load_session(phone)
    
  2. If not logged in, guide the user:

    • Start login process
    • Display CAPTCHA image to user
    • Ask user for CAPTCHA answer
    • Send SMS code
    • Ask user for SMS code
    • Complete login
  3. Call API with session:

    from scripts.wmtwin_login import call_api
    result = call_api(phone, endpoint, method, data)
    

Best Practices

  1. Always check login before API calls - Avoid 401/403 errors
  2. Show CAPTCHA image to user - Human input required for graphical CAPTCHA
  3. Clear error messages - Guide user through each step
  4. Session reuse - Don't login repeatedly if session exists
  5. Multi-account support - Each phone number has independent session

Debugging

View CAPTCHA

# macOS
open /tmp/linkfox_wmtwin_captcha.png

# Or in conversation
"帮我查看验证码图片"

View Session

cat /tmp/linkfox_wmtwin_sessions/13699998888.json | python3 -m json.tool

Clear Session

rm /tmp/linkfox_wmtwin_sessions/13699998888.json

Security

  • ✅ Password encrypted with RSA before transmission
  • ✅ HTTPS communication only
  • ✅ No plaintext password storage
  • ✅ Local session storage
  • ✅ Support for session cleanup

Performance

Operation Time
Password login attempt < 2s
Get CAPTCHA < 1s
Send SMS code < 2s
SMS login < 2s
API call (logged in) < 2s

Limitations

  • CAPTCHA recognition: Requires human input (no auto-recognition yet)
  • SMS verification: User must manually provide SMS code
  • Session expiry: Session may expire, requiring re-login

Competitor Search

Usage

Search Walmart competitors, with support for multiple filter conditions.Integrated automatic login feature, no need to manually manage login status.

✨ Automatic pagination feature

New feature: When the requested data volume exceeds the API single-page limit (50 items), the script automatically queries multiple pages and merges the results:

# 自动获取100条数据(自动查询2页)
python3 scripts/wmtwin_search_competitors.py \
    --keyword "iphone case" \
    --phone 15625238480 \
    --page-size 100 \
    -o results.json

Features:

  • ✅ Automatically detects whether the requested quantity exceeds the single-page limit (50 items)
  • ✅ Automatically queries multiple pages until the target quantity is reached
  • ✅ Automatically merges multi-page results into a single JSON file
  • ✅ Displays real-time query progress (retrieved/target total)
  • ✅ Supports all filter conditions

Automatic login process

When calling the search API, it will automatically:

  1. Check whether there is a valid login session
  2. If there is no session, guide the user to log in
  3. Automatically save the session after successful login
  4. Automatically load the saved session next time
  5. If the session expires, automatically log in again

Python code

from scripts.wmtwin_search_competitors import WMTwinCompetitorSearch

# 创建搜索客户端(提供手机号会自动加载已有登录)
client = WMTwinCompetitorSearch(phone="13699998888")

# 方法1: 使用参数字典(自动检查登录)
params = {
    "keyword": "iphone case",
    "is_wfs": True,
    "min_sales_volume": 200,
    "max_sales_volume": 800,
    "min_sales_amount": 200,
    "max_sales_amount": 800,
    "min_number_of_reviews": 50,
    "max_number_of_reviews": 100,
    "min_average_rating": 1.0,
    "max_average_rating": 5.0,
    "min_price": 1.0,
    "max_price": 10.0,
    "seller_name": "ERIC-EXPRESS",
    "brand": "Simyoung",
    "page": 1,
    "pageSize": 10
}
results = client.search_from_params(params)

# 方法2: 直接调用(自动检查登录)
results = client.search_competitors(
    keyword="iphone case",
    is_wfs=True,
    min_sales_volume=200,
    max_sales_volume=800,
    min_sales_amount=200,
    max_sales_amount=800,
    min_number_of_reviews=50,
    max_number_of_reviews=100,
    min_average_rating=1.0,
    max_average_rating=5.0,
    min_price=1.0,
    max_price=10.0,
    seller_name="ERIC-EXPRESS",
    brand="Simyoung",
    page=1,
    page_size=10
)

# 方法3: 提供登录信息(首次登录)
results = client.search_competitors(
    keyword="iphone",
    phone="13699998888",
    password="your_password",  # 可选,不提供会提示输入
    is_wfs=True
)

# 方法4: 自动分页获取大量数据(推荐)
results = client.search_multiple_pages(
    total_count=100,  # 自动查询多页直到获取100条
    keyword="iphone case",
    phone="15625238480",
    is_wfs=True,
    min_sales_volume=200
)
print(f"共获取 {len(results['data']['list'])} 条数据")

# 使用解码后的数据
for product in results['data']['list']:
    print(f"产品: {product['title']}")
    print(f"价格: {product['price']}")
    print(f"卖家: {product['sellers'][0]['display_name']}")
    print(f"销量: {product['sales_trends'][0]['sales_volume']['label']}")

Command line

# 基本搜索(会自动检查登录,需要时提示登录)
python3 scripts/wmtwin_search_competitors.py --keyword "iphone"

# 提供手机号(自动加载已有登录)
python3 scripts/wmtwin_search_competitors.py --keyword "iphone" --phone 13699998888

# 完整参数(自动管理登录)
python3 scripts/wmtwin_search_competitors.py \
    --keyword "iphone case" \
    --phone 13699998888 \
    --seller-name "ERIC-EXPRESS" \
    --brand "Simyoung" \
    --is-wfs \
    --min-sales 200 \
    --max-sales 800 \
    --min-sales-amount 200 \
    --max-sales-amount 800 \
    --min-reviews 50 \
    --max-reviews 100 \
    --min-rating 1.0 \
    --max-rating 5.0 \
    --min-price 1.0 \
    --max-price 10.0 \
    --page 1 \
    --page-size 10

# 模拟模式(无需登录,用于测试)
python3 scripts/wmtwin_search_competitors.py --keyword "iphone" --mock

# 从 JSON 文件读取参数
python3 scripts/wmtwin_search_competitors.py --from-json params.json --phone 13699998888

# 保存结果(自动保存原始和解码两个文件)
python3 scripts/wmtwin_search_competitors.py --keyword "iphone" --phone 13699998888 -o results.json
# 这将保存:
#   - results_raw.json (原始编码数据)
#   - results.json (解码后的数据)

Important notes:

  • When using -o When saving the parameter file, two files will be saved automatically:
    • <filename>_raw.json - Raw encoded data (data returned directly by the API)
    • <filename>.json - Decoded data (all characters have been decoded)
  • Subsequent operations always use the decoded file
  • The decoding process is automatic; no manual operation is required

Search parameters

Parameter name Type Required Description Example
keyword string Yes Search keyword "iphone"
is_wfs boolean No Search only WFS products true
min_sales_volume integer No Minimum sales volume 4000
max_sales_volume integer No Maximum sales volume 90000
min_sales_amount integer No Minimum sales amount 200
max_sales_amount integer No Maximum sales amount 800
min_number_of_reviews integer No Minimum number of reviews 50
max_number_of_reviews integer No Maximum number of reviews 100
min_average_rating float No Minimum rating (1-5) 1.0
max_average_rating float No Maximum rating (1-5) 5.0
min_price float No Minimum price 1.0
max_price float No Maximum price 10.0
seller_name string No Seller name "ERIC-EXPRESS"
brand string No Brand "Simyoung"
page integer No Page number (starting from 1) 1
pageSize integer No Number per page 10

Returned data structure

The returned data structure is the same as when calling other APIs after logging in, including product lists, seller information, sales data, etc. All encoded characters are automatically decoded.

For detailed data structure and field descriptions, see references/competitor_search.md。

Automatic decoding

Woshifu uses Unicode character encoding for data, and this tool automatically decodes it:

Encoding example (code point) Decoding result Type
U+021F… (seller name) ERIC-EXPRESS Seller name
U+0212 U+0213… $12.37 Price
U+0213 U+0211 U+0211 + 200+ Quantity
U+0213 U+0212… $2110.4k+ Sales amount

Common usage examples

# 1. 搜索高销量产品
results = client.search_competitors(
    keyword="phone case",
    min_sales_volume=10000,
    page_size=50
)

# 2. 只搜索 WFS 商品
results = client.search_competitors(
    keyword="iphone",
    is_wfs=True
)

# 3. 特定销量区间
results = client.search_competitors(
    keyword="charger",
    min_sales_volume=5000,
    max_sales_volume=50000
)

# 4. 按评论数和评分筛选
results = client.search_competitors(
    keyword="iphone case",
    min_number_of_reviews=50,
    max_number_of_reviews=100,
    min_average_rating=4.0,
    max_average_rating=5.0
)

# 5. 按价格范围筛选
results = client.search_competitors(
    keyword="phone charger",
    min_price=5.0,
    max_price=20.0
)

# 6. 按卖家和品牌筛选
results = client.search_competitors(
    keyword="iphone case",
    seller_name="ERIC-EXPRESS",
    brand="Simyoung"
)

# 7. 综合筛选(多条件组合)
results = client.search_competitors(
    keyword="iphone case",
    is_wfs=True,
    min_sales_volume=200,
    max_sales_volume=800,
    min_price=1.0,
    max_price=10.0,
    min_number_of_reviews=50,
    max_number_of_reviews=100,
    min_average_rating=1.0,
    max_average_rating=5.0,
    seller_name="ERIC-EXPRESS",
    brand="Simyoung",
    page=1,
    page_size=10
)

# 8. 分页获取所有数据
all_products = []
page = 1
while True:
    results = client.search_competitors(
        keyword="iphone",
        page=page,
        page_size=50
    )
    products = results['data']['list']
    if not products:
        break
    all_products.extend(products)
    page += 1

Command-line usage examples

# 基本搜索
python3 scripts/wmtwin_search_competitors.py --keyword "iphone case" --phone 15625238480

# 多条件筛选
python3 scripts/wmtwin_search_competitors.py \
    --keyword "iphone case" \
    --phone 15625238480 \
    --seller-name "ERIC-EXPRESS" \
    --brand "Simyoung" \
    --is-wfs \
    --min-sales 200 \
    --max-sales 800 \
    --min-sales-amount 200 \
    --max-sales-amount 800 \
    --min-reviews 50 \
    --max-reviews 100 \
    --min-rating 1.0 \
    --max-rating 5.0 \
    --min-price 1.0 \
    --max-price 10.0 \
    --page 1 \
    --page-size 10 \
    -o results.json

References

  • API Documentation: See references/api.md
  • Competitor Search API: See references/competitor_search.md
  • Auto Login Guide: See AUTO_LOGIN.md
  • Competitor Search Quick Start: See COMPETITOR_SEARCH.md
  • Login Script: See scripts/wmtwin_login.py
  • Search Script (with Auto Login): See scripts/wmtwin_search_competitors.py
  • Decoder: See scripts/wmtwin_complete_decoder.py
  • Decoding Guide: See DECODING.md
  • Auto Paging: See AUTO_PAGING.md

Handling Large Responses

To avoid overflowing the agent context, persist the response to disk and extract only the fields you need:

python scripts/response_io.py run --script scripts/wmtwin_complete_decoder.py --out-dir <DIR> '<params>'
python scripts/response_io.py read <file> --fields "<paths>"   # or --path "<JMESPath>"

Pick --out-dir outside any git working tree (e.g. /tmp/... on Unix, %TEMP%/... on Windows). Persisted responses may contain PII, pricing, or auth-sensitive data — do not commit them. Files are not auto-deleted; clean up when the task is done.

This skill exposes multiple entry scripts: wmtwin_complete_decoder.py, wmtwin_login.py, wmtwin_search_competitors.py. Pass --script scripts/<name>.py to choose the one you need.

run writes the full response to a file and emits only a schema preview + file path. read projects specific fields, with --limit/--offset for slicing and --format json|jsonl|csv|table for output.

When to prefer this pattern — apply your judgment based on the response characteristics, e.g.:

  • High field count per record, or fields you don't need
  • Batch/paginated results (multiple items per call)
  • Long-text fields (descriptions, reviews, HTML, time series)
  • Output reused across later steps rather than consumed immediately

For small, single-use responses, calling the main script directly is fine.

⚠️ The preview is a truncated schema + sample, not the full data. Any field-level decision must read from the persisted file via read.