fix: 给采集结果填 content/summary(主站资源库对空 content 拒收)
- ScrapedItem 加 content/summary 字段;to_ingest_dict 输出它们,content 为空时回退用 title - scraper 新增 _extract_description:抓 meta/og/jsonld 描述 + 详情面板文本 + 标签,拼成 content
This commit is contained in:
@@ -20,6 +20,9 @@ class ScrapedItem:
|
||||
cover_image: str | None = None
|
||||
# 视频 URL(上传 MinIO 后改为 MinIO 地址,否则是 xchina 限时签名 m3u8)
|
||||
video_url: str | None = None
|
||||
# 简介 / 正文(主站资源库要求 content 非空才入库;为空时回退用 title)
|
||||
summary: str | None = None
|
||||
content: str | None = None
|
||||
# 列表页页码(单详情页直采时为 1)
|
||||
page_no: int = 1
|
||||
# xchina 详情页里的 id 段;作 MinIO object key 前缀
|
||||
@@ -36,6 +39,8 @@ class ScrapedItem:
|
||||
if self.video_id:
|
||||
extra_data["video_id"] = self.video_id
|
||||
extra_data.update(self.extra or {})
|
||||
# 主站 ingest 对空 content 直接拒收 —— 兜底用 title,确保非空
|
||||
content = (self.content or "").strip() or (self.title or "").strip() or self.source_url
|
||||
return {
|
||||
"source_type": "video",
|
||||
"source_name": self.source_name,
|
||||
@@ -43,6 +48,8 @@ class ScrapedItem:
|
||||
"content_type": "video",
|
||||
"title": self.title,
|
||||
"cover_image": self.cover_image,
|
||||
"summary": (self.summary or None),
|
||||
"content": content,
|
||||
"video_url": self.video_url,
|
||||
"extra_data": extra_data,
|
||||
}
|
||||
|
||||
+49
-1
@@ -324,13 +324,16 @@ class XChinaScraper:
|
||||
await self._assert_not_blocked(page)
|
||||
await self._handle_interstitial_ad(page, detail_url)
|
||||
title = await self._extract_title(page)
|
||||
summary, content = await self._extract_description(page, title)
|
||||
cover_url = await self._find_cover_url(page)
|
||||
video_url = await self._find_video_url(page, media_urls)
|
||||
self.log(f"采集: {title} | cover={'有' if cover_url else '无'} | video={video_url or '无'}")
|
||||
self.log(f"采集: {title} | cover={'有' if cover_url else '无'} | video={video_url or '无'} | content={len(content or '')}字")
|
||||
from .media import extract_video_id
|
||||
return ScrapedItem(
|
||||
source_url=detail_url,
|
||||
title=title,
|
||||
summary=summary,
|
||||
content=content,
|
||||
cover_image=cover_url,
|
||||
video_url=video_url,
|
||||
page_no=page_no,
|
||||
@@ -458,6 +461,51 @@ class XChinaScraper:
|
||||
low = title.lower()
|
||||
return not any(w.lower() in low for w in bad)
|
||||
|
||||
# ---- description / content -------------------------------------------
|
||||
|
||||
async def _extract_description(self, page, title: str) -> tuple[str | None, str]:
|
||||
"""返回 (summary, content)。content 保证非空(实在没有就用 title)——
|
||||
主站资源库 ingest 对空 content 直接拒收。"""
|
||||
data = await page.evaluate(
|
||||
"""() => {
|
||||
function clean(t){ return (t || '').replace(/\\s+/g,' ').trim(); }
|
||||
const out = {};
|
||||
const m = document.querySelector('meta[name="description"], meta[property="og:description"], meta[name="twitter:description"]');
|
||||
out.meta_desc = clean(m && m.getAttribute('content'));
|
||||
for (const s of document.querySelectorAll('script[type="application/ld+json"]')) {
|
||||
try { const d = JSON.parse(s.textContent||'null'); const rows = Array.isArray(d)?d:[d];
|
||||
for (const r of rows) { if (r && r.description) { out.jsonld_desc = clean(r.description); break; } } } catch(_){}
|
||||
}
|
||||
// 影片信息 / 详情面板里的文本(键值对、简介等)
|
||||
const panel = document.querySelector('.video-detail') || document.querySelector('.tab-content.active') || document.querySelector('.tab-content');
|
||||
out.panel = panel ? clean(panel.innerText).slice(0, 4000) : '';
|
||||
// 标签
|
||||
const tags = [];
|
||||
for (const a of document.querySelectorAll('.tags a, .tag a, a[href*="/tags/"], .video-detail .item a')) {
|
||||
const t = clean(a.innerText); if (t && t.length<=20 && !tags.includes(t)) tags.push(t);
|
||||
}
|
||||
out.tags = tags.slice(0, 30);
|
||||
return out;
|
||||
}"""
|
||||
)
|
||||
meta_desc = (data.get("meta_desc") or "").strip()
|
||||
jsonld_desc = (data.get("jsonld_desc") or "").strip()
|
||||
panel = (data.get("panel") or "").strip()
|
||||
tags = data.get("tags") or []
|
||||
# content: 优先详情面板文本(信息量最大),否则 og/jsonld 描述,再否则 标签拼接,最后 title
|
||||
parts: list[str] = []
|
||||
body = panel or jsonld_desc or meta_desc
|
||||
if body:
|
||||
parts.append(body)
|
||||
if tags:
|
||||
parts.append("标签: " + " ".join(tags))
|
||||
content = "\n".join(parts).strip()
|
||||
if not content:
|
||||
content = title
|
||||
# summary: og/jsonld 描述,或 content 头一截
|
||||
summary = (meta_desc or jsonld_desc or content)[:300].strip() or None
|
||||
return summary, content
|
||||
|
||||
# ---- cover -----------------------------------------------------------
|
||||
|
||||
# 明显不是封面的图: 站点 logo / 占位图 / 图标 / 广告
|
||||
|
||||
Reference in New Issue
Block a user