dy-cli 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,376 @@
1
+ Metadata-Version: 2.4
2
+ Name: dy-cli
3
+ Version: 0.2.0
4
+ Summary: 抖音命令行工具 — 发布、搜索、下载、互动、数据分析、热榜、直播
5
+ Project-URL: Homepage, https://github.com/Youhai020616/douyin
6
+ Project-URL: Repository, https://github.com/Youhai020616/douyin
7
+ Project-URL: Issues, https://github.com/Youhai020616/douyin/issues
8
+ Author-email: Youhai <youhai020616@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: automation,cli,douyin,dy,tiktok,抖音
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Utilities
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: browser-cookie3>=0.19
19
+ Requires-Dist: click>=8.0
20
+ Requires-Dist: httpx>=0.27.0
21
+ Requires-Dist: playwright>=1.40
22
+ Requires-Dist: pyyaml>=6.0
23
+ Requires-Dist: rich>=13.0
24
+ Description-Content-Type: text/markdown
25
+
26
+ <p align="center">
27
+ <h1 align="center">🎬 douyin</h1>
28
+ <p align="center">AI-powered Douyin (抖音/TikTok China) automation — search, download, publish, engage, and analyze.</p>
29
+ </p>
30
+
31
+ <p align="center">
32
+ <a href="#cli-quick-start">CLI Quick Start</a> •
33
+ <a href="#features">Features</a> •
34
+ <a href="#commands">Commands</a> •
35
+ <a href="#scripts">Scripts</a> •
36
+ <a href="#claude-code-integration">Claude Code</a> •
37
+ <a href="./LICENSE">License</a>
38
+ </p>
39
+
40
+ ---
41
+
42
+ <p align="center">
43
+ <img src="./demo.gif" alt="dy-cli demo" width="800">
44
+ </p>
45
+
46
+ ## CLI Quick Start
47
+
48
+ The fastest way to get started — **3 commands** from zero to searching:
49
+
50
+ ```bash
51
+ # 1. Clone
52
+ git clone https://github.com/your-username/douyin.git
53
+ cd douyin
54
+
55
+ # 2. One-click install (auto: Python check → venv → pip install → Playwright Chromium)
56
+ bash setup.sh
57
+
58
+ # 3. Initialize (auto: install Chromium → config → QR login)
59
+ source activate.sh && dy init
60
+ ```
61
+
62
+ Then just use:
63
+
64
+ ```bash
65
+ dy search "AI创业" # Search
66
+ dy trending # Hot trending
67
+ dy download https://v.douyin.com/xxxxx/ # Download (no watermark)
68
+ dy publish -t "Hello" -c "My first post" -v video.mp4 # Publish
69
+ dy live info ROOM_ID # Live stream info
70
+ dy analytics # Dashboard
71
+ dy --help # All commands
72
+ ```
73
+
74
+ > 📖 Full CLI guide: [docs/cli-guide.md](docs/cli-guide.md)
75
+
76
+ ---
77
+
78
+ ## What is this?
79
+
80
+ A complete toolkit for automating Douyin (抖音/TikTok China) operations through two complementary engines:
81
+
82
+ | Engine | Technology | Use Cases | Startup |
83
+ |--------|-----------|-----------|---------|
84
+ | **API Client** | Python httpx, reverse-engineered API | Search, download, comments, trending, live | Instant |
85
+ | **Playwright** | Python Playwright, browser automation | Publish, login, analytics dashboard | On-demand |
86
+
87
+ Built as an [OpenClaw](https://github.com/openclaw/openclaw) Skill, but works standalone or with any MCP-compatible client (Claude Code, Cursor, etc.).
88
+
89
+ ## Features
90
+
91
+ - 🔍 **Search** — Keyword search with filters (sort, time, type)
92
+ - 📥 **Download** — No-watermark video/image download with progress bar
93
+ - 📝 **Publish** — Video and image posts with tags, scheduling, visibility
94
+ - 🔥 **Trending** — Real-time hot search rankings with watch mode
95
+ - 📺 **Live** — Live stream info, stream URL extraction, ffmpeg recording
96
+ - 💬 **Engage** — Comment, like, favorite, follow
97
+ - 📊 **Analytics** — Creator dashboard data export (CSV)
98
+ - 🔔 **Notifications** — Fetch interaction notifications
99
+ - 👤 **Profile** — Fetch any user's profile and posts
100
+ - 👥 **Multi-Account** — Isolated cookie storage per account
101
+ - 🔐 **QR Code Login** — Scan-to-login via Playwright, persistent cookie storage
102
+
103
+ ## Quick Start
104
+
105
+ ### Prerequisites
106
+
107
+ - Python 3.10+
108
+ - Playwright Chromium (auto-installed by `setup.sh`)
109
+ - ffmpeg (optional, for live recording: `brew install ffmpeg`)
110
+
111
+ ### 1. Clone & Install
112
+
113
+ ```bash
114
+ git clone https://github.com/your-username/douyin.git
115
+ cd douyin
116
+ bash setup.sh
117
+ ```
118
+
119
+ ### 2. Initialize & Login
120
+
121
+ ```bash
122
+ source activate.sh
123
+ dy init
124
+ ```
125
+
126
+ This will:
127
+ 1. Check your environment
128
+ 2. Install Playwright Chromium
129
+ 3. Configure proxy (optional)
130
+ 4. Open browser for QR code login
131
+
132
+ ### 3. Start Using
133
+
134
+ ```bash
135
+ dy search "旅行" # Search
136
+ dy trending # Hot topics
137
+ dy download URL # Download video
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Commands
143
+
144
+ ### Search & Discovery
145
+
146
+ ```bash
147
+ dy search "关键词" # Basic search
148
+ dy search "咖啡" --sort 最多点赞 # Sort by likes
149
+ dy search "春招" --time 一天内 --type video # Filters
150
+ dy trending # Hot trending list
151
+ dy trending --watch # Auto-refresh every 5 min
152
+ dy trending --json-output # JSON output
153
+ ```
154
+
155
+ ### Download
156
+
157
+ ```bash
158
+ dy download https://v.douyin.com/xxxxx/ # Share link
159
+ dy download https://www.douyin.com/video/123 # Full link
160
+ dy download 1234567890 # Video ID
161
+ dy download URL --music # Also download BGM
162
+ dy download URL -o ~/Videos # Custom output dir
163
+ ```
164
+
165
+ ### Publish
166
+
167
+ ```bash
168
+ # Video
169
+ dy publish -t "标题" -c "描述" -v video.mp4
170
+
171
+ # Image post
172
+ dy publish -t "标题" -c "描述" -i img1.jpg -i img2.jpg
173
+
174
+ # With tags
175
+ dy publish -t "旅行日记" -c "巴厘岛" -v trip.mp4 --tags 旅行 --tags 巴厘岛
176
+
177
+ # Private (test)
178
+ dy publish -t "测试" -c "测试" -v test.mp4 --visibility 仅自己可见
179
+
180
+ # Scheduled
181
+ dy publish -t "早安" -c "新的一天" -v morning.mp4 --schedule "2026-03-16T08:00:00+08:00"
182
+
183
+ # Preview only
184
+ dy publish -t "标题" -c "描述" -v video.mp4 --dry-run
185
+ ```
186
+
187
+ ### Video Detail & Comments
188
+
189
+ ```bash
190
+ dy detail AWEME_ID # Video detail
191
+ dy detail AWEME_ID --comments # With comments
192
+ dy comments AWEME_ID # Comments only
193
+ ```
194
+
195
+ ### Interaction
196
+
197
+ ```bash
198
+ dy like AWEME_ID # Like
199
+ dy favorite AWEME_ID # Favorite
200
+ dy comment AWEME_ID -c "Great!" # Comment
201
+ dy follow SEC_USER_ID # Follow user
202
+ ```
203
+
204
+ ### Live Stream
205
+
206
+ ```bash
207
+ dy live info ROOM_ID # Live info + stream URLs
208
+ dy live record ROOM_ID # Record with ffmpeg
209
+ dy live record ROOM_ID --quality HD1 # Specific quality
210
+ ```
211
+
212
+ ### Analytics & Notifications
213
+
214
+ ```bash
215
+ dy analytics # Creator dashboard
216
+ dy analytics --csv data.csv # Export CSV
217
+ dy notifications # Messages
218
+ ```
219
+
220
+ ### User Profile
221
+
222
+ ```bash
223
+ dy me # My info
224
+ dy profile SEC_USER_ID # User profile
225
+ dy profile SEC_USER_ID --posts # With post list
226
+ ```
227
+
228
+ ### Multi-Account
229
+
230
+ ```bash
231
+ dy account list # List accounts
232
+ dy account add work # Add & login
233
+ dy account default work # Set default
234
+ dy account remove work # Remove
235
+ ```
236
+
237
+ ### Configuration
238
+
239
+ ```bash
240
+ dy config show # Show config
241
+ dy config set api.proxy http://127.0.0.1:7897
242
+ dy config set default.download_dir ~/Videos
243
+ dy config reset # Reset to defaults
244
+ ```
245
+
246
+ ### Command Aliases
247
+
248
+ | Alias | Full Command |
249
+ |-------|-------------|
250
+ | `dy pub` | `dy publish` |
251
+ | `dy s` | `dy search` |
252
+ | `dy dl` | `dy download` |
253
+ | `dy t` | `dy trending` |
254
+ | `dy fav` | `dy favorite` |
255
+ | `dy noti` | `dy notifications` |
256
+ | `dy stat` | `dy status` |
257
+ | `dy acc` | `dy account` |
258
+ | `dy cfg` | `dy config` |
259
+
260
+ ---
261
+
262
+ ## Engine Architecture
263
+
264
+ | Engine | Features | Technology |
265
+ |--------|----------|------------|
266
+ | **API Client** | Search, download, comments, trending, live, user profile | httpx + reverse-engineered API |
267
+ | **Playwright** | Publish, login, analytics, notifications | Playwright browser automation |
268
+
269
+ Most commands auto-select the best engine. Only `publish`, `analytics`, and `login` require Playwright.
270
+
271
+ ---
272
+
273
+ ## Scripts
274
+
275
+ Standalone Python scripts for direct use without the CLI:
276
+
277
+ ```bash
278
+ # Login
279
+ python scripts/douyin_login.py --account default
280
+
281
+ # Publish video
282
+ python scripts/douyin_publisher.py -t "标题" -c "描述" -v video.mp4
283
+
284
+ # Publish images
285
+ python scripts/douyin_publisher.py -t "标题" -c "描述" -i img1.jpg img2.jpg
286
+
287
+ # Analytics
288
+ python scripts/douyin_analytics.py --csv output.csv
289
+
290
+ # Chrome management
291
+ python scripts/chrome_launcher.py
292
+ python scripts/chrome_launcher.py --kill
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Claude Code Integration
298
+
299
+ See [docs/claude-code-integration.md](docs/claude-code-integration.md) for setup instructions.
300
+
301
+ ## Project Structure
302
+
303
+ ```
304
+ douyin/
305
+ ├── README.md # This file
306
+ ├── SKILL.md # OpenClaw skill definition
307
+ ├── pyproject.toml # CLI package config
308
+ ├── manifest.json # Skill metadata
309
+ ├── LICENSE # MIT License
310
+ ├── requirements.txt # Python dependencies
311
+ ├── setup.sh # One-click install (macOS/Linux)
312
+ ├── setup.bat # One-click install (Windows)
313
+ ├── activate.sh # Environment activation
314
+ ├── src/dy_cli/ # ⭐ CLI package
315
+ │ ├── main.py # Unified entry point (dy command)
316
+ │ ├── engines/
317
+ │ │ ├── api_client.py # Reverse-engineered API client
318
+ │ │ └── playwright_client.py # Playwright browser automation
319
+ │ ├── commands/
320
+ │ │ ├── init.py # dy init (guided setup)
321
+ │ │ ├── auth.py # dy login/logout/status
322
+ │ │ ├── publish.py # dy publish (Playwright)
323
+ │ │ ├── search.py # dy search/detail (API)
324
+ │ │ ├── download.py # dy download (API) ⭐
325
+ │ │ ├── interact.py # dy like/comment/favorite/follow
326
+ │ │ ├── trending.py # dy trending (API) ⭐
327
+ │ │ ├── live.py # dy live info/record ⭐
328
+ │ │ ├── analytics.py # dy analytics (Playwright)
329
+ │ │ ├── profile.py # dy me/profile
330
+ │ │ ├── account.py # dy account management
331
+ │ │ └── config_cmd.py # dy config
332
+ │ └── utils/
333
+ │ ├── config.py # ~/.dy/config.json management
334
+ │ ├── output.py # Rich formatted output
335
+ │ └── signature.py # Douyin signature utilities
336
+ ├── scripts/
337
+ │ ├── douyin_login.py # Login script
338
+ │ ├── douyin_publisher.py # Publish script
339
+ │ ├── douyin_analytics.py # Analytics script
340
+ │ └── chrome_launcher.py # Chrome lifecycle
341
+ ├── config/
342
+ │ └── accounts.json.example
343
+ └── docs/
344
+ ├── cli-guide.md # CLI usage guide
345
+ └── claude-code-integration.md # Claude Code setup
346
+ ```
347
+
348
+ ## Platform Support
349
+
350
+ | Component | macOS | Linux | Windows |
351
+ |-----------|:-----:|:-----:|:-------:|
352
+ | **dy CLI** | ✅ | ✅ | ✅ |
353
+ | API Client | ✅ | ✅ | ✅ |
354
+ | Playwright | ✅ | ✅ | ✅ |
355
+
356
+ ## Tips & Known Issues
357
+
358
+ - **Signature algorithm**: Douyin frequently updates `a-bogus`/`x-bogus` — some API calls may need browser-based signing
359
+ - **Login**: Cookie expires periodically, re-login with `dy login`
360
+ - **Rate limiting**: Avoid rapid-fire requests, add delays between batch operations
361
+ - **Proxy**: Outside China may need proxy: `dy config set api.proxy http://...`
362
+ - **Live recording**: Requires ffmpeg: `brew install ffmpeg` (macOS)
363
+
364
+ ## Contributing
365
+
366
+ Issues and PRs welcome! Areas where help is needed:
367
+
368
+ - [ ] Improved `a-bogus` signature algorithm
369
+ - [ ] Batch download by user/hashtag
370
+ - [ ] Playwright interaction (like/comment/follow)
371
+ - [ ] More analytics data points
372
+ - [ ] Test suite
373
+
374
+ ## License
375
+
376
+ [MIT](./LICENSE)
@@ -0,0 +1,34 @@
1
+ scripts/chrome_launcher.py,sha256=wOsxSyoFx4XtFe7ZHK3O0RY9xlbf5U5OrbjYf4YaZhI,2269
2
+ scripts/douyin_analytics.py,sha256=iIom8IeHOz9KhZMOMWr4C1aOzeR4191XHt7Vb8jqrEw,3450
3
+ scripts/douyin_login.py,sha256=UTwK4-YiOCX6pXIck49PV9I6hTZv84Dy6G9evaDgeRI,1933
4
+ scripts/douyin_publisher.py,sha256=Ny2CVGxJnPcJ04dZWia_Mi5nuVDotTwHtMHOSmZYAWE,7033
5
+ dy_cli/__init__.py,sha256=KmtSQreEp4d8uycTz7chUSNz0tyEO6N0YRc94R6NAoU,65
6
+ dy_cli/main.py,sha256=sKXUUW_P_Kw4juTO7_019J-yACgtWVSFCdcgg7wFtHc,4212
7
+ dy_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ dy_cli/commands/account.py,sha256=Ahud5A2AaVkQ8NYoFSMEAeZWzzKP9uWAVnkj4zvMM54,3199
9
+ dy_cli/commands/analytics.py,sha256=HTrJHi7BfM9aHgq_kPzci3samFCZmAyh3XQEbLJT58g,3568
10
+ dy_cli/commands/auth.py,sha256=PGU43AC50wv6jOW9FGeFe149o8yNp2Tdv2NLaVxFj7U,5417
11
+ dy_cli/commands/config_cmd.py,sha256=5JFuUBCl4_8YAn7io85K6eFHSIOxEjy_Dl2YbbVgwDk,1752
12
+ dy_cli/commands/download.py,sha256=XMOt5KXHmZOeb0wloLVDIS6WEhqLjhWI1AtOy8b7fRU,7683
13
+ dy_cli/commands/init.py,sha256=SxVmG36TJ1fyhY1MHzEz1a4r96ffJ7Fsbpsj8_GgicQ,7555
14
+ dy_cli/commands/interact.py,sha256=X6I6wVlnvkeZ1EQ1zhyac-q2CjfrHZWR_ZAndTcpBk0,4881
15
+ dy_cli/commands/live.py,sha256=xbtF4A6Qg39YpNVhXP414NgH-G41K8d3RIkvKTNYbgk,4726
16
+ dy_cli/commands/profile.py,sha256=1cwgrYGBeF5iJRRceyzGkPZ568QTzox7ZROxGkAAmeg,2650
17
+ dy_cli/commands/publish.py,sha256=1UyxsTei4pROsaOP2hmgfbDb7Fucld2eiHwL18weEU4,4635
18
+ dy_cli/commands/search.py,sha256=UEzU1lgwm5i8cT4-N7CXgvxZShJtC6-nhNNUmgacDqk,4275
19
+ dy_cli/commands/trending.py,sha256=iUOs0JKffsXv4xcmA2Bxgp37HcXPEy4SpwcmuOVcDm4,2714
20
+ dy_cli/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ dy_cli/engines/api_client.py,sha256=AksJ-4jL_qYaUP5SyQWW3cLleDVccIOz41x81Ze4xO8,23211
22
+ dy_cli/engines/playwright_client.py,sha256=-p3DW_y1wXn0JxrHc2L-jgCwdRL_WmYRMofztofsw0Q,35198
23
+ dy_cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ dy_cli/utils/config.py,sha256=S73PvZvMWGZPJf3VYV3MnK-HwMXBMFWemRz7gU71BRA,2781
25
+ dy_cli/utils/envelope.py,sha256=cJj9LPhCwSfPr-Jxkvrktk02SSL3SOL898cSQCCidmA,1434
26
+ dy_cli/utils/export.py,sha256=I3aG7Li5y1K3MwZKmhdzUS09THRk-IFlnnGEwWJ0rDI,2034
27
+ dy_cli/utils/index_cache.py,sha256=o1uObcXCE1QHCeZ6Odfl4ch9GEfMt53rud4bVzM27uc,2815
28
+ dy_cli/utils/output.py,sha256=loqW4dc9JvEBWuLZBzabOSxK3yM2u2b46Y4H0fec3Pc,9715
29
+ dy_cli/utils/signature.py,sha256=LM4V_tieB-lHo5zmpIRlHKDBqcf_yS2_16OT1OR6nKo,5870
30
+ dy_cli-0.2.0.dist-info/METADATA,sha256=b-L_5nOb8FLJYocUlMm8r6OCvGfFA-UxTnVN7xk3eGk,12358
31
+ dy_cli-0.2.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
32
+ dy_cli-0.2.0.dist-info/entry_points.txt,sha256=FV1C9hRIdlkSnnNwvU515738x5AJxaFxFxFduCcjbAM,39
33
+ dy_cli-0.2.0.dist-info/licenses/LICENSE,sha256=ESYyLizI0WWtxMeS7rGVcX3ivMezm-HOd5WdeOh-9oU,1056
34
+ dy_cli-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ dy = dy_cli.main:cli
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,71 @@
1
+ """
2
+ Chrome/Chromium 生命周期管理。
3
+
4
+ Usage:
5
+ python scripts/chrome_launcher.py # 启动 (Playwright Chromium)
6
+ python scripts/chrome_launcher.py --headless # 无头模式
7
+ python scripts/chrome_launcher.py --kill # 关闭
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import asyncio
13
+ import os
14
+ import signal
15
+ import subprocess
16
+ import sys
17
+
18
+
19
+ async def launch_chromium(headless: bool = False):
20
+ """使用 Playwright 启动 Chromium。"""
21
+ from playwright.async_api import async_playwright
22
+
23
+ async with async_playwright() as pw:
24
+ browser = await pw.chromium.launch(headless=headless)
25
+ context = await browser.new_context()
26
+ page = await context.new_page()
27
+ await page.goto("https://www.douyin.com/", wait_until="domcontentloaded")
28
+
29
+ endpoint = browser._impl_obj._browser.ws_endpoint if hasattr(browser._impl_obj, '_browser') else "N/A"
30
+ print(f"[dy] Chromium 已启动")
31
+ print(f"[dy] Headless: {headless}")
32
+ print(f"[dy] 按 Ctrl+C 关闭")
33
+
34
+ try:
35
+ while True:
36
+ await asyncio.sleep(1)
37
+ except (KeyboardInterrupt, asyncio.CancelledError):
38
+ pass
39
+ finally:
40
+ await browser.close()
41
+ print("[dy] Chromium 已关闭")
42
+
43
+
44
+ def kill_chromium():
45
+ """关闭所有 Playwright Chromium 进程。"""
46
+ try:
47
+ if sys.platform == "darwin":
48
+ subprocess.run(["pkill", "-f", "chromium"], capture_output=True)
49
+ elif sys.platform == "win32":
50
+ subprocess.run(["taskkill", "/F", "/IM", "chromium.exe"], capture_output=True)
51
+ else:
52
+ subprocess.run(["pkill", "-f", "chromium"], capture_output=True)
53
+ print("[dy] Chromium 进程已终止")
54
+ except Exception as e:
55
+ print(f"[dy] 关闭失败: {e}")
56
+
57
+
58
+ def main():
59
+ parser = argparse.ArgumentParser(description="Chrome/Chromium 管理")
60
+ parser.add_argument("--headless", action="store_true", help="无头模式")
61
+ parser.add_argument("--kill", action="store_true", help="关闭 Chromium")
62
+ args = parser.parse_args()
63
+
64
+ if args.kill:
65
+ kill_chromium()
66
+ else:
67
+ asyncio.run(launch_chromium(headless=args.headless))
68
+
69
+
70
+ if __name__ == "__main__":
71
+ main()
@@ -0,0 +1,99 @@
1
+ """
2
+ 抖音数据看板脚本 — Playwright 爬取 creator.douyin.com 数据。
3
+
4
+ Usage:
5
+ python scripts/douyin_analytics.py
6
+ python scripts/douyin_analytics.py --csv output.csv
7
+ python scripts/douyin_analytics.py --account work
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import asyncio
13
+ import csv
14
+ import json
15
+ import os
16
+ import sys
17
+
18
+
19
+ async def get_analytics(account: str = "default", csv_file: str | None = None):
20
+ """获取创作者数据看板。"""
21
+ from playwright.async_api import async_playwright
22
+
23
+ cookie_file = os.path.expanduser(f"~/.dy/cookies/{account}.json")
24
+ if not os.path.isfile(cookie_file):
25
+ print(f"[dy] Cookie 文件不存在: {cookie_file}")
26
+ return None
27
+
28
+ async with async_playwright() as pw:
29
+ browser = await pw.chromium.launch(headless=True)
30
+ context = await browser.new_context(storage_state=cookie_file)
31
+ page = await context.new_page()
32
+
33
+ try:
34
+ print("[dy] 正在访问数据看板...")
35
+ await page.goto(
36
+ "https://creator.douyin.com/creator-micro/data/stats/self-content",
37
+ wait_until="domcontentloaded",
38
+ )
39
+ await page.wait_for_timeout(5000)
40
+
41
+ if await page.get_by_text("扫码登录").count() > 0:
42
+ print("[dy] Cookie 已失效")
43
+ return None
44
+
45
+ # Extract data
46
+ data = await page.evaluate("""() => {
47
+ const rows = [];
48
+ const items = document.querySelectorAll('tr, [class*="content-item"]');
49
+ items.forEach(item => {
50
+ const cells = item.querySelectorAll('td, [class*="cell"]');
51
+ if (cells.length >= 3) {
52
+ const texts = Array.from(cells).map(c => c.textContent.trim());
53
+ rows.push({
54
+ '标题': texts[0] || '-',
55
+ '发布时间': texts[1] || '-',
56
+ '播放': texts[2] || '-',
57
+ '完播率': texts[3] || '-',
58
+ '点赞': texts[4] || '-',
59
+ '评论': texts[5] || '-',
60
+ '分享': texts[6] || '-',
61
+ '涨粉': texts[7] || '-',
62
+ });
63
+ }
64
+ });
65
+ return rows;
66
+ }""")
67
+
68
+ print(f"[dy] 获取到 {len(data)} 条数据")
69
+
70
+ # Output JSON
71
+ print(json.dumps(data, ensure_ascii=False, indent=2))
72
+
73
+ # Export CSV
74
+ if csv_file and data:
75
+ keys = data[0].keys()
76
+ with open(csv_file, "w", newline="", encoding="utf-8-sig") as f:
77
+ writer = csv.DictWriter(f, fieldnames=keys)
78
+ writer.writeheader()
79
+ writer.writerows(data)
80
+ print(f"[dy] CSV 已导出: {csv_file}")
81
+
82
+ return data
83
+
84
+ finally:
85
+ await browser.close()
86
+
87
+
88
+ def main():
89
+ parser = argparse.ArgumentParser(description="抖音数据看板")
90
+ parser.add_argument("--account", default="default", help="账号名")
91
+ parser.add_argument("--csv", default=None, help="导出 CSV 文件路径")
92
+ args = parser.parse_args()
93
+
94
+ result = asyncio.run(get_analytics(args.account, args.csv))
95
+ sys.exit(0 if result is not None else 1)
96
+
97
+
98
+ if __name__ == "__main__":
99
+ main()
@@ -0,0 +1,64 @@
1
+ """
2
+ 抖音登录脚本 — Playwright 扫码登录,保存 Cookie。
3
+
4
+ Usage:
5
+ python scripts/douyin_login.py
6
+ python scripts/douyin_login.py --account work
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import asyncio
12
+ import os
13
+ import sys
14
+
15
+
16
+ async def login(account: str = "default"):
17
+ """打开浏览器扫码登录抖音。"""
18
+ from playwright.async_api import async_playwright
19
+
20
+ # Cookie save path
21
+ cookie_dir = os.path.expanduser("~/.dy/cookies")
22
+ os.makedirs(cookie_dir, exist_ok=True)
23
+ cookie_file = os.path.join(cookie_dir, f"{account}.json")
24
+
25
+ async with async_playwright() as pw:
26
+ browser = await pw.chromium.launch(headless=False)
27
+ context = await browser.new_context()
28
+ page = await context.new_page()
29
+
30
+ print("[dy] 正在打开抖音创作者中心...")
31
+ await page.goto("https://creator.douyin.com/", wait_until="domcontentloaded")
32
+
33
+ print("[dy] 请使用抖音 App 扫码登录")
34
+ print("[dy] 扫码后浏览器会自动关闭")
35
+
36
+ # Wait for login — detect navigation to creator dashboard
37
+ try:
38
+ await page.wait_for_url("**/creator-micro/**", timeout=120000)
39
+ await page.wait_for_timeout(3000)
40
+ print("[dy] 登录成功!")
41
+ except Exception:
42
+ print("[dy] 登录超时")
43
+ await browser.close()
44
+ return False
45
+
46
+ # Save cookies (playwright storage_state format)
47
+ await context.storage_state(path=cookie_file)
48
+ print(f"[dy] Cookie 已保存: {cookie_file}")
49
+
50
+ await browser.close()
51
+ return True
52
+
53
+
54
+ def main():
55
+ parser = argparse.ArgumentParser(description="抖音扫码登录")
56
+ parser.add_argument("--account", default="default", help="账号名 (默认: default)")
57
+ args = parser.parse_args()
58
+
59
+ ok = asyncio.run(login(args.account))
60
+ sys.exit(0 if ok else 1)
61
+
62
+
63
+ if __name__ == "__main__":
64
+ main()