返回 Skill 列表
extension
分类: 数据与分析无需 API Key

本地数据源获取引擎

本地优先的文档/数据获取引擎——统一管理 crawler_db 网页库与 skill_reference Skill 库,提供 query_local 统一路由查询+缓存命中+远程抓取 fallback;保留 BFS/批量抓取能力(借鉴Crawl4AI)

person作者: user_287b0fechubcommunity

Skill · 本地数据源获取引擎 v2.1

定位:本地优先的数据获取层——统一查询本地 SQLite 数据源(网页库 / Skill 库),命中即返回;未命中则远程抓取并入库(缓存优先,远程兜底) 触发词:「抓取」「查本地」「查数据」「获取 XX 内容」「批量抓取」 固化指令:任何「抓取/搜索/查找 XX」且需获取内容时,自动调用本 Skill——先查本地数据源,未命中再远程抓取并入库。 前置条件:httpx / parsel 已安装;LLM 提取需 embedding 引擎(可选) 职责边界:语义层(brain / memory / lcm_grep)由小夏直接调用;本引擎负责文档/数据层获取。


一、核心接口(原有)

scrape(url) → dict

单页抓取,同步接口,Windows 兼容。

from crawler_core import scrape
data = scrape('https://example.com/chapter/1.html')
# 返回: title / h1 / desc / content / images / links / url / hash / length

bfs_scrape(start_url, config=None) → dict ⭐ NEW

BFS 深度爬取:自动从目录页发现所有章节 URL,零手动配置。

from crawler_core import bfs_scrape, BFSConfig

# 方式一:默认配置(max_depth=2, max_total=1000)
result = bfs_scrape('https://example.com/book/1234/')
links = result['links']        # 去重后的章节 URL 列表
stats = result['stats']        # 统计信息
visited = result['visited_urls']  # 全部已访问 URL(调试用)

# 方式二:自定义配置
config = BFSConfig(
    max_depth=3,               # 最大爬取深度(默认2)
    max_total=500,             # 全局 URL 上限(默认1000)
    url_pattern=r'\.html$',    # 仅爬 .html 页面
    exclude_dirs=['/ads/', '/tag/'],  # 排除含这些词的 URL
)
result = bfs_scrape('https://example.com/book/1234/', config=config)
print(f"发现 {len(result['links'])} 个章节")
# links 可直接传入 batch_scrape()
batch_scrape(result['links'], 'output.txt')

返回 stats 字段说明

| 字段 | 含义 | |------|------| | total_discovered | 全部发现的 URL 数量 | | dir_pages_visited | 访问的目录页数量 | | chapter_candidates | 发现的章节候选数(去重前)| | final_links | 去重后章节数(传入 batch_scrape 的数量)| | duplicates | 重复 URL 数量 | | elapsed | 总耗时(秒)| | max_total_hit | 是否达到全局上限 |

BFSConfig 参数说明

| 参数 | 默认值 | 说明 | |------|--------|------| | max_depth | 2 | 最大爬取深度(避免太深)| | max_total | 1000 | 全局 URL 上限(防止失控)| | max_per_page | 100 | 单页最大提取链接数 | | rate_limit | True | 是否启用自适应速率限制 | | domain | 自动 | 限制爬取的域名(默认从 start_url 提取)| | url_pattern | None | URL 白名单正则(示例:r'\.html$')| | exclude_dirs | [] | 排除的目录关键字列表 |

scrape_to_db(url) → dict

抓取 + 自动去重入库(SQLite + FTS5)。

from crawler_core import scrape_to_db
data = scrape_to_db('https://example.com/page.html')
# _source: 'fresh' 新抓取 / 'cache' 命中缓存

batch_scrape(links, output_path, ...) → dict

批量抓取唯一写入口。自动处理:去重 + 正序排序 + 断点续传 + 正文清洗 + 进度报告 + 自适应速率 + 多分块策略 + LLM 驱动提取(可选)

from crawler_core import batch_scrape, sort_links

# ① 获取章节链接(方式一:BFS 自动发现)
from crawler_core import bfs_scrape
result = bfs_scrape('https://example.com/book/1234/')
links = result['links']

# 方式二:用户直接提供链接
links = [...]

# ② 正序排列(URL 数字升序)
links = sort_links(links)

