k-skill 实战:naver-blog-research 技能实现 Naver 博客搜索、正文提取与图片下载(零 API Key)
【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill
naver-blog-research 是 k-skill 技能库中面向韩语内容调研的轻量级技能,它让 AI Agent 仅凭python3标准库即可完成 Naver 博客搜索、单篇正文提取与图片本地下载,全程不需要任何 API Key。本文以其instruction.md为骨架,结合仓库内 4 个脚本源码与单元测试,完整讲解三个核心命令的参数用法、JSON 输出结构、底层实现原理与合规边界,读完即可在 k-skill CLI 中直接落地韩语博客调研工作流。
一、技能定位:这个 Skill 能做什么
naver-blog-research 的核心能力可以概括为三句话(源自其 instruction.md 的 What this skill does):
- 搜索:检索 Naver 博客(블로그),输出结构化的 JSON 结果;
- 阅读:读取单篇博客的原文本内容;
- 下载:把正文中的图片下载到本地目录。
它的设计取舍非常有特点,也是它区别于一般爬虫脚本的关键:
- 零依赖零密钥:不依赖任何第三方 Python 包,全部使用
python3(3.8+)标准库完成 HTTP 请求与 HTML 解析; - 结构化输出:搜索结果、正文、图片列表都以 JSON 返回,方便 Agent 或下游程序直接消费;
- 移动端直取正文:PC 版
blog.naver.com是 iframe 嵌套结构,难以直接抓取,脚本会主动把 URL 转为移动版m.blog.naver.com,从而无 iframe 地直接提取正文; - CDN 定向下载:只允许从 Naver 博客图片 CDN 域名(
blogfiles.naver.net、postfiles.pstatic.net)下载图片。
从 skill.json 的元数据可以看到,它被归类为category: research、locale: ko-KR、phase: v1,即面向韩国本土内容的调研型技能。
二、适用与不适用场景
什么时候用(When to use)
文档给出了几类典型触发场景,均是韩语内容调研的自然语言指令:
- "네이버 블로그에서 결혼식 체크리스트 검색해줘"(帮我在 Naver 博客搜索婚礼清单)
- "네이버 블로그 리서치 해줘"(帮我做 Naver 博客调研)
- "한국 블로그에서 관련 정보 조사해줘"(帮我调查韩国博客上的相关信息)
- "네이버 블로그 글 읽어줘"(帮我读这篇 Naver 博客文章)
- "이 네이버 블로그 포스트에서 이미지 다운로드해줘"(帮我下载这篇 Naver 博客里的图片)
- 在韩语内容调研中,需要 Google 之外补充 Naver 博客这一信源时
什么时候不要用(When not to use)
文档明确划定了使用边界,Agent 触发时应主动拒绝或改道:
- 搜索 Naver 新闻、Cafe、지식iN(知识人)等其他非博客服务——本技能只处理博客域;
- 大规模爬取/抓取(单个会话内数十次以上的请求)——本技能明确不适用;
- 商业性数据采集。
三、前置条件
按文档要求,运行本技能需要:
- 可用的互联网连接;
python33.8 及以上版本(标准库即可,无第三方依赖);- 技能目录
scripts/内的 helper 脚本(即本仓库 packages/k-skill-cli/skills/naver-blog-research/scripts/ 下的 4 个文件)。
此外,实际调用依赖 k-skill CLI 执行环境。技能目录下的 SKILL.md 还提示:可以先运行npx -y @nomadamas/k-skill@0 instruct naver-blog-research获取完整指令,用npx -y @nomadamas/k-skill@0 files naver-blog-research查看随技能打包的 helper 文件清单。
四、脚本架构:4 个文件的分工
从 scripts 目录 看,技能由 3 个可执行脚本 + 1 个共享工具模块组成:
| 文件 | 职责 |
|---|---|
naver_search.py | 调用 Naver 搜索页抓取博客搜索结果,输出结构化 JSON |
naver_read.py | 读取单篇博客,提取标题、正文与图片 URL |
naver_download_images.py | 从 CDN 下载图片到本地目录 |
_naver_http.py | 共享 HTTP 工具:SSL 上下文管理、Naver 域名校验、urlopen封装 |
这种"共享工具 + 三个功能入口"的结构保证了三处对 HTTP 行为的处理(尤其是 SSL 与域名白名单)完全一致,是阅读源码时值得借鉴的分层方式。
五、工作流 1:博客搜索(naver_search.py)
命令与参数
npx -y @nomadamas/k-skill@0 exec naver-blog-research scripts/naver_search.py -- "검색어" --count 10 --sort sim参数表(继承自 instruction.md):
| 参数 | 必填 | 说明 | 默认值 |
|---|---|---|---|
| query | 是 | 搜索词 | - |
| --count | 否 | 返回结果数(最大 30) | 10 |
| --sort | 否 | sim(相关度)/ date(最新) | sim |
| --timeout | 否 | 请求超时(秒) | 15 |
输出示例
{ "query": "결혼식 체크리스트", "total_results": 7, "results": [ { "title": "결혼식 체크리스트 총정리", "url": "https://blog.naver.com/user123/224212849946", "mobile_url": "https://m.blog.naver.com/user123/224212849946", "snippet": "결혼식 1주일 전에 반드시 확인해야 할...", "author": "user123" } ] }每个结果条目同时包含 PC URL 与 mobile URL,author即博客作者 ID(从 URL 路径中解析),snippet为搜索摘要,便于 Agent 先概览再决定是否深入阅读。
源码级解析:请求参数与分页
查看 naver_search.py 可了解其底层实现:
搜索请求构造(build_search_params,约 L46-L53):请求目标为https://search.naver.com/search.naver,核心查询参数包括:
ssc=tab.blog.all:锁定"博客"标签页;sm=tab_jum(首页跳转)/tab_pge(翻页)两种模式;start:起始结果序号,每页 15 条(RESULTS_PER_PAGE = 15);nso:排序控制,sim对应so:r,p:all,a:all(按相关度),date对应so:dd,p:all,a:all(按日期倒序)。
结果解析(parse_search_results):通过正则BLOG_ANCHOR_PATTERN(L31-L34)匹配形如blog.naver.com/{author}/{postId}的链接,并利用标题/摘要的 class 特征(如headline1、body1)区分 title 与 snippet。值得注意的是,解析时会专门剔除"새 창 열림"(新窗口打开)这类可访问性隐藏标签,避免污染标题文本。
分页与去重(search函数,L109-L150):count会被钳制在 1~30 之间;每页只取前 15 条,跨页请求之间time.sleep(0.5)限速;结果按 URL 去重,不足目标数量时继续翻页,直到取够或没有新结果为止。若首页就解析失败,会向 stderr 打印警告,提示 Naver HTML 结构可能已变化。
六、工作流 2:博客正文阅读(naver_read.py)
命令与参数
npx -y @nomadamas/k-skill@0 exec naver-blog-research scripts/naver_read.py -- "https://blog.naver.com/user123/224212849946"参数表:
| 参数 | 必填 | 说明 | 默认值 |
|---|---|---|---|
| url | 是 | 博客文章 URL(PC 或移动版均可) | - |
| --no-images | 否 | 输出中排除图片 URL | false |
| --max-length | 否 | 正文最大字符数(0=不限) | 0 |
| --timeout | 否 | 请求超时(秒) | 20 |
文档特别说明:即使传入 PC 版 URL,脚本也会自动转换为移动版 URL 再请求。
源码级解析:移动版转换与正文提取
查看 naver_read.py:
URL 转换(to_mobile_url,L53-L60):把https://blog.naver.com/...前缀替换为https://m.blog.naver.com/;若 URL 本身不是该形式,则用正则从任意 URL 中提取blog.naver.com/{id}/{postId}重组移动版地址。请求时使用 iPhone 版 User-Agent(L15-L18)。
正文区域定位(extract_content_area,L115-L131):优先匹配se-main-container容器,依次回退到post_ct、postViewArea、post-view等 class,最后尝试id="viewTypeSelector"标记;找到后通过括号配平的_extract_div_block切出完整 div 块,并对 HTML 注释做了跳过处理。
文本清洗(extract_text,L134-L148):先剔除<script>、<style>、<noscript>块,再把<br>与</p>、</div>、</li>等块级结束标签替换为换行,随后剥掉所有标签并做 HTML 实体反转义,最后规整空白行。
图片提取(extract_images,L151-L182):仅接受来自三个 CDN 域(blogfiles.naver.net、postfiles.pstatic.net、mblogthumb-phinf.pstatic.net)的图片,同时匹配data-lazy-src(懒加载)与src两种属性并按基础 URL 去重;对带_blur模糊后缀的缩略图会改写为?type=w800的高清版本,并附带alt文本。
输出结构(read_blog,L185-L209):
{ "url": "https://m.blog.naver.com/user123/224212849946", "title": "결혼식 체크리스트 총정리", "content": "…正文文本…", "char_count": 1024, "images": [ { "url": "https://blogfiles.naver.net/...", "alt": "…" } ] }--max-length生效时正文会被截断并追加...;若未找到正文区域,会输出warning字段提示 HTML 结构可能已变化。
七、工作流 3:图片下载(naver_download_images.py)
命令与参数
npx -y @nomadamas/k-skill@0 exec naver-blog-research scripts/naver_download_images.py -- --urls "url1,url2,url3" --output ./images/也可以把naver_read.py的结果直接通过管道喂给它:
npx -y @nomadamas/k-skill@0 exec naver-blog-research scripts/naver_read.py -- "https://..." | npx -y @nomadamas/k-skill@0 exec naver-blog-research scripts/naver_download_images.py -- --output ./images/参数表:
| 参数 | 必填 | 说明 | 默认值 |
|---|---|---|---|
| --urls | 否 | 逗号分隔的图片 URL 列表 | - |
| --output | 否 | 保存目录 | ./naver-images/ |
| --max | 否 | 最大下载数量 | 10 |
| --timeout | 否 | 请求超时(秒) | 15 |
源码级解析:管道读取、并发与安全
查看 naver_download_images.py:
- stdin 管道(
read_urls_from_stdin,L180-L199):若未传--urls且 stdin 不是 TTY,会尝试把 stdin 作为 JSON 解析,支持三种形态——含images键的字典(即naver_read.py的输出)、URL 字符串数组、{"url": ...}对象数组。因此上一节的管道用法天然成立; - 并发下载(
download_images,L105-L150):用ThreadPoolExecutor最多 4 个 worker 并发,文件按001.jpg、002.png的序号命名(保持传入顺序),最终输出{downloaded, files[], failed[]},其中每个文件记录url、path、size_kb; - 扩展名推断(
guess_extension,L47-L67):依次依据Content-Type、URL 后缀、文件魔数(magic bytes,如 PNG/ GIF/ WebP/ BMP/ JPEG)判断; - 安全护栏:
download_image首先用is_naver_url校验 URL 必须属于.naver.com/.naver.net/.pstatic.net域(见 _naver_http.py 的 is_naver_url),并用realpath校验输出路径不能逃逸目标目录(防路径穿越),请求头还带上了Referer: https://m.blog.naver.com/。
八、推荐工作流与跨源验证
instruction.md 给出了一条完整的研究流水线:
- 用
naver_search.py搜索,先查看前 3~5 条结果概览; - 挑出相关度高的文章,用
naver_read.py读取正文; - 按需用
naver_download_images.py保存图片; - 与 WebSearch(Google)结果交叉验证,提升信息可信度。
这套流程的本质是"先摘要后精读、多信源交叉"的调研范式,Agent 按此执行即可避免盲目抓取整页结果。
九、响应策略与完成标准
Response policy(输出给用户时的约束)
- 搜索结果与正文要摘要化后传达给用户,而非原文倾倒;
- 必须附上博客出处(URL、作者);
- 单个会话内避免过量请求(数十次以上);
- 下载图片后要告知用户本地保存路径。
Done when(判定任务完成的标准)
- 搜索结果能正常输出 JSON;
- 博客正文文本成功提取;
- 所需图片成功保存到本地;
- 出处(来源)明确告知用户。
十、注意事项与限制(Notes)
文档末尾明确列出了三条运维级提醒,这是实际使用中必须接受的前提:
- IP 风控:脚本直接请求 Naver 搜索引擎,大量/自动化使用存在 IP 被封锁的可能,因此本技能被设计为小批量、非商业的轻量调研用途;
- HTML 易变:Naver 的页面结构可能随时调整,解析失败时需查看报错信息并更新脚本。这一点在源码中也有呼应——
naver_search.py首页解析失败会打警告、naver_read.py找不到正文区域会输出warning字段; - iframe 问题的技术缘由:PC 版
blog.naver.com采用 iframe 结构,正文在嵌套文档中,因此统一改用移动版m.blog.naver.com直接提取。
另外,根目录 SKILL.md 及 references/ 下的法律声明文件(含韩国大法院判例与成文法依据)要求:自动收集公开信息必须限于个人、非组织用途,不得用于系统化/批量爬取、构建数据库、绕过访问控制或妨碍第三方业务。这与文档"当不要用时"的约束完全一致。
十一、质量保障:单元测试覆盖
仓库根目录的 scripts/test_naver_blog_search.py 为本技能提供了针对性测试,可佐证其核心逻辑的稳定性:
- RequestBuilderTest:验证搜索参数构造——
ssc锁定博客标签、首页用sm=tab_jum翻页切换为sm=tab_pge、sim/date分别映射到不同的nso值; - ParseSearchResultsHiddenLabelTest:验证"새 창 열림"可访问性标签从标题/摘要中被正确剥离,且不会误伤正文中原本就含该词组的合法文本;
- SearchWorkflowTest:mock 掉网络层,验证
count=20时按 15 条一页翻页、URL 去重、跨页间隔sleep(0.5)以及date排序参数的透传。
测试直接通过importlib从 naver-blog-research/scripts/naver_search.py 加载模块进行单测,不依赖网络,证明了解析与分页逻辑可离线验证——如果你要二次开发这个技能,这套测试模式可以直接复用。
结语
naver-blog-research 是一个"小而完整"的调研技能样板:它用纯标准库解决了韩语博客搜索、正文提取、图片下载三个实际问题,并通过移动版 URL 转换、CDN 域名白名单、路径穿越防护、限速去重和明确的使用边界,把"轻量合规调研"落到了工程实处。结合本仓库中 4 个脚本源码与根目录测试用例,你可以直接掌握其请求构造、解析回退策略与并发下载的全部细节,并在此基础上按需扩展。
【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考