
Web Content Fetcher
- 2.9k installs
- 605 repo stars
- Updated March 28, 2026
- shirenchuang/web-content-fetcher
web-content-fetcher is an agent skill that extracts main article content from URLs as clean Markdown using a Scrapling fetch.py script with domain-aware fast or stealth modes and Jina Reader fallback.
About
web-content-fetcher is a shirenchuang skill that returns the main content of any URL as clean Markdown, preserving headings, links, images, lists, and code blocks. It uses a Scrapling script as the primary extractor with automatic fast-to-stealth fallback, and Jina Reader as an alternative for simpler pages. Trigger it when you need to fetch, read, scrape, extract, or summarize content from blog posts, news articles, WeChat public articles, or documentation without hand-copying HTML. The skill is optimized for article body extraction rather than full-site crawling or structured API ingestion, making it a practical bridge between arbitrary web pages and downstream agent summarization or knowledge-base updates.
- Extracts article content from any URL as clean Markdown preserving headings, links, images, lists and code blocks
- Primary method uses Scrapling script with automatic fast-to-stealth fallback based on domain routing table
- Falls back to Jina Reader API for simple pages when Scrapling is unavailable
- Handles international content including WeChat public articles and Chinese documentation pages
- Triggered by natural language requests such as "read this page for me", "extract main content" or Chinese equivalents
Web Content Fetcher by the numbers
- 2,924 all-time installs (skills.sh)
- +41 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #269 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/shirenchuang/web-content-fetcher --skill web-content-fetcherAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.9k |
|---|---|
| repo stars | ★ 605 |
| Security audit | 2 / 3 scanners passed |
| Last updated | March 28, 2026 |
| Repository | shirenchuang/web-content-fetcher ↗ |
How do you extract readable article body content from a web URL as Markdown for agent summarization or knowledge updates?
Pull clean article content from any web URL directly into their agent workflow as Markdown.
Who is it for?
Agent workflows that need single-page article extraction from blogs, news, documentation, or WeChat articles without manual HTML copying.
Skip if: Skip for full-site crawling, structured API ingestion, or pages where one failed extraction attempt already occurred (no retries per skill rules).
When should I use this skill?
User wants to fetch, read, scrape, extract, or summarize content from a URL including phrases like read this page or extract main content.
What you get
Clean Markdown preserving headings, links, images, lists, and code blocks, with optional JSON metadata via --json output mode.
- clean Markdown article body
By the numbers
- Domain routing table covers at least nine domains including WeChat, Zhihu, and CSDN
- Default max output 30000 characters with optional limit parameter
Files
Web Content Fetcher
Given a URL, return its main content as clean Markdown — headings, links, images, lists, code blocks all preserved.
Extraction Strategy
Always try one method per URL — don't cascade blindly. Pick the right one upfront.
URL
│
├─ 1. Scrapling script (preferred)
│ Run fetch.py — check the domain routing table to decide fast vs --stealth.
│ Works for most sites. Returns clean Markdown directly.
│
└─ 2. Jina Reader (fallback — only if Scrapling fails or dependencies not installed)
web_fetch("https://r.jina.ai/<url>")
Free tier: 200 req/day. Fast (~1-2s), good Markdown output.
Does NOT work for: WeChat (403), some Chinese platforms.Scrapling script
python3 <SKILL_DIR>/scripts/fetch.py "<url>" [max_chars] [--stealth]<SKILL_DIR> is the directory where this SKILL.md lives. Resolve it before calling the script.
The script has two modes built in:
- Default (fast): HTTP fetch, ~1-3s, works for most sites
- `--stealth`: Headless browser, ~5-15s, for JS-rendered or anti-scraping sites
When run without --stealth, the script automatically falls back to stealth if the fast result has too little content. So you rarely need to specify --stealth manually — the only reason to force it is when you already know the site needs it (see routing table), which saves the initial fast attempt.
Domain Routing
Use this table to pick the right mode on the first call:
| Domain | Command | Why |
|---|---|---|
mp.weixin.qq.com | fetch.py <url> --stealth | JS-rendered content |
zhuanlan.zhihu.com | fetch.py <url> --stealth | Anti-scraping + JS |
juejin.cn | fetch.py <url> --stealth | JS-rendered SPA |
sspai.com | fetch.py <url> | Static HTML |
blog.csdn.net | fetch.py <url> | Static HTML |
ruanyifeng.com | fetch.py <url> | Static blog |
openai.com | fetch.py <url> | Static HTML |
blog.google | fetch.py <url> | Static HTML |
| Everything else | fetch.py <url> | Auto-fallback handles it |
Script Options
# Basic — auto-selects fast or stealth
python3 <SKILL_DIR>/scripts/fetch.py "https://sspai.com/post/73145"
# Force stealth for known JS-heavy sites
python3 <SKILL_DIR>/scripts/fetch.py "https://mp.weixin.qq.com/s/xxx" --stealth
# Limit output to 15000 characters (default: 30000)
python3 <SKILL_DIR>/scripts/fetch.py "https://example.com/article" 15000
# JSON output with metadata (url, mode, selector, content_length)
python3 <SKILL_DIR>/scripts/fetch.py "https://example.com" --jsonInstall Dependencies
First use only — the script checks and tells you if anything is missing:
pip install scrapling html2textIf on system-managed Python (macOS/Linux), add --break-system-packages or use a venv.
Failure Rules
- Same URL fails once → give up, tell the user "unable to extract content from this URL"
- Do not retry — each failed call wastes context tokens
test-results/
<div align="center">
Web Content Fetcher
网页正文提取 · 永久免费 · 支持微信公众号
 