# ③ 批量抓取
result = batch_scrape(
    links=links,
    output_path='books/小说名_整理版.txt',
    checkpoint_path='books/小说名.checkpoint',
    batch_report=50,
    content_min_len=200,
    header='《小说名》\n作者:XXX\n共 N 章\n================\n\n',
    rate_limit=True,
    chunk_strategy='by_size',
    chunk_size=50,
    llm_extract_types=['entities', 'keywords'],  # 可选
)

print(result)
# {'total': 100, 'success': 99, 'failed': 1,
#  'elapsed': 600.0, 'output_size': 5242880,
#  'chunks_count': 2, 'chunk_size': 50}

llm_extract(url, content, extract_types=None) → dict

LLM 驱动的结构化数据提取(v1.3)。

from crawler_core import llm_extract

result = llm_extract(
    url='http://example.com/chapter/1.html',
    content='张三先生是一位武林高手...',
    extract_types=['entities', 'keywords', 'summary']
)
# 返回: {url, entities:[{entity,type,count}], keywords:[{keyword,score}], summary}

extract_entities(text, max_entities=20) → list[dict]

独立调用:抽取人物 / 作品 / 地名实体(regex + 频次统计)。

extract_keywords(text, top_k=10, ngram_range=(2,3)) → list[dict]

独立调用:抽取关键词(依赖 embedding 引擎,未装返回空)。

scrape_many(urls, concurrency=3) → list[dict]

并发批量抓取(无文件写入)。

add_task(url) → bool

唤起迅雷下载。

from thunder_bridge import add_task
add_task('https://目标文件链接')

二、辅助函数

sort_links(links, reverse=False) → list[str]

URL 列表去重 + 正序排列(按 URL 数字 ID 升序)。

clean_chapter_content(text) -> str

标准正文清洗:去开头分隔线 + 清章末网站 UI + 去章内广告 + 合并空行。

extract_url_id(url) -> int

从 URL 提取数字 ID(用于排序)。

chunk_by_size(links, chunk_size=50) -> list[list[str]]

按 size 分块(v1.2 · 借鉴 Crawl4AI chunk_strategy)。

estimate_total_chunks(links, chunk_size=50) -> dict

预估分块统计信息。

scrape_with_retry(url, max_retry=2) -> dict | None

带自动重试的单页抓取(内容 <200 字自动重试)。


三、速率控制

RateLimiter

自适应速率限制器:连续成功逐步加速(最快 0.2s),连续失败逐步减速(最长 5s)。

ProgressReporter

每 N 章结构化进度报告:含速度 / ETA / 失败详情。


四、存储结构

data/crawler_db.sqlite3(本地文件,不上传):

| 表 | 用途 | |----|------| | crawl_history | URL / 标题 / 正文 / 图片 / 链接 | | crawl_fts | FTS5 全文检索索引 | | dl_tasks | 迅雷下载任务记录 | | crawl_checkpoints | 批量抓取断点续传记录 |

from crawler_db import CrawlerDB
db = CrawlerDB()
db.search('关键词')          # FTS5 检索
db.stats()                  # 统计
db.load_checkpoints()       # 获取已完成 URL
db.save_checkpoints_batch(['/path/1.html'])
db.clear_checkpoints()       # 清空断点(慎用)

五、配置

config.yaml

thunder:
  path: "D:\\软件安装\\Thunder\\Program\\Thunder.exe"

crawler:
  timeout: 30
  user_agent: "Mozilla/5.0 ..."

六、版本变更

v2.0 (2026-08-02) · 转型本地数据源获取引擎

| 变更 | 说明 | |------|------| | 定位转型 | 从「网页爬虫」重构为「本地优先的数据获取层」 | | 新增 local_engine.py | 统一查询接口 query_local() + 数据源路由 + 缓存优先抓取 fetch_or_cache() | | 数据源路由 | web(crawler_db) / skill(skill_reference.db),可扩展注册 | | 职责边界 | 语义层(brain/memory/lcm)由小夏直调,本引擎聚焦文档/数据层 | | 清理 | 删除 tests/ 临时文件 + crawl_shiri 项目残留脚本 |

v2.1 (2026-08-02) · 数据源扩展 + 自动兜底

