网站反爬越狠,它越兴奋!这个自愈式爬虫专治各种不服
📅 2026年05月19日 · 技术
网站反爬越狠,它越兴奋!这个自愈式爬虫专治各种不服
每个网络爬虫刚开始都能正常工作。问题是——它能撑多久不坏?
网站改版了,选择器失效了;加了 Cloudflare,请求被拦截了;反爬升级了,IP 被封了。大部分爬虫团队靠的是"出了事再修"的运维模式,但 Anansi 提供了一条完全不同的路。
"The spider that learns." —— 这是一只会学习的蜘蛛。
一句话概括 Anansi 的能力
当网站更改布局时,Anansi 自动找到数据并记住修复方案;当页面需要浏览器渲染时,它静默切换到浏览器模式;当反爬检测找上门时,它在网络层模仿 Chrome 的 TLS 指纹——这是大多数爬虫从未考虑过的层面;当重新抓取时,未更改的页面在发出请求前就被跳过;当提取出错时,Pydantic 验证立即捕获,而不是让垃圾数据污染你的数据库。
结果:一个能对付恶意站点、扛得住网站改版、越跑越聪明的爬虫。它还自带 MCP 服务器,任何 LLM 都可以通过对话驱动完整的抓取流程。
核心能力详解
1. 自愈式解析器
CSS 选择器带有置信度分数存储。当某个选择器失效时,四种修复策略会依次尝试——模糊类名匹配、文本模式正则、结构上下文、XPath 回退——胜出者会被持久化供下次使用。
# 提取失败后的修复流程
1. Text-pattern match — 对元素文本做正则匹配
2. Attribute fuzzy match — Levenshtein 相似 CSS 类名
3. Structural context — 父/兄弟节点导航
4. XPath fallback — CSS 转 XPath
2. 结构化数据自动提取
JSON-LD、Open Graph 和 Microdata 会从每个页面自动提取。匹配到 schema.org 标记的字段直接跳过 CSS 评估——它们更稳定,无需选择器维护。
3. TLS/HTTP-2 指纹模仿
企业级反爬系统(Cloudflare、Akamai、DataDome)在检查任何请求头之前,会先对你的 TLS ClientHello 和 HTTP/2 SETTINGS/帧顺序进行指纹识别。使用 impersonate="chrome124",Anansi 通过 curl-cffi 精确重现这两个指纹,再加上按主机预热会话和 Akamai 拦截升级阶梯。
tls 扩展包,由操作员把关,仅限授权用途使用。请遵守目标网站的 robots.txt 和服务条款。
4. 自动浏览器升级
每个 HTTP 响应都会检查 SPA 标记、noscript 重定向和异常低的文本密度。JS 壳子会触发静默重试,使用隐身 Playwright 浏览器。该决策会在抓取会话期间按域名缓存。
5. 反爬与 Cloudflare 绕过
浏览器提取器会移除 webdriver 指纹、伪造插件、硬件并发数、音频上下文、字体测量、电池 API 和触摸点,添加 Canvas/WebGL 噪声,自动关闭 GDPR/Cookie 同意横幅,并自动等待 Cloudflare Turnstile 挑战完成。
安装
# 核心安装
pip install "git+https://github.com/mdowis/anansi"
# 浏览器提取(Cloudflare 绕过、JS 渲染)
playwright install chromium
# TLS 指纹模仿扩展
pip install "anansi-scraper[tls] @ git+https://github.com/mdowis/anansi"
# OpenAI/ChatGPT Agents SDK 扩展
pip install "anansi-scraper[openai] @ git+https://github.com/mdowis/anansi"
快速上手
从产品页面提取结构化数据
import asyncio
from anansi import AdaptiveParser
from anansi.parser.adaptive import SelectorConfig
async def main():
html = ... # 获取的 HTML
parser = AdaptiveParser()
data = await parser.extract(html, {
"name": SelectorConfig("h1.product-title", expected_pattern=r"\w+"),
"price": SelectorConfig(".price-tag", expected_pattern=r"\$[\d,.]+"),
"sku": ".product-sku",
}, url="https://shop.example.com/product/42")
print(data)
# {"name": "Widget Pro", "price": "$49.99", "sku": "WGT-001"}
# 原始结构化数据也可直接获取
structured = await parser.extract_structured(html)
print(structured["json_ld"])
print(structured["open_graph"])
asyncio.run(main())
运行弹性并发爬取
from pydantic import BaseModel
from anansi import Crawler, ProxyManager
from anansi.core import Item, Request, Response
from anansi.spider.spider import Spider
class ProductItem(BaseModel):
title: str
price: float
sku: str | None = None
class ShopSpider(Spider):
name = "shop"
start_urls = ["https://shop.example.com/products"]
item_schema = ProductItem
async def parse(self, response: Response):
for link in response.css("a.product-link"):
yield Request(response.urljoin(link["href"]), callback="parse_product")
async def parse_product(self, response: Response):
yield Item({"title": response.css("h1")[0].get_text(),
"url": response.url})
pm = ProxyManager(["http://proxy1:8080", "socks5://proxy2:1080"])
crawler = Crawler(
ShopSpider,
concurrency=10,
delay=0.5,
max_pages=1000,
proxy_manager=pm,
)
crawler.run()
自适应限速
每次抓取后,Anansi 会调整请求频率:
- 遇到 429 状态码 → 间隙翻倍(上限 60 秒)+ 30 秒熔断
- 滑动窗口内错误率 > 30% → 间隙 × 1.5
- 错误率 < 5% → 间隙 × 0.95(不低于基础延迟)
递增式爬取
ETag、Last-Modified 和内容 MD5 会按 URL 存储。重新爬取时发送条件 GET 头——304 响应直接跳过解析,哈希比较能在没有服务端 ETag 支持的情况下检测变更。Sitemap 的 <lastmod> 日期用于预过滤,在发起网络请求前就跳过未变更的页面。
其他值得关注的功能
- URL 规范化:自动剥离跟踪参数(utm_*、fbclid、gclid 等 25 种)
- 数据验证:设置
item_schema = MyPydanticModel,每个产出项在持久化前都会被验证 - 并发爬取:纯 asyncio,信号量控制工作线程,SQLite 支持的 URL 队列,爬取可跨进程重启
- 代理轮换:HTTP/HTTPS/SOCKS5 支持,轮询/随机/最少使用策略,失败代理自动隔离
- MCP 服务器:FastMCP 暴露 17 个抓取工具,任何 LLM 都能通过对话驱动完整爬取
- JS 交互:点击、填写、滚动、无限滚动循环、等待
- 网络请求拦截:从 SPA 中捕获 JSON API 响应
适用场景
- 需要长期稳定抓取电商、新闻等频繁改版的网站
- 目标网站有 Cloudflare、Akamai 等企业级反爬防护
- 需要低运维成本的数据采集管道
- 希望通过自然语言与 AI 对话驱动爬虫的非技术人员