walmart-price-monitor 0.2.1
沃尔玛价格监控工具 - 每天定时获取商品价格并写入钉钉表格
License: MIT
Requires Python: >=3.9
Keywords: dingtalk, price-monitor, spider, walmart

# 沃尔玛价格监控工具

每天定时从钉钉表格读取商品SKU，爬取沃尔玛价格并写回表格，支持促销价识别和历史价格追踪。

## 功能特性

- 定时任务自动执行（支持 Cron 表达式）
- 从钉钉表格读取商品 SKU
- 自动识别促销价/原价
- 智能防爬验证处理（Logo点击、验证码、按住验证等）
- 价格数据写回钉钉表格
- 历史价格记录自动追加
- 钉钉机器人通知（开始/完成/异常）
- 多实例并发支持

## 快速开始

### 1. 安装

```bash
# 使用 uvx 一键运行（推荐）
uvx walmart-price-monitor

# 或使用 pip 安装
pip install walmart-price-monitor

# 或克隆项目手动安装
git clone <repo-url>
cd WalmartAbby
pip install -e .
```

### 2. 配置

复制 `.env-example` 为 `.env`，填入配置：

```bash
cp .env-example .env
```

**必填配置项：**

| 配置项 | 说明 | 示例 |
|--------|------|------|
| `CRON_EXPRESSION` | 定时任务表达式 | `0 8 * * *`（每天8点） |
| `DINGTALK_WEBHOOK` | 钉钉机器人 Webhook | `https://oapi.dingtalk.com/robot/send?access_token=...` |
| `DINGTALK_SECRET` | 钉钉机器人密钥 | `SECxxxx` |
| `DINGTALK_DOC_URL` | 钉钉表格链接 | `https://alidocs.dingtalk.com/i/nodes/xxx` |
| `DINGTALK_APP_KEY` | 钉钉应用 AppKey | `dingxxxx` |
| `DINGTALK_APP_SECRET` | 钉钉应用 AppSecret | `xxxx` |
| `DINGTALK_OPERATOR_ID` | 操作人 UnionId | `xxxx` |
| `DATA_SHEET_NAME` | SKU 所在工作表名 | `ALL` |

**可选配置项：**

| 配置项 | 说明 | 默认值 |
|--------|------|--------|
| `DINGTALK_AT_MOBILES` | @指定人员手机号（逗号分隔） | 空（异常时@所有人） |
| `CHROME_USER_DATA_PATH` | Chrome 用户数据目录 | 空（自动使用系统Chrome） |
| `PROXY_ENABLED` | 是否启用代理 | `false` |
| `PROXY_POOL` | 代理地址池（逗号分隔） | 空 |

### 3. 运行

```bash
# 定时任务模式（默认）
python run.py

# 单次执行模式
python run.py --once

# uvx 运行
uvx walmart-price-monitor
uvx wpm --once
```

## 钉钉表格结构

| 行 | A列 | B列 | C列 | D列 | E列 | F列+ |
|----|-----|-----|-----|-----|-----|------|
| 1 | - | - | - | 日期（如"30日"） | - | 历史日期 |
| 2 | 商品ID | WM链接 | SKU | Price | Promo Price | 历史价格 |
| 3+ | **商品ID** | 链接 | SKU号 | **当前价格** | **促销价** | 历史数据 |

- **A列（商品ID）**：必填，沃尔玛商品ID（6-15位纯数字）
- **D列+**：程序自动写入，每次执行占用2列（价格+促销价）
- 同一天重复执行会覆盖当天数据

## 价格识别逻辑

1. **有促销时**（存在划线价）：
   - D列：原价（划线价）
   - E列：促销价（当前显示价）

2. **无促销时**：
   - D列：当前价格
   - E列：空

## 防爬处理

项目内置完善的防爬验证处理机制：

| 验证类型 | 处理方式 | 说明 |
|---------|---------|------|
| Logo点击 | 自动处理 | 最常见，成功率 >90% |
| 验证码 | 等待手动输入 | 最长等待2分钟 |
| 按住验证 | 自动模拟 | PerimeterX 验证 |
| 拼图验证 | 等待手动完成 | 需要人工操作 |
| 被封禁 | 返回错误 | 无法自动处理 |

**防爬优化建议：**
- 使用 Chrome 用户数据目录保持登录状态
- 避免短时间内大量请求（内置频率限制）
- 首次运行建议使用 `--once` 模式观察

## 多实例运行

同一台机器可运行多个爬虫实例，通过 `INSTANCE_ID` 区分：

```bash
# Windows CMD
set INSTANCE_ID=0 && python run.py --once   # 端口 9333
set INSTANCE_ID=1 && python run.py --once   # 端口 9334
set INSTANCE_ID=2 && python run.py --once   # 端口 9335

# Windows PowerShell
$env:INSTANCE_ID=1; python run.py --once

# Linux/macOS
INSTANCE_ID=1 python run.py --once
```

每个实例有独立的 Chrome 调试端口和用户数据目录。

## 通知示例

```markdown
### 沃尔玛价格监控报告

**执行时间**: 2024-02-01 08:00:00 ~ 08:15:32

**扫描统计**:
- 商品总数: 150 个
- 获取成功: 145 个
- 有促销价: 23 个
- 获取异常: 5 个

**异常商品**:
1. SKU: 10101089 - 页面不存在
2. SKU: 10102007 - 商品不可用

---
数据已更新至钉钉表格
```

## 目录结构

```
WalmartAbby/
├── app/
│   ├── cli.py                    # 入口（定时任务/单次执行）
│   ├── config.py                 # 配置管理
│   ├── notifier.py               # 钉钉通知
│   ├── dingtalk_doc_reader.py    # 钉钉文档API
│   ├── models/
│   │   └── price_result.py       # 价格结果模型
│   ├── readers/
│   │   └── sku_reader.py         # SKU读取器
│   ├── recorders/
│   │   └── price_recorder.py     # 价格记录器
│   ├── selectors/
│   │   └── walmart_selectors.py  # 页面选择器
│   ├── spiders/
│   │   ├── base_spider.py        # 爬虫基类
│   │   ├── walmart_spider.py     # 价格爬虫
│   │   └── walmart_bot_handler.py # 防爬处理器
│   └── utils/
│       ├── rate_limiter.py       # 频率限制
│       └── behavior_simulator.py # 人类行为模拟
├── docs/                         # 详细文档
├── data/                         # 数据目录（日志、备份）
├── run.py                        # 启动脚本
├── .env-example                  # 配置示例
└── pyproject.toml                # 项目配置
```

## 技术栈

- **Python** >= 3.9
- **DrissionPage** - 浏览器自动化
- **alibabacloud-dingtalk** - 钉钉文档 API
- **dingtalkchatbot** - 钉钉通知
- **croniter** - 定时任务

## 详细文档

更多详细说明请查看 [docs/](docs/README.md) 目录：

- [安装指南](docs/getting-started/installation.md)
- [配置指南](docs/getting-started/configuration.md)
- [快速入门](docs/getting-started/quick-start.md)
- [通知设置](docs/user-guide/notification-setup.md)
- [发布指南](docs/developer-guide/publish.md)

## License

MIT