</div>
---
简介
Web Content Fetcher 是一个轻量级的网页正文提取工具,能够自动将任意网页转换为干净的 Markdown 格式,保留标题、链接、图片和列表结构。
核心优势:
- Scrapling 优先提取,内置 fast / stealth 双模式,自动降级
- Jina Reader 作为二级备选
- 完美支持微信公众号、掘金、CSDN 等国内平台
- 返回标准 Markdown 格式,便于后续处理
- 零配置,开箱即用
---
安装
方式一:一键安装(推荐)
访问 skills.sh 页面,按提示一键安装。
方式二:命令行安装
npx skills add https://github.com/shirenchuang/web-content-fetcher --skill web-content-fetcher方式三:手动安装
# Clone
git clone https://github.com/shirenchuang/web-content-fetcher.git
# Copy to Claude Code skills directory
cp -r web-content-fetcher ~/.claude/skills/安装 Python 依赖
pip install scrapling html2text注意:在系统管理的 Python (macOS/Linux) 上,加 --break-system-packages 或使用 venv。---
使用方式
在 Claude Code 中使用
直接告诉 AI 你要读取的 URL,会自动选择最佳方案:
帮我读取这篇文章:https://mp.weixin.qq.com/s/EwVItQH4JUsONqv_Fmi4wQ
Extract the content from https://openai.com/blog/gpt-4o命令行单独使用
# 基础用法(自动选择 fast 或 stealth 模式)
python3 scripts/fetch.py https://sspai.com/post/73145
# 强制 stealth 模式(用于 JS 渲染页面)
python3 scripts/fetch.py https://mp.weixin.qq.com/s/xxx --stealth
# 限制输出字符数(默认 30000)
python3 scripts/fetch.py https://example.com/article 15000
# JSON 输出(含 url, mode, selector, content_length)
python3 scripts/fetch.py https://example.com --json
# 输出到文件
python3 scripts/fetch.py https://example.com/article > output.md---
提取策略
URL 输入
│
▼
┌─────────────────────────────────────┐
│ 1. Scrapling(首选) │
│ · fast 模式:~1-3s,大部分网站 │
│ · stealth 模式:~5-15s,JS 渲染 │
│ · 内容太少时自动 fast → stealth │
└─────────────────────────────────────┘
│ 失败 / 未安装依赖
▼
┌─────────────────────────────────────┐
│ 2. Jina Reader(备选) │
│ · 速度快(~1-2s),格式干净 │
│ · 免费额度:200次/天 │
│ · 不支持:微信公众号、部分国内站 │
└─────────────────────────────────────┘域名路由
| 域名 | 模式 | 说明 |
|---|---|---|
mp.weixin.qq.com | --stealth | JS 渲染内容 |
zhuanlan.zhihu.com | --stealth | 反爬 + JS |
juejin.cn | --stealth | JS 渲染 SPA |
sspai.com | fast | 静态 HTML |
blog.csdn.net | fast | 静态 HTML |
| 其他 | fast | 自动降级 |
---
支持平台
国内平台
| 平台 | 模式 | 状态 | 说明 |
|---|---|---|---|
| 微信公众号 (mp.weixin.qq.com) | fast | ✅ | 正文完整提取 |
| 掘金 (juejin.cn) | stealth (auto) | ✅ | 自动降级到 stealth |
| CSDN (blog.csdn.net) | fast | ✅ | 正文精准提取 |
| 少数派 (sspai.com) | fast | ✅ | article 选择器命中 |
| 博客园 (cnblogs.com) | fast | ✅ | 文章列表和正文 |
| 知乎 (zhihu.com) | stealth | ✅ | 需有效 URL |
| 36氪 (36kr.com) | fast | ✅ | 需有效文章 URL |
| 今日头条 (toutiao.com) | stealth | ✅ | JS 渲染,需有效文章 URL |
| InfoQ 中文 (infoq.cn) | stealth (auto) | ✅ | 需有效文章 URL |
| 网易 (163.com) | fast | ✅ | 需有效文章 URL |
| 小红书 | - | ❌ | 需登录态 |
海外平台
| 平台 | 模式 | 状态 | 说明 |
|---|---|---|---|
| OpenAI Blog | fast | ✅ | article 选择器命中 |
| Google Blog | fast | ✅ | article 选择器命中 |
| Nature | fast | ✅ | 论文摘要完整 |
| arXiv | fast | ✅ | 标题/作者/摘要 |
| GitHub | fast | ✅ | README 完整提取 |
| Next.js Blog | fast | ✅ | article 选择器命中 |
| React Docs (react.dev) | fast | ✅ | 文档正文清晰 |
| MDN Web Docs | fast | ✅ | main 选择器命中 |
| Python Docs | fast | ✅ | 目录和正文 |
| Paul Graham Essays | fast | ✅ | 经典静态页 |
| 阮一峰博客 | fast | ✅ | 周刊完整提取 |
| Claude Code Docs | fast | ✅ | 文档正文 |
| Product Hunt | stealth | ⚠️ | Cloudflare 验证拦截 |
| more... |
---
输出格式
返回标准 Markdown,自动保留:
- 标题层级:
# ## ### - 超链接:
[文字](url) - 图片:
(data-src 懒加载自动处理) - 列表、代码块、引用块
---
相关项目
Kuaifa(快发) — 公众号一键排版发布
如果你需要将 Markdown 文章发布到微信公众号,推荐使用 Kuaifa:
- 一键 Markdown 排版,支持多种主题
- 自动上传图片到 CDN
- 一键创建公众号草稿
- 支持预览和发布
pip install kuaifa
kuaifa publish your-article.md---
作者
<div align="center">
石臻说AI
AI科技博主 · 10+年大厂AI提效专家
专注于个人提效、超级个体、AI 资讯
<img src="qrcode_for_shizhen.jpg" width="200" alt="公众号二维码"/>
扫码关注公众号
</div>
---
License
MIT
scrapling
html2text
#!/usr/bin/env python3
"""
Universal web content extractor (Scrapling + html2text).
Returns clean Markdown with headings, links, images, lists, and code blocks.
Usage:
python3 fetch.py <url> [max_chars] [--stealth]
Modes:
(default) Fast HTTP fetch via Fetcher — works for most sites (~1-3s)
--stealth Headless browser via StealthyFetcher — for JS-rendered or
anti-scraping sites like WeChat, Zhihu, Juejin (~5-15s)
Examples:
python3 fetch.py https://sspai.com/post/73145
python3 fetch.py https://mp.weixin.qq.com/s/xxx 30000 --stealth
python3 fetch.py https://zhuanlan.zhihu.com/p/12345 --stealth
"""
import sys
import re
import json
import logging
def check_dependencies():
"""Check if required packages are installed and provide install instructions."""
missing = []
try:
import scrapling # noqa: F401
except ImportError:
missing.append("scrapling")
try:
import html2text # noqa: F401
except ImportError:
missing.append("html2text")
if missing:
print(
f"Error: missing dependencies: {', '.join(missing)}\n"
f"Install with:\n"
f" pip install {' '.join(missing)}",
file=sys.stderr,
)
sys.exit(1)
def fix_lazy_images(html_raw):
"""
Promote data-src to src for lazy-loaded images (WeChat, Zhihu, etc.).
Many Chinese platforms use data-src for the real image URL while src
holds a tiny placeholder. html2text only reads src, so we swap them.
"""
return re.sub(
r'<img([^>]*?)\sdata-src="([^"]+)"([^>]*?)>',
lambda m: f'<img{m.group(1)} src="{m.group(2)}"{m.group(3)}>',
html_raw,
)
# CSS selectors in priority order — the first match with enough content wins.
# Covers most blog/article platforms without needing per-site customization.
CONTENT_SELECTORS = [
"article",
"main",
".post-content",
".entry-content",
".article-content",
".article-body",
".article-detail", # 36kr
".article-holder", # InfoQ
".post_body", # 163.com (NetEase)
".markdown-body", # GitHub
".Post-RichText", # Zhihu
"#article_content", # CSDN
".article-area", # Juejin
".ssa-article", # Toutiao
'[role="article"]',
'[itemprop="articleBody"]',
]
# WeChat has a unique DOM structure — try these first for mp.weixin.qq.com
WECHAT_SELECTORS = [
"div#js_content",
"div.rich_media_content",
]
# Minimum characters for a selector match to be considered "real content"
MIN_CONTENT_LENGTH = 200
def html_to_markdown(html_raw, max_chars=30000):
"""Convert raw HTML to clean Markdown."""
import html2text
html_raw = fix_lazy_images(html_raw)
h = html2text.HTML2Text()
h.ignore_links = False
h.ignore_images = False
h.body_width = 0 # No line wrapping
h.skip_internal_links = True
h.ignore_emphasis = False
md = h.handle(html_raw)
md = re.sub(r"\n{3,}", "\n\n", md).strip()
return md[:max_chars]
def extract_content(page, url, max_chars=30000):
"""
Try content selectors to find the article body.
Returns (markdown_text, matched_selector).
"""
is_wechat = "mp.weixin.qq.com" in url
selectors = (WECHAT_SELECTORS + CONTENT_SELECTORS) if is_wechat else CONTENT_SELECTORS
for selector in selectors:
els = page.css(selector)
if els:
md = html_to_markdown(els[0].html_content, max_chars)
if len(md) >= MIN_CONTENT_LENGTH:
return md, selector
# Fallback: convert the entire page
md = html_to_markdown(page.html_content, max_chars)
return md, "body(fallback)"
def _suppress_scrapling_logs():
"""Scrapling's logger is noisy (deprecation warnings, fetch info). Silence it."""
logging.getLogger("scrapling").setLevel(logging.CRITICAL)
def fetch_fast(url, max_chars=30000, timeout=15):
"""
Fast HTTP fetch — no JavaScript execution.
Works for most blogs and static sites.
"""
from scrapling.fetchers import Fetcher
_suppress_scrapling_logs()
page = Fetcher().get(url, timeout=timeout, stealthy_headers=True)
return extract_content(page, url, max_chars)
def fetch_stealth(url, max_chars=30000, timeout=30000):
"""
Headless browser fetch — executes JavaScript, bypasses anti-scraping.
Required for: WeChat articles, Zhihu, Juejin, and other JS-rendered pages.
Slower (~5-15s) but more reliable for protected content.
"""
from scrapling.fetchers import StealthyFetcher
_suppress_scrapling_logs()
page = StealthyFetcher().fetch(
url,
headless=True,
network_idle=True,
timeout=timeout,
)
return extract_content(page, url, max_chars)
def fetch(url, max_chars=30000, stealth=False):
"""
Main entry point. Fetches URL and returns (markdown, selector, mode).
If stealth=False, tries fast mode first and falls back to stealth
when the result is too short (likely a JS-rendered page).
"""
if stealth:
md, selector = fetch_stealth(url, max_chars)
return md, selector, "stealth"
# Try fast mode first
md, selector = fetch_fast(url, max_chars)
# If fast mode got barely any content, the page likely needs JS rendering
if len(md) < MIN_CONTENT_LENGTH:
try:
md_stealth, sel_stealth = fetch_stealth(url, max_chars)
if len(md_stealth) > len(md):
return md_stealth, sel_stealth, "stealth(auto-fallback)"
except Exception:
pass # Stick with fast mode result
return md, selector, "fast"
def main():
if len(sys.argv) < 2:
print(
"Usage: python3 fetch.py <url> [max_chars] [--stealth]\n"
"\n"
"Options:\n"
" max_chars Maximum output characters (default: 30000)\n"
" --stealth Use headless browser for JS-rendered pages\n"
" --json Output as JSON with metadata\n",
file=sys.stderr,
)
sys.exit(1)
url = sys.argv[1]
args = sys.argv[2:]
stealth = "--stealth" in args
json_output = "--json" in args
args = [a for a in args if not a.startswith("--")]
max_chars = int(args[0]) if args else 30000
try:
md, selector, mode = fetch(url, max_chars, stealth=stealth)
if json_output:
result = {
"url": url,
"mode": mode,
"selector": selector,
"content_length": len(md),
"content": md,
}
print(json.dumps(result, ensure_ascii=False, indent=2))
else:
print(md)
except Exception as e:
error_msg = f"Error fetching {url}: {type(e).__name__}: {e}"
if json_output:
print(json.dumps({"url": url, "error": error_msg}, ensure_ascii=False))
else:
print(error_msg, file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
check_dependencies()
main()
Related skills
How it compares
Use web-content-fetcher for single-article Markdown extraction; use crawl-focused tools when you need multi-page site indexing.
FAQ
What extraction methods does web-content-fetcher use?
Primary Scrapling fetch.py with fast HTTP or --stealth headless browser modes per domain routing table, with Jina Reader as fallback for simple pages.
When should I force --stealth mode?
For mp.weixin.qq.com, zhuanlan.zhihu.com, and juejin.cn where JS rendering or anti-scraping requires headless browser extraction on first call.
What happens if extraction fails?
After one failed attempt for the same URL, stop and tell the user extraction was unsuccessful without retrying to avoid wasting context tokens.
Is Web Content Fetcher safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.