| 变更 | 说明 | |------|------| | 新增数据源 | workspace(WorkspaceSource) / memory(MemorySource) / brain(BrainSource) 经 register_source() 接入 | | query_local 新增 auto_remote | 本地全空且 query 为 URL 时,自动 fetch_or_cache() 兜底 | | 职责边界调整 | memory/brain 现已可统一查询,语义层仍建议小夏直调优先 |

v3.0.1 (2026-08-05) · P0 四件套 · 反爬+决策矩阵+fit_markdown+设备模拟

| 变更 | 说明 | 来源 | |------|------|------| | 新增 anti_detection.py | 反爬 stealth 策略 + 决策矩阵 + 设备模拟(PC/iPhone/Android)| 借鉴 playwright-scraper-skill stealth JS | | 新增 fit_markdown.py | LLM 友好 Markdown 输出,trafilatura 主路 + readability 备路,省 80% token | 借鉴 crawl4ai-skill fit_markdown | | 新增 enhanced_tools.py | sitemap 发现 + DuckDuckGo 搜索 + XPath/CSS/Regex 三模提取 | 借鉴 crawl4ai-skill + smart-crawler | | 新增决策矩阵 get_crawl_method() | 普通→httpx / 动态渲染→Playwright Simple / Cloudflare→Stealth | 借鉴 playwright-scraper-skill | | 新增 generate_playwright_init_script() | Playwright 注入 JS 隐藏自动化特征(webdriver/navigator/permissions)| 借鉴 playwright-scraper-skill | | 新增 CrawlConfig 配置类 | level/device/delay/retry/timeout 统一配置,含 CrawlConfig.auto(url) 自动探测 | 内联设计 | | 修复 trafilatura v2.2 API 兼容 | reset_counter 在 v2.2 移除,改为 extract 直调 | 实测踩坑修复 | | 补装 readability-lxml | QClaw Python 统一依赖环境 | 环境规范化 |

九、本地数据源引擎(核心 v2.0)

定位落地:crawler-assistant 转型为「本地优先的数据获取层」的核心实现。统一管理本地 SQLite 数据源,提供统一查询 + 缓存优先抓取 fallback。

query_local(query, sources=None, n=10, merge=True, auto_remote=False) → dict

统一本地查询入口,自动路由到最优本地源并融合。

from local_engine import query_local, engine_stats

# 默认轻量查询(web + skill)
r = query_local('合同审查', n=5)
# {'total': 12, 'results': [{...含 _source 标记...}]}

# 扩展源查询(含 workspace/memory/brain)
r = query_local('十日终焉', sources=['web','skill','memory'], n=5)

# 空结果自动远程兜底(query 为 URL 时 fetch_or_cache)
r = query_local('https://example.com/page', auto_remote=True)
# {'total': N, 'results': [...], '_auto_remote': True}

# 引擎统计(全源)
print(engine_stats())
# {'web': {...}, 'skill': {...}, 'workspace': {...}, 'memory': {...}, 'brain': {...}}

数据源路由表(已注册):

