Auto backup \2026-\04-\20

This commit is contained in:
Ubuntu
2026-08-06 16:00:01 +08:00
parent bcc8866ad8
commit a04277e6eb
4 changed files with 555 additions and 55 deletions
@@ -23,6 +23,14 @@ from bs4 import BeautifulSoup
# Scrapling 引擎
from scrapling import Fetcher, StealthyFetcher
# 策略化重构(v2):站点提取策略注册表 + 双轨调度
from .crawl_strategies import (
get_extractor_for_url,
is_strategy_first,
run_extractor,
is_strategy_success,
)
# 复用 crawl.py 的通用工具函数
from .crawl import (
fix_encoding,
@@ -375,6 +383,70 @@ def _filter_51cto_images(images: list) -> list:
return filtered
def _legacy_extract(url: str, html: str, images: Optional[list] = None):
"""旧逻辑(轨A):现有站点特判提取,逐行保留原实现,不删除。
返回 (title, markdown_content, images),与策略链 ExtractorResult 同构。
images 为 None 时内部自行调用 extract_images;否则复用调用方已提取的结果。
原第 6 步的 is_wechat 变量从未被使用,搬迁时省略。
"""
# 5. 提取标题(InfoQ / 掘金 / CSDN / 博客园 / 51CTO 使用专用提取)
is_infoq = 'infoq.cn' in url or 'infoq.com' in url
is_juejin = 'juejin.cn' in url
is_csdn = 'csdn.net' in url or 'csdn.com' in url
is_cnblogs = 'cnblogs.com' in url
is_51cto = '51cto.com' in url
if is_infoq:
title = _extract_infoq_title(html)
elif is_juejin:
title = _extract_juejin_title(html)
elif is_csdn:
title = _extract_csdn_title(html)
elif is_cnblogs:
title = _extract_cnblogs_title(html)
elif is_51cto:
title = _extract_51cto_title(html)
else:
title = None
if not title:
title = extract_title_from_html(html)
if not title:
title = "未获取到标题"
# 6. 提取正文和图片
if images is None:
images = extract_images(html, url)
if is_csdn:
images = _filter_csdn_images(images)
elif is_cnblogs:
images = _filter_cnblogs_images(images)
elif is_51cto:
images = _filter_51cto_images(images)
# 7. 转换为 Markdown(InfoQ / 掘金 / CSDN / 博客园 / 51CTO 使用专用提取)
if is_infoq:
infoq_html = _extract_infoq_content(html)
markdown_content = html_to_markdown(infoq_html, url)
elif is_juejin:
juejin_html = _extract_juejin_content(html)
markdown_content = html_to_markdown(juejin_html, url)
elif is_csdn:
csdn_html = _extract_csdn_content(html)
markdown_content = html_to_markdown(csdn_html, url)
elif is_cnblogs:
cnblogs_html = _extract_cnblogs_content(html)
markdown_content = html_to_markdown(cnblogs_html, url)
elif is_51cto:
cto_html = _extract_51cto_content(html)
markdown_content = html_to_markdown(cto_html, url)
elif is_spa_site(html):
markdown_content = convert_spa_html_to_markdown(html, images, url)
else:
markdown_content = html_to_markdown(html, url)
return title, markdown_content, images
@router.post("/fetch", response_model=CrawlResponse)
async def universal_fetch(request: UniversalCrawlRequest):
"""通用采集:使用 Scrapling 引擎获取文章"""
@@ -402,64 +474,24 @@ async def universal_fetch(request: UniversalCrawlRequest):
# 4. 微信图片防盗链处理
html = _bypass_wechat_images(html, url)
# 5. 提取标题(InfoQ / 掘金 / CSDN / 博客园 / 51CTO 使用专用提取)
is_infoq = 'infoq.cn' in url or 'infoq.com' in url
is_juejin = 'juejin.cn' in url
is_csdn = 'csdn.net' in url or 'csdn.com' in url
is_cnblogs = 'cnblogs.com' in url
is_51cto = '51cto.com' in url
if is_infoq:
title = _extract_infoq_title(html)
elif is_juejin:
title = _extract_juejin_title(html)
elif is_csdn:
title = _extract_csdn_title(html)
elif is_cnblogs:
title = _extract_cnblogs_title(html)
elif is_51cto:
title = _extract_51cto_title(html)
# 5. 提取标题和正文(双轨调度 v2:默认旧逻辑优先;白名单站点新策略优先,质量不达标回退旧逻辑)
extractor = get_extractor_for_url(url)
if extractor and is_strategy_first(url):
images = extract_images(html, url)
result = run_extractor(extractor, url, html, images)
if is_strategy_success(result):
title, markdown_content, images = result.title, result.markdown, result.images
print(f"[Universal Crawl] 策略链成功: {extractor.name}")
else:
print(f"[Universal Crawl] 策略链质量不达标({extractor.name}),回退旧逻辑")
title, markdown_content, images = _legacy_extract(url, html, images)
else:
title = None
if not title:
title = extract_title_from_html(html)
if not title:
title = "未获取到标题"
title, markdown_content, images = _legacy_extract(url, html)
# 6. 提取正文和图片
is_wechat = 'mp.weixin.qq.com' in url
images = extract_images(html, url)
if is_csdn:
images = _filter_csdn_images(images)
elif is_cnblogs:
images = _filter_cnblogs_images(images)
elif is_51cto:
images = _filter_51cto_images(images)
# 7. 转换为 Markdown(InfoQ / 掘金 / CSDN / 博客园 / 51CTO 使用专用提取)
if is_infoq:
infoq_html = _extract_infoq_content(html)
markdown_content = html_to_markdown(infoq_html, url)
elif is_juejin:
juejin_html = _extract_juejin_content(html)
markdown_content = html_to_markdown(juejin_html, url)
elif is_csdn:
csdn_html = _extract_csdn_content(html)
markdown_content = html_to_markdown(csdn_html, url)
elif is_cnblogs:
cnblogs_html = _extract_cnblogs_content(html)
markdown_content = html_to_markdown(cnblogs_html, url)
elif is_51cto:
cto_html = _extract_51cto_content(html)
markdown_content = html_to_markdown(cto_html, url)
elif is_spa_site(html):
markdown_content = convert_spa_html_to_markdown(html, images, url)
else:
markdown_content = html_to_markdown(html, url)
# 8. 数学公式修复
# 6. 数学公式修复
markdown_content = fix_math_formulas(markdown_content)
# 9. 清理 Markdown 中的 HTML 标签
# 7. 清理 Markdown 中的 HTML 标签
markdown_content = re.sub(r'<[^>]+>', '', markdown_content)
markdown_content = re.sub(r'\n{3,}', '\n\n', markdown_content)
markdown_content = markdown_content.strip()