- 新增韩国(KR)适配:countries/pinterest 种子词、K-pop 提示词、UI 国家列表 - 爬虫跨运行持久化已采集 URL(.collected_urls.json),同关键词重复搜索采新图 - 模板导出增强:SPU 商品属性列名前缀剥离匹配、尺码下拉框 INDIRECT 动态引用、 SPU 字段映射(袖长/门襟/胸垫等)、季节/印花图案女装映射、建议售价统一必填、 SKU 分类/数量/单位直接填默认值 - 自定义模式:多模态提示词独立(custom_analyze_*)、生图提示词模板可配置 - Pinterest:空选品守卫、连续空分析保护(max_empty_analyze)、flat_prompt 配置覆盖 - 生图可靠性:开始/完成进度日志、异步任务轮询超时 60s→300s
90 lines
4.1 KiB
Python
90 lines
4.1 KiB
Python
"""Pinterest 爬取封装:把 pinterest_image_capture 的 CLI 逻辑封装成可调用函数,供 UI/节点后台线程调用。
|
||
|
||
用法:
|
||
from pinterest_scraper.scraper import scrape_pinterest
|
||
files = scrape_pinterest("vintage 70s", count=40, save_dir="output/pinterest_ref/US/vintage_70s")
|
||
|
||
增量续采:每个 save_dir 下维护 .collected_urls.json(该关键词历史已采集 URL 集合)。
|
||
重复搜索同一关键词时自动跳过旧图、往下拉采集新图,避免反复下载顶部重复图片。
|
||
"""
|
||
import asyncio
|
||
import json
|
||
import os
|
||
from pathlib import Path
|
||
from typing import List, Optional, Set
|
||
|
||
from pinterest_scraper.pinterest_image_capture import (
|
||
detect_proxy,
|
||
download_all,
|
||
get_system_proxy,
|
||
scrape,
|
||
)
|
||
|
||
|
||
def _load_collected_urls(save_dir: str) -> Set[str]:
|
||
"""读该关键词历史已采集 URL(.collected_urls.json),不存在/损坏返回空集。"""
|
||
p = Path(save_dir) / ".collected_urls.json"
|
||
if not p.exists():
|
||
return set()
|
||
try:
|
||
data = json.loads(p.read_text(encoding="utf-8"))
|
||
return {str(u) for u in data if str(u).strip()}
|
||
except Exception: # noqa: BLE001
|
||
return set()
|
||
|
||
|
||
def _save_collected_urls(save_dir: str, urls: Set[str]) -> None:
|
||
"""把已采集 URL 集合持久化到 .collected_urls.json(供下次增量续采)。"""
|
||
try:
|
||
p = Path(save_dir) / ".collected_urls.json"
|
||
p.write_text(json.dumps(sorted(urls), ensure_ascii=False), encoding="utf-8")
|
||
except Exception as e: # noqa: BLE001
|
||
print(f"[pinterest] 已采集 URL 持久化失败: {e}")
|
||
|
||
|
||
def scrape_pinterest(keyword: str, count: int = 40, save_dir: Optional[str] = None,
|
||
proxy: Optional[str] = None, headless: bool = False,
|
||
cdp_url: Optional[str] = None,
|
||
login_wait: bool = False) -> List[str]:
|
||
"""按关键词爬取 Pinterest 图片并下载到 save_dir,返回下载成功的文件路径列表。
|
||
|
||
- proxy 为 None 时自动探测(环境变量/系统代理/本地常见端口);空字符串显式禁用。
|
||
- login_wait=False(默认):运行时检测到未登录时不阻塞,直接返回空列表(由调用方跳过并告警);
|
||
login_wait=True:弹出 Chrome 窗口等待手动登录一次,登录态缓存在
|
||
pinterest_scraper/.chrome_session,之后自动复用。
|
||
- 增量续采:读取 save_dir/.collected_urls.json 历史已采集 URL,滚动时跳过旧图往下拉,
|
||
只下载新图,并把新 URL 合并写回(种子词用尽复用同一关键词时自动采集更靠后的新图)。
|
||
"""
|
||
# 代理解析:显式传入 > 自动探测 > 直连
|
||
if proxy is None:
|
||
proxy = detect_proxy() or get_system_proxy()
|
||
if proxy:
|
||
print(f"[pinterest] 使用代理: {proxy}")
|
||
else:
|
||
print("[pinterest] 未检测到代理,将直连(如无法访问请手动指定代理)")
|
||
proxy = proxy or None
|
||
|
||
out = save_dir or os.path.join(os.getcwd(), "output", "img", keyword)
|
||
os.makedirs(out, exist_ok=True)
|
||
print(f"[pinterest] 关键词: {keyword} | 数量: {count} | 保存目录: {out}")
|
||
|
||
# 跨运行已采集 URL:重复搜索同一关键词时跳过旧图、往下拉续采
|
||
known = _load_collected_urls(out)
|
||
if known:
|
||
print(f"[pinterest] 该关键词已采集过 {len(known)} 个 URL,将跳过旧图往下拉续采新图")
|
||
|
||
imgs_url = asyncio.run(scrape(keyword, count, headless, proxy, cdp_url, login_wait,
|
||
known_urls=known))
|
||
if not imgs_url:
|
||
print(f"[pinterest] 未收集到新图片(可能未登录、搜索无结果或该关键词已无新图): {keyword}")
|
||
return []
|
||
asyncio.run(download_all(imgs_url, out, proxy))
|
||
|
||
# 合并本次新采集 URL 到持久化集合,供下次增量续采
|
||
known |= imgs_url
|
||
_save_collected_urls(out, known)
|
||
|
||
files = [str(p) for p in sorted(Path(out).iterdir()) if p.is_file()]
|
||
print(f"[pinterest] 完成,本次新增 {len(imgs_url)} 张图片(累计已采集 {len(known)} 个 URL): {keyword}")
|
||
return files
|