| key | 数据源 | 后端 | 内容 | |-----|--------|------|------| | web | WebCrawlSource | crawler_db.sqlite3 | 已抓取网页/文档 | | skill | SkillRefSource | skill_reference.db | GitHub Skill 文档 | | workspace | WorkspaceSource | workspace 文件 Glob | 工作区 .md/.txt/.py | | memory | MemorySource | memory/*.md | 小夏记忆文件 | | brain | BrainSource | gbrain CLI 桥接 | 个人知识库 |

扩展点:workspace / memory / brain 已通过 register_source() 接入(v2.1),query_local 无需改动即可查询新源。

fetch_or_cache(url, db_path='data/crawler_db.sqlite3', force=False) → dict

缓存优先的远程抓取 fallback:命中 crawler_db 缓存返回 cache,未命中则 scrape_to_db 抓取入库 fresh。这是「本地优先,远程兜底」的落地函数。

engine_stats(sources=None) → dict

引擎统计:各本地数据源状态。

与语义层职责边界:brain / memory / lcm_grep 属语义记忆层。本引擎 v2.1 已支持统一查询 workspace/memory/brain 数据源,但语义层仍建议优先由小夏直接调用(brain-ops 协议);引擎层面提供统一入口,便于 Agent 一站式获取本地数据。lcm_grep 为 qclaw 内置会话检索,不在本引擎范围内。

十、Skill 参考数据库模块(新增 v1.7)

定位:从 GitHub clawhub 仓库爬取 Skill 文档与代码,构建本地参考数据库,供 Agent/Skill 升级时查阅对比。

新增模块 skill_hub.py

| 接口 | 说明 | |------|------| | build_skill_reference() | 核心入口,从 GitHub clawhub 全量抓取 Skill | | build_skill_reference_sync() | 同步包装,Windows 直接调用 | | search_skills(query) | FTS5 全文检索 Skill 参考库 | | get_skill(slug) | 获取某 Skill 的所有文件内容 | | list_all_slugs() | 列出数据库中所有 Skill slug | | db_stats() | 数据库统计(Skill 数/文件数/大小) |

数据源

  • GitHub: openclaw/clawhub 仓库 .agents/skills / .codex / .config 目录
  • 抓取方式:GitHub REST API(api.github.com),无需 Token(匿名 60 req/h)

数据库data/skill_reference.db,SQLite + FTS5 |

from crawler_assistant.scripts.skill_hub import (
    build_skill_reference_sync,
    search_skills,
    get_skill,
    db_stats,
)

# 构建参考数据库(全量首次 ~10min,增量约2min)
result = build_skill_reference_sync()
# {'new': 300, 'skipped': 0, 'error': 2, 'db': 'data/skill_reference.db'}

# FTS5 全文检索
results = search_skills('合同审查')
for r in results:
    print(f"[{r['slug']}] {r['name']}")
    print(f"  snippet: {r['snippet']}")

# 获取某 Skill 全部文件
files = get_skill('autoreview')
for f in files:
    print(f"{f['file_path']} | {len(f['content'])} chars")

# 数据库统计
print(db_stats())
# {'skills': 120, 'files': 380, 'db_size_mb': 4.2}

抓取范围

| 目录 | 说明 | |------|------| | .agents/skills | OpenClaw Skills 主目录 | | .codex | Codex Skills | | .config | 配置类 Skill |

增量策略:首次全量;后续运行时比对 SHA,只抓变更文件,不重复下载。

常见障碍

| 障碍 | 解决方案 | |------|---------| | raw.githubusercontent.com 被封锁 | 无影响,走 GitHub API 返回 base64 内容 | | 腾讯 SkillHub JS 渲染 | 暂不支持,需后续探明内部 API | | GitHub API rate limit | 自动等待 60s 后重试;匿名 60次/h |

v1.6 (2026-07-31) · BFS 根 Bug 修复 · 正式发布

| Bug | 根因 | 修复 | |-----|------|------| | Event loop is closed(BFS 中批量失败)| httpx 全局 _client 跨 loop 缓存,loop.close() 后状态丢失 | 删除全局 client,fetch() 改为 async with httpx.AsyncClient() 单次创建用完即关 | | extract_links 丢失所有相对路径链接 | href.startswith('http') 过滤掉 ../xxx.html 等相对路径 | 改为 urljoin(base_url, h) 后直接收集,不做 http 前缀过滤 | | BFS 发现 0 章节(_is_dir_page 过度保守)| 默认返回 True(其他全目录),.html 后缀无法区分 | 反转默认假设:默认章节页(False),只在明确目录特征时返回 True |

真实验收数据(Python 官方文档)

  • BFS depth=1, max_total=20:166 个章节发现9 个目录页访问19.6s
  • 内容验证(3 章节):title/content_len 全正确

v1.4 (2026-07-31) · 借鉴 Crawl4AI · P2 BFS 深度爬取

| 变更 | 说明 | 来源 | |------|------|------| | 新增 bfs_scrape() | BFS 自动发现章节 URL,无需手动配置目录 | 借鉴 Crawl4AI BFS 深度爬取 | | 新增 BFSConfig | BFS 配置类(深度/上限/域名/白名单/黑名单)| 借鉴 Crawl4AI config 理念 | | 新增 _is_dir_page() | 启发式判断 URL 是目录页还是章节页 | 内联实现,无外部依赖 | | 目录页/章节页自动分流 | BFS 队列只进目录页,章节页直接收集 | 借鉴 Crawl4AI 爬取策略 | | 零手动配置 | bfs_scrape(url) 即可自动发现全部章节 | 极简用户接口 |

P2 典型工作流

用户输入: 抓取 https://example.com/book/1234/
     ↓
工具调用: bfs_scrape('https://example.com/book/1234/')
     ↓ 发现 1000 个章节,访问 20 个目录页
     ↓
     batch_scrape(links, 'output.txt')
     ↓
     完成!

v1.3 (2026-07-31) · 借鉴 Crawl4AI · P1 LLM 驱动提取

| 变更 | 说明 | 来源 | |------|------|------| | 新增 llm_extract() | 结构化数据提取(entities/keywords/summary)| 借鉴 Crawl4AI schema extraction | | 新增 extract_entities() | 人物/作品/地名实体独立抽取 | 借鉴 entity extraction | | 新增 extract_keywords() | 关键词+权重(复用 embedding 引擎 n-gram)| 借鉴 keyword extraction | | 新增 llm_extract_types 参数 | batch_scrape 可选触发 LLM 提取 | 借鉴 extract_types | | 零新增强依赖 | embedding 未装时降级,不阻断主流程 | 轻量内联设计 |

v1.2 (2026-07-31) · 借鉴 Crawl4AI · P0 分块策略

| 变更 | 说明 | |------|------| | 新增 chunk_by_size() | 按 size 分块 | | 新增 estimate_total_chunks() | 分块预估统计 | | 升级 batch_scrape() | 新增 chunk_strategy + chunk_size 参数 | | 保持向后兼容 | 默认 chunk_strategy='by_id',与 v1.1 一致 |

v1.1 (2026-07-30)

| 变更 | 说明 | |------|------| | 新增 batch_scrape() | 批量抓取唯一写入口 | | 新增 clean_chapter_content() | 标准正文清洗 | | 新增 sort_links() | URL 正序排列 | | 新增 RateLimiter | 自适应速率控制 | | 新增 ProgressReporter | 结构化进度报告 | | 新增 crawl_checkpoints 表 | 断点记录 |


七、借鉴映射表

| Crawl4AI 能力 | 本 Skill 对应实现 | 版本 | |--------------|-----------------|------| | 多分块策略(chunk_strategy)| chunk_by_size() | v1.2 | | LLM 驱动结构化提取 | llm_extract() + extract_entities/keywords | v1.3 | | BFS 深度爬取 | bfs_scrape() + BFSConfig | v1.4 |

设计哲学:Crawl4AI(GitHub 76k stars)是 AI 网页爬虫标杆。本 Skill 借鉴其三大核心能力,保持轻量内联架构——不引入 Docker / Playwright / 外部 API 依赖,所有能力零外部依赖可独立运行。


八、文件清单

skills/crawler-assistant/
├── SKILL.md              ← 本文件(v3.0)
├── config.yaml           ← 迅雷路径配置
├── scripts/
│   ├── local_engine.py   ← 【v2.0 核心】本地数据源统一引擎
│   ├── anti_detection.py  ← 【v3.0】反爬 stealth + 决策矩阵 + 设备模拟
│   ├── fit_markdown.py     ← 【v3.0】LLM 友好 Markdown 输出
│   ├── enhanced_tools.py   ← 【v3.0】sitemap + DuckDuckGo + XPath 三模提取
│   ├── crawler_core.py   ← 抓取核心(BFS/批量/清洗)
│   ├── crawler_db.py     ← 数据持久层(crawler_db.sqlite3)
│   ├── skill_hub.py      ← Skill 参考数据库(skill_reference.db)
│   └── thunder_bridge.py ← 迅雷协议唤起
└── tests/
    ├── test_chunk_strategy.py
    ├── test_skill_hub.py
    └── test_skill_hub_write.py

十一、依赖

| 包 | 用途 | 状态 | |----|------|------| | httpx | HTTP 请求 | 必须 | | parsel | HTML 解析 | 必须 | | aiohttp | 异步并发 | 必须 | | PyYAML | 解析 SKILL.md frontmatter | 必须(已内置)| | trafilatura | LLM 友好 Markdown 正文提取 | 必须(v3.0 新增)| | readability-lxml | HTML 正文提取(备路)| 必须(v3.0 新增)| | embedding 引擎 | n-gram 关键词抽取 | 可选(未装降级)|

pip install httpx parsel aiohttp
# PyYAML 为 Python 内置,无需单独安装