🔄 卡若AI 同步 2026-03-23 13:49 | 更新:金仓、水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个
This commit is contained in:
@@ -1,7 +1,15 @@
|
|||||||
{
|
{
|
||||||
"updated": "2026-03-23T01:48:25.039999+00:00",
|
"updated": "2026-03-23T05:45:13.875278+00:00",
|
||||||
"conversations": [
|
"conversations": [
|
||||||
{
|
{
|
||||||
|
"对话ID": "aa70825b-eec2-4373-8c0f-86d550114599",
|
||||||
|
"名称": "下载视频号助手 macbook",
|
||||||
|
"项目": "微信管理",
|
||||||
|
"首条消息": "下载视频号助手 macbook",
|
||||||
|
"创建时间": "2026-03-23T05:43:55.225000+00:00",
|
||||||
|
"消息数量": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
"对话ID": "98abcf81-b237-44b7-af5a-dfe6d5bcb0ed",
|
"对话ID": "98abcf81-b237-44b7-af5a-dfe6d5bcb0ed",
|
||||||
"名称": "卡路亚复盘推送功能讨论",
|
"名称": "卡路亚复盘推送功能讨论",
|
||||||
"项目": "飞书",
|
"项目": "飞书",
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ ROWS = {
|
|||||||
'129': [ 'AI手机金融坏账投流', 200, 0, 250, 14, 187, 4, 561, 21, 31 ],
|
'129': [ 'AI手机金融坏账投流', 200, 0, 250, 14, 187, 4, 561, 21, 31 ],
|
||||||
# 130场 2026-03-21:视频号直播结束页 02:25:49≈146min;观众总数2278、最高在线355、新增关注4、总热度3、送礼1;Soul推流无截图数据填0→脚本跳过第5行保留空
|
# 130场 2026-03-21:视频号直播结束页 02:25:49≈146min;观众总数2278、最高在线355、新增关注4、总热度3、送礼1;Soul推流无截图数据填0→脚本跳过第5行保留空
|
||||||
'130': [ 'Soul爆量脸视频号问微信', 146, 0, 2278, 0, 3, 1, 3, 4, 355 ],
|
'130': [ 'Soul爆量脸视频号问微信', 146, 0, 2278, 0, 3, 1, 3, 4, 355 ],
|
||||||
# 131场 2026-03-23:结束页 02:05:55≈126min;观众总数1144、最高在线75、新增关注4;点赞1595+评论498+分享12=2105;礼物/灵魂力/人均未给填0;Soul推流无填0→跳过第5行
|
# 131场 2026-03-23:文章口径场观2580/进房328/128min;视频号结束页补关注4、最高在线75、点赞评论分享计互动;礼物灵魂力无截图填0
|
||||||
'131': [ '视频号中枢Soul哨兵', 126, 0, 1144, 0, 2105, 0, 0, 4, 75 ],
|
'131': [ '视频号中枢Soul做哨兵', 128, 2580, 328, 0, 2105, 0, 0, 4, 75 ],
|
||||||
}
|
}
|
||||||
# 场次→按日期列填写时的日期(表头为当月日期 1~31)
|
# 场次→按日期列填写时的日期(表头为当月日期 1~31)
|
||||||
SESSION_DATE_COLUMN = {'105': '20', '106': '21', '107': '23', '113': '2', '114': '3', '115': '4', '116': '5', '117': '6', '118': '7', '119': '8', '124': '14', '126': '17', '127': '18', '128': '19', '129': '20', '130': '21', '131': '23'}
|
SESSION_DATE_COLUMN = {'105': '20', '106': '21', '107': '23', '113': '2', '114': '3', '115': '4', '116': '5', '117': '6', '118': '7', '119': '8', '124': '14', '126': '17', '127': '18', '128': '19', '129': '20', '130': '21', '131': '23'}
|
||||||
@@ -96,6 +96,8 @@ PARTY_VIDEO_LINKS = {
|
|||||||
'127': 'https://cunkebao.feishu.cn/minutes/obcnhybw322112tad6916v8r',
|
'127': 'https://cunkebao.feishu.cn/minutes/obcnhybw322112tad6916v8r',
|
||||||
'129': 'https://cunkebao.feishu.cn/minutes/obcnjb994323l12lhl448177',
|
'129': 'https://cunkebao.feishu.cn/minutes/obcnjb994323l12lhl448177',
|
||||||
'130': 'https://cunkebao.feishu.cn/minutes/obcnj1y95z73n53e8m6m1s3j',
|
'130': 'https://cunkebao.feishu.cn/minutes/obcnj1y95z73n53e8m6m1s3j',
|
||||||
|
# 131场:urls_soul_party.txt 中紧接 130 的新妙记
|
||||||
|
'131': 'https://cunkebao.feishu.cn/minutes/obcnjzx7dyxco67btud7y8gz',
|
||||||
}
|
}
|
||||||
|
|
||||||
# 团队会议(飞书妙记)链接:场次 → 完整 URL,填表时写入「团队会议」行对应列(row 31)
|
# 团队会议(飞书妙记)链接:场次 → 完整 URL,填表时写入「团队会议」行对应列(row 31)
|
||||||
@@ -110,6 +112,7 @@ TEAM_MEETING_LINKS = {
|
|||||||
'126': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcng991jg3114b2nj99548d',
|
'126': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcng991jg3114b2nj99548d',
|
||||||
'127': 'https://cunkebao.feishu.cn/minutes/obcnhxs8usi8c7n27a9f66ux',
|
'127': 'https://cunkebao.feishu.cn/minutes/obcnhxs8usi8c7n27a9f66ux',
|
||||||
'129': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcnjbn178iy6919od4119ww',
|
'129': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcnjbn178iy6919od4119ww',
|
||||||
|
'131': 'https://kcnxrqd5ata7.feishu.cn/minutes/obcnjzx7dyxco67btud7y8gz',
|
||||||
}
|
}
|
||||||
|
|
||||||
# 小程序当日运营数据:日期号 → {访问次数, 访客, 交易金额},填表时自动写入对应日期列
|
# 小程序当日运营数据:日期号 → {访问次数, 访客, 交易金额},填表时自动写入对应日期列
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""B站 Cookie 获取 - Playwright 扫码登录 → 保存 storage_state"""
|
"""B站 Cookie 获取 - Playwright 扫码登录 → 保存 storage_state"""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
|
|
||||||
COOKIE_FILE = Path(__file__).parent / "bilibili_storage_state.json"
|
COOKIE_FILE = Path(__file__).parent / "bilibili_storage_state.json"
|
||||||
LOGIN_URL = "https://passport.bilibili.com/login"
|
LOGIN_URL = "https://passport.bilibili.com/login"
|
||||||
|
PROFILE_PLATFORM = "B站"
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "多平台分发" / "脚本"))
|
||||||
|
from browser_profile import get_browser_profile_dir
|
||||||
|
|
||||||
UA = (
|
UA = (
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
||||||
@@ -14,14 +19,20 @@ UA = (
|
|||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
|
profile_dir = get_browser_profile_dir(PROFILE_PLATFORM)
|
||||||
print("即将弹出浏览器,请用 B站 APP 扫码登录。")
|
print("即将弹出浏览器,请用 B站 APP 扫码登录。")
|
||||||
|
print(f"固定浏览器目录: {profile_dir}")
|
||||||
print("登录成功后(看到创作中心页面),按 Enter 或在 Inspector 点绿色 ▶。\n")
|
print("登录成功后(看到创作中心页面),按 Enter 或在 Inspector 点绿色 ▶。\n")
|
||||||
|
|
||||||
async with async_playwright() as pw:
|
async with async_playwright() as pw:
|
||||||
browser = await pw.chromium.launch(headless=False)
|
context = await pw.chromium.launch_persistent_context(
|
||||||
context = await browser.new_context(user_agent=UA, viewport={"width": 1280, "height": 720})
|
str(profile_dir),
|
||||||
|
headless=False,
|
||||||
|
user_agent=UA,
|
||||||
|
viewport={"width": 1280, "height": 720},
|
||||||
|
)
|
||||||
await context.add_init_script("Object.defineProperty(navigator,'webdriver',{get:()=>undefined})")
|
await context.add_init_script("Object.defineProperty(navigator,'webdriver',{get:()=>undefined})")
|
||||||
page = await context.new_page()
|
page = context.pages[0] if context.pages else await context.new_page()
|
||||||
await page.goto(LOGIN_URL, timeout=60000)
|
await page.goto(LOGIN_URL, timeout=60000)
|
||||||
|
|
||||||
print("等待登录完成...")
|
print("等待登录完成...")
|
||||||
@@ -33,7 +44,6 @@ async def main():
|
|||||||
|
|
||||||
await context.storage_state(path=str(COOKIE_FILE))
|
await context.storage_state(path=str(COOKIE_FILE))
|
||||||
await context.close()
|
await context.close()
|
||||||
await browser.close()
|
|
||||||
|
|
||||||
print(f"\n[✓] B站 Cookie 已保存: {COOKIE_FILE}")
|
print(f"\n[✓] B站 Cookie 已保存: {COOKIE_FILE}")
|
||||||
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")
|
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")
|
||||||
|
|||||||
30
03_卡木(木)/木叶_视频内容/多平台分发/脚本/browser_profile.py
Normal file
30
03_卡木(木)/木叶_视频内容/多平台分发/脚本/browser_profile.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""多平台分发统一浏览器配置。"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
PROFILE_ROOT = Path(
|
||||||
|
os.environ.get("SOUL_DISTRIBUTION_BROWSER_ROOT", "~/.soul-distribution-browser")
|
||||||
|
).expanduser()
|
||||||
|
|
||||||
|
_PLATFORM_DIR = {
|
||||||
|
"视频号": "channels",
|
||||||
|
"抖音": "douyin",
|
||||||
|
"B站": "bilibili",
|
||||||
|
"小红书": "xiaohongshu",
|
||||||
|
"快手": "kuaishou",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_browser_profile_dir(platform: str) -> Path:
|
||||||
|
"""返回平台固定 Profile 目录(自动创建)。"""
|
||||||
|
name = _PLATFORM_DIR.get(platform, platform)
|
||||||
|
p = PROFILE_ROOT / name
|
||||||
|
p.mkdir(parents=True, exist_ok=True)
|
||||||
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
def profile_root_str() -> str:
|
||||||
|
return str(PROFILE_ROOT)
|
||||||
@@ -50,8 +50,70 @@ from schedule_generator import (
|
|||||||
format_schedule,
|
format_schedule,
|
||||||
)
|
)
|
||||||
from video_metadata import VideoMeta
|
from video_metadata import VideoMeta
|
||||||
|
from browser_profile import get_browser_profile_dir, profile_root_str
|
||||||
|
|
||||||
CHANNELS_LOGIN_SCRIPT = BASE_DIR / "视频号发布" / "脚本" / "channels_login.py"
|
CHANNELS_LOGIN_SCRIPT = BASE_DIR / "视频号发布" / "脚本" / "channels_login.py"
|
||||||
|
LOGIN_COMMANDS = {
|
||||||
|
"抖音": f'python3 "{BASE_DIR / "抖音发布" / "脚本" / "douyin_login.py"}"',
|
||||||
|
"B站": f'python3 "{BASE_DIR / "B站发布" / "脚本" / "bilibili_login.py"}"',
|
||||||
|
"视频号": f'python3 "{BASE_DIR / "视频号发布" / "脚本" / "channels_login.py"} --playwright-only"',
|
||||||
|
"小红书": f'python3 "{BASE_DIR / "小红书发布" / "脚本" / "xiaohongshu_login.py"}"',
|
||||||
|
"快手": f'python3 "{BASE_DIR / "快手发布" / "脚本" / "kuaishou_login.py"}"',
|
||||||
|
}
|
||||||
|
BAN_KEYWORDS = ("封禁", "封号", "禁止", "冻结", "suspend", "banned", "risk", "风控", "限制")
|
||||||
|
|
||||||
|
|
||||||
|
def _print_unified_browser_profiles() -> None:
|
||||||
|
print(f"\n 统一浏览器根目录: {profile_root_str()}")
|
||||||
|
for p in PLATFORM_CONFIG:
|
||||||
|
print(f" - {p}: {get_browser_profile_dir(p)}")
|
||||||
|
|
||||||
|
|
||||||
|
def _classify_platform_status(
|
||||||
|
platform: str,
|
||||||
|
platform_results: list[PublishResult],
|
||||||
|
) -> tuple[str, str]:
|
||||||
|
if not platform_results:
|
||||||
|
ok, msg = check_cookie_valid(platform)
|
||||||
|
if ok:
|
||||||
|
return "空闲/未执行", "本轮未执行该平台发布"
|
||||||
|
return "需重登", f"Cookie 无效:{msg}"
|
||||||
|
|
||||||
|
successes = [r for r in platform_results if r.success]
|
||||||
|
failures = [r for r in platform_results if not r.success]
|
||||||
|
failure_msgs = " | ".join((r.message or "").lower() for r in failures)
|
||||||
|
|
||||||
|
if any(k in failure_msgs for k in BAN_KEYWORDS):
|
||||||
|
return "疑似封禁/风控", "失败信息包含封禁/风控关键词"
|
||||||
|
if successes and not failures:
|
||||||
|
return "正常", f"成功 {len(successes)}/{len(platform_results)}"
|
||||||
|
if failures and not successes:
|
||||||
|
ok, msg = check_cookie_valid(platform)
|
||||||
|
if not ok:
|
||||||
|
return "需重登", f"Cookie 无效:{msg}"
|
||||||
|
return "持续失败", f"失败 {len(failures)} 条,需人工排查平台侧限制"
|
||||||
|
if failures:
|
||||||
|
return "部分失败", f"成功 {len(successes)} / 失败 {len(failures)}"
|
||||||
|
return "正常", f"成功 {len(successes)}/{len(platform_results)}"
|
||||||
|
|
||||||
|
|
||||||
|
def print_platform_account_status(all_results: list[PublishResult], targets: list[str]) -> None:
|
||||||
|
print(f"\n{'=' * 60}")
|
||||||
|
print(" 平台账号状态复盘")
|
||||||
|
print(f"{'=' * 60}")
|
||||||
|
regroup: dict[str, list[PublishResult]] = {p: [] for p in targets}
|
||||||
|
for r in all_results:
|
||||||
|
if r.platform in regroup and r.status != "skipped":
|
||||||
|
regroup[r.platform].append(r)
|
||||||
|
|
||||||
|
for p in targets:
|
||||||
|
status, detail = _classify_platform_status(p, regroup[p])
|
||||||
|
print(f" [{p}] {status} | {detail}")
|
||||||
|
if status in ("需重登", "持续失败", "疑似封禁/风控"):
|
||||||
|
cmd = LOGIN_COMMANDS.get(p, "")
|
||||||
|
if cmd:
|
||||||
|
print(f" 重登命令: {cmd}")
|
||||||
|
print(f"{'=' * 60}\n")
|
||||||
|
|
||||||
|
|
||||||
def _ensure_channels_cookie_or_login(*, auto_login: bool) -> None:
|
def _ensure_channels_cookie_or_login(*, auto_login: bool) -> None:
|
||||||
@@ -433,6 +495,8 @@ async def main():
|
|||||||
)
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
_print_unified_browser_profiles()
|
||||||
|
|
||||||
if not args.allow_ui_browser:
|
if not args.allow_ui_browser:
|
||||||
os.environ.setdefault("PUBLISH_PLAYWRIGHT_HEADLESS", "1")
|
os.environ.setdefault("PUBLISH_PLAYWRIGHT_HEADLESS", "1")
|
||||||
|
|
||||||
@@ -525,9 +589,8 @@ async def _publish_one_round(args: argparse.Namespace) -> tuple[int, int]:
|
|||||||
|
|
||||||
if not available:
|
if not available:
|
||||||
print("\n[✗] 没有可用平台,请先登录:")
|
print("\n[✗] 没有可用平台,请先登录:")
|
||||||
for p, c in PLATFORM_CONFIG.items():
|
for p in PLATFORM_CONFIG:
|
||||||
login = str(c["script"]).replace("publish", "login").replace("pure_api", "login")
|
print(f" {p}: {LOGIN_COMMANDS.get(p, '(未配置)')}")
|
||||||
print(f" {p}: python3 {login}")
|
|
||||||
return 1, 9999
|
return 1, 9999
|
||||||
|
|
||||||
targets = args.platforms if args.platforms else available
|
targets = args.platforms if args.platforms else available
|
||||||
@@ -613,6 +676,7 @@ async def _publish_one_round(args: argparse.Namespace) -> tuple[int, int]:
|
|||||||
print(f"\n 有 {failed_count} 条失败,可执行: python3 distribute_all.py --retry")
|
print(f"\n 有 {failed_count} 条失败,可执行: python3 distribute_all.py --retry")
|
||||||
|
|
||||||
failed_non_success = sum(1 for r in actual_results if not r.success)
|
failed_non_success = sum(1 for r in actual_results if not r.success)
|
||||||
|
print_platform_account_status(actual_results, targets)
|
||||||
return (0 if ok == total else 1), failed_non_success
|
return (0 if ok == total else 1), failed_non_success
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ import time
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
BASE = Path("/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容")
|
BASE = Path("/Users/karuo/Documents/个人/卡若AI/03_卡木(木)/木叶_视频内容")
|
||||||
|
sys.path.insert(0, str(BASE / "多平台分发" / "脚本"))
|
||||||
|
from browser_profile import get_browser_profile_dir
|
||||||
|
|
||||||
UA = (
|
UA = (
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
||||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"
|
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"
|
||||||
@@ -96,14 +99,13 @@ async def headless_login(platform: str) -> bool:
|
|||||||
print(f"{'='*60}")
|
print(f"{'='*60}")
|
||||||
|
|
||||||
async with async_playwright() as pw:
|
async with async_playwright() as pw:
|
||||||
browser = await pw.chromium.launch(
|
context = await pw.chromium.launch_persistent_context(
|
||||||
|
str(get_browser_profile_dir(platform)),
|
||||||
headless=True,
|
headless=True,
|
||||||
args=["--disable-blink-features=AutomationControlled"],
|
|
||||||
)
|
|
||||||
context = await browser.new_context(
|
|
||||||
user_agent=UA,
|
user_agent=UA,
|
||||||
viewport={"width": 1280, "height": 900},
|
viewport={"width": 1280, "height": 900},
|
||||||
locale="zh-CN",
|
locale="zh-CN",
|
||||||
|
args=["--disable-blink-features=AutomationControlled"],
|
||||||
)
|
)
|
||||||
await context.add_init_script(
|
await context.add_init_script(
|
||||||
"Object.defineProperty(navigator,'webdriver',{get:()=>undefined})"
|
"Object.defineProperty(navigator,'webdriver',{get:()=>undefined})"
|
||||||
@@ -189,7 +191,7 @@ async def headless_login(platform: str) -> bool:
|
|||||||
|
|
||||||
await context.storage_state(path=str(cookie_file))
|
await context.storage_state(path=str(cookie_file))
|
||||||
size = cookie_file.stat().st_size
|
size = cookie_file.stat().st_size
|
||||||
await browser.close()
|
await context.close()
|
||||||
|
|
||||||
# API 验证
|
# API 验证
|
||||||
print(f" [4] API 验证 Cookie...", flush=True)
|
print(f" [4] API 验证 Cookie...", flush=True)
|
||||||
@@ -203,7 +205,7 @@ async def headless_login(platform: str) -> bool:
|
|||||||
else:
|
else:
|
||||||
print(f" [✗] {platform} 登录超时(5分钟)", flush=True)
|
print(f" [✗] {platform} 登录超时(5分钟)", flush=True)
|
||||||
await page.screenshot(path=f"/tmp/login_timeout_{platform}.png")
|
await page.screenshot(path=f"/tmp/login_timeout_{platform}.png")
|
||||||
await browser.close()
|
await context.close()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""小红书 Cookie 获取 - Playwright 登录 → 保存 storage_state"""
|
"""小红书 Cookie 获取 - Playwright 登录 → 保存 storage_state"""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
|
|
||||||
COOKIE_FILE = Path(__file__).parent / "xiaohongshu_storage_state.json"
|
COOKIE_FILE = Path(__file__).parent / "xiaohongshu_storage_state.json"
|
||||||
LOGIN_URL = "https://creator.xiaohongshu.com/login"
|
LOGIN_URL = "https://creator.xiaohongshu.com/login"
|
||||||
|
PROFILE_PLATFORM = "小红书"
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "多平台分发" / "脚本"))
|
||||||
|
from browser_profile import get_browser_profile_dir
|
||||||
|
|
||||||
UA = (
|
UA = (
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
||||||
@@ -14,15 +19,21 @@ UA = (
|
|||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
|
profile_dir = get_browser_profile_dir(PROFILE_PLATFORM)
|
||||||
print("即将弹出浏览器,请登录小红书创作者中心。")
|
print("即将弹出浏览器,请登录小红书创作者中心。")
|
||||||
print("支持扫码或手机号+验证码登录。")
|
print("支持扫码或手机号+验证码登录。")
|
||||||
|
print(f"固定浏览器目录: {profile_dir}")
|
||||||
print("登录成功后(看到创作者中心主页),按 Enter 或在 Inspector 点绿色 ▶。\n")
|
print("登录成功后(看到创作者中心主页),按 Enter 或在 Inspector 点绿色 ▶。\n")
|
||||||
|
|
||||||
async with async_playwright() as pw:
|
async with async_playwright() as pw:
|
||||||
browser = await pw.chromium.launch(headless=False)
|
context = await pw.chromium.launch_persistent_context(
|
||||||
context = await browser.new_context(user_agent=UA, viewport={"width": 1280, "height": 720})
|
str(profile_dir),
|
||||||
|
headless=False,
|
||||||
|
user_agent=UA,
|
||||||
|
viewport={"width": 1280, "height": 720},
|
||||||
|
)
|
||||||
await context.add_init_script("Object.defineProperty(navigator,'webdriver',{get:()=>undefined})")
|
await context.add_init_script("Object.defineProperty(navigator,'webdriver',{get:()=>undefined})")
|
||||||
page = await context.new_page()
|
page = context.pages[0] if context.pages else await context.new_page()
|
||||||
await page.goto(LOGIN_URL, timeout=60000)
|
await page.goto(LOGIN_URL, timeout=60000)
|
||||||
|
|
||||||
print("等待登录完成...")
|
print("等待登录完成...")
|
||||||
@@ -35,7 +46,6 @@ async def main():
|
|||||||
|
|
||||||
await context.storage_state(path=str(COOKIE_FILE))
|
await context.storage_state(path=str(COOKIE_FILE))
|
||||||
await context.close()
|
await context.close()
|
||||||
await browser.close()
|
|
||||||
|
|
||||||
print(f"\n[✓] 小红书 Cookie 已保存: {COOKIE_FILE}")
|
print(f"\n[✓] 小红书 Cookie 已保存: {COOKIE_FILE}")
|
||||||
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")
|
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""快手 Cookie 获取 - Playwright 扫码登录 → 保存 storage_state"""
|
"""快手 Cookie 获取 - Playwright 扫码登录 → 保存 storage_state"""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
|
|
||||||
COOKIE_FILE = Path(__file__).parent / "kuaishou_storage_state.json"
|
COOKIE_FILE = Path(__file__).parent / "kuaishou_storage_state.json"
|
||||||
LOGIN_URL = "https://cp.kuaishou.com/article/publish/video"
|
LOGIN_URL = "https://cp.kuaishou.com/article/publish/video"
|
||||||
|
PROFILE_PLATFORM = "快手"
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "多平台分发" / "脚本"))
|
||||||
|
from browser_profile import get_browser_profile_dir
|
||||||
|
|
||||||
UA = (
|
UA = (
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
||||||
@@ -14,14 +19,20 @@ UA = (
|
|||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
|
profile_dir = get_browser_profile_dir(PROFILE_PLATFORM)
|
||||||
print("即将弹出浏览器,请用快手 APP 扫码登录创作者服务平台。")
|
print("即将弹出浏览器,请用快手 APP 扫码登录创作者服务平台。")
|
||||||
|
print(f"固定浏览器目录: {profile_dir}")
|
||||||
print("登录成功后(看到创作中心页面),按 Enter 或在 Inspector 点绿色 ▶。\n")
|
print("登录成功后(看到创作中心页面),按 Enter 或在 Inspector 点绿色 ▶。\n")
|
||||||
|
|
||||||
async with async_playwright() as pw:
|
async with async_playwright() as pw:
|
||||||
browser = await pw.chromium.launch(headless=False)
|
context = await pw.chromium.launch_persistent_context(
|
||||||
context = await browser.new_context(user_agent=UA, viewport={"width": 1280, "height": 720})
|
str(profile_dir),
|
||||||
|
headless=False,
|
||||||
|
user_agent=UA,
|
||||||
|
viewport={"width": 1280, "height": 720},
|
||||||
|
)
|
||||||
await context.add_init_script("Object.defineProperty(navigator,'webdriver',{get:()=>undefined})")
|
await context.add_init_script("Object.defineProperty(navigator,'webdriver',{get:()=>undefined})")
|
||||||
page = await context.new_page()
|
page = context.pages[0] if context.pages else await context.new_page()
|
||||||
await page.goto(LOGIN_URL, timeout=60000)
|
await page.goto(LOGIN_URL, timeout=60000)
|
||||||
|
|
||||||
print("等待扫码登录...\n")
|
print("等待扫码登录...\n")
|
||||||
@@ -49,7 +60,6 @@ async def main():
|
|||||||
|
|
||||||
await context.storage_state(path=str(COOKIE_FILE))
|
await context.storage_state(path=str(COOKIE_FILE))
|
||||||
await context.close()
|
await context.close()
|
||||||
await browser.close()
|
|
||||||
|
|
||||||
print(f"\n[✓] 快手 Cookie 已保存: {COOKIE_FILE}")
|
print(f"\n[✓] 快手 Cookie 已保存: {COOKIE_FILE}")
|
||||||
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")
|
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")
|
||||||
|
|||||||
@@ -4,19 +4,27 @@
|
|||||||
扫码后无需手动操作,脚本自动检测登录状态并保存。
|
扫码后无需手动操作,脚本自动检测登录状态并保存。
|
||||||
"""
|
"""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from playwright.async_api import async_playwright
|
from playwright.async_api import async_playwright
|
||||||
|
|
||||||
COOKIE_FILE = Path(__file__).parent / "douyin_storage_state.json"
|
COOKIE_FILE = Path(__file__).parent / "douyin_storage_state.json"
|
||||||
|
PROFILE_PLATFORM = "抖音"
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "多平台分发" / "脚本"))
|
||||||
|
from browser_profile import get_browser_profile_dir
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
|
profile_dir = get_browser_profile_dir(PROFILE_PLATFORM)
|
||||||
print("即将弹出浏览器,请用抖音 APP 扫码登录。")
|
print("即将弹出浏览器,请用抖音 APP 扫码登录。")
|
||||||
|
print(f"固定浏览器目录: {profile_dir}")
|
||||||
print("登录成功后脚本会自动保存 Cookie,无需手动操作。\n")
|
print("登录成功后脚本会自动保存 Cookie,无需手动操作。\n")
|
||||||
|
|
||||||
async with async_playwright() as pw:
|
async with async_playwright() as pw:
|
||||||
browser = await pw.chromium.launch(headless=False)
|
context = await pw.chromium.launch_persistent_context(
|
||||||
context = await browser.new_context(
|
str(profile_dir),
|
||||||
|
headless=False,
|
||||||
user_agent=(
|
user_agent=(
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
||||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||||
@@ -27,7 +35,7 @@ async def main():
|
|||||||
await context.add_init_script("""
|
await context.add_init_script("""
|
||||||
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
|
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
|
||||||
""")
|
""")
|
||||||
page = await context.new_page()
|
page = context.pages[0] if context.pages else await context.new_page()
|
||||||
await page.goto("https://creator.douyin.com/", timeout=60000)
|
await page.goto("https://creator.douyin.com/", timeout=60000)
|
||||||
|
|
||||||
print("[i] 等待扫码登录... (最长等待 120 秒)")
|
print("[i] 等待扫码登录... (最长等待 120 秒)")
|
||||||
@@ -56,7 +64,6 @@ async def main():
|
|||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
await context.storage_state(path=str(COOKIE_FILE))
|
await context.storage_state(path=str(COOKIE_FILE))
|
||||||
await context.close()
|
await context.close()
|
||||||
await browser.close()
|
|
||||||
|
|
||||||
print(f"\n[✓] Cookie 已保存到: {COOKIE_FILE}")
|
print(f"\n[✓] Cookie 已保存到: {COOKIE_FILE}")
|
||||||
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")
|
print(f" 文件大小: {COOKIE_FILE.stat().st_size} bytes")
|
||||||
|
|||||||
@@ -22,8 +22,14 @@ QR_SCREENSHOT = Path("/tmp/channels_qr.png")
|
|||||||
|
|
||||||
DEFAULT_CDP = os.environ.get("CHANNELS_CDP_URL", "http://127.0.0.1:9223")
|
DEFAULT_CDP = os.environ.get("CHANNELS_CDP_URL", "http://127.0.0.1:9223")
|
||||||
# 持久化 Chromium:同目录保留登录态,显著减少重复扫码(腾讯侧过期/风控时仍需重登)
|
# 持久化 Chromium:同目录保留登录态,显著减少重复扫码(腾讯侧过期/风控时仍需重登)
|
||||||
|
sys.path.insert(0, str(SCRIPT_DIR.parent.parent / "多平台分发" / "脚本"))
|
||||||
|
from browser_profile import get_browser_profile_dir
|
||||||
|
|
||||||
PERSISTENT_PROFILE_DIR = Path(
|
PERSISTENT_PROFILE_DIR = Path(
|
||||||
os.environ.get("CHANNELS_CHROMIUM_USER_DATA", str(Path.home() / ".soul-channels-playwright-profile"))
|
os.environ.get(
|
||||||
|
"CHANNELS_CHROMIUM_USER_DATA",
|
||||||
|
str(get_browser_profile_dir("视频号")),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
UA = (
|
UA = (
|
||||||
|
|||||||
@@ -422,3 +422,4 @@
|
|||||||
| 2026-03-22 14:38:11 | 🔄 卡若AI 同步 2026-03-22 14:38 | 更新:Cursor规则、金仓、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 |
|
| 2026-03-22 14:38:11 | 🔄 卡若AI 同步 2026-03-22 14:38 | 更新:Cursor规则、金仓、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||||
| 2026-03-22 21:22:06 | 🔄 卡若AI 同步 2026-03-22 21:22 | 更新:Cursor规则、金仓、卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 |
|
| 2026-03-22 21:22:06 | 🔄 卡若AI 同步 2026-03-22 21:22 | 更新:Cursor规则、金仓、卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||||
| 2026-03-23 09:48:42 | [强制] 🔄 卡若AI 同步 2026-03-23 09:48 | 更新:Cursor规则、金仓、水桥平台对接、卡木、火炬、运营中枢、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 |
|
| 2026-03-23 09:48:42 | [强制] 🔄 卡若AI 同步 2026-03-23 09:48 | 更新:Cursor规则、金仓、水桥平台对接、卡木、火炬、运营中枢、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||||
|
| 2026-03-23 13:36:13 | [强制] 🔄 卡若AI 同步 2026-03-23 13:35 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 |
|
||||||
|
|||||||
@@ -425,3 +425,4 @@
|
|||||||
| 2026-03-22 14:38:11 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-22 14:38 | 更新:Cursor规则、金仓、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
| 2026-03-22 14:38:11 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-22 14:38 | 更新:Cursor规则、金仓、总索引与入口、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||||
| 2026-03-22 21:22:06 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-22 21:22 | 更新:Cursor规则、金仓、卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
| 2026-03-22 21:22:06 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-22 21:22 | 更新:Cursor规则、金仓、卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||||
| 2026-03-23 09:48:42 | 成功(强制) | 成功 | 🔄 卡若AI 同步 2026-03-23 09:48 | 更新:Cursor规则、金仓、水桥平台对接、卡木、火炬、运营中枢、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
| 2026-03-23 09:48:42 | 成功(强制) | 成功 | 🔄 卡若AI 同步 2026-03-23 09:48 | 更新:Cursor规则、金仓、水桥平台对接、卡木、火炬、运营中枢、运营中枢参考资料、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||||
|
| 2026-03-23 13:36:13 | 成功(强制) | 成功 | 🔄 卡若AI 同步 2026-03-23 13:35 | 更新:水桥平台对接、卡木、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
|
||||||
|
|||||||
Reference in New Issue
Block a user