
在 AI 爬虫和比价机器人横行的时代Robots.txt 已经越来越像一个“防君子不防小人”的告示牌。传统搜索引擎还会自觉遵守它但做数据采集、价格监控、AI 训练数据抓取的工具并没有统一的意愿和义务去理会这个文本文件。商业场景的数据争夺已经从“能不能抓”变成了“允不允许用”“允不允许转售”“允不允许喂给模型”。Shelf Protocol 提出的方向正是把 Robots.txt 的思路延伸到商业数据访问上让每个电商站点都能表达自己的数据使用边界。我的判断是Shelf Protocol 的真正价值不在于设计一个新的文本协议而在于它把“数据访问权”从技术声明问题变成了可验证的商业契约问题。但这恰恰也是最难的部分——没有强制力的声明本质上只是优雅的愿望清单。这篇文章会先讲清楚 Robots.txt 和 Shelf Protocol 的关系与差异再给出一个可落地的实现思路、验证方法和工程建议帮助你在自己的站点或项目里判断“要不要接、怎么接、接入后能防住什么、防不住什么”。1. 这篇文章真正要解决的问题如果你经营电商网站或者正在做电商数据服务下面这些场景你应该不陌生比价插件每隔几分钟就模拟浏览器访问商品页价格一变就推给用户服务器负载直线上涨。第三方数据公司抓取商品标题、图片、评价直接搬到自己的平台甚至打包出售。AI 公司大规模抓取商品图文内容用于训练生成式模型你的内容变成了别人模型的训练语料。竞争对手通过自动化脚本分析你的库存和促销策略你的运营数据几乎透明。传统 Robots.txt 在解决这些问题时非常吃力。它只能表达“哪些路径不要抓”无法表达“哪种商业用途不允许”更无法识别请求方是谁、有没有授权。即使你在 Robots.txt 里写了Disallow: /prices一个不守规矩的采集脚本依然会照抓不误。它没有身份概念没有用途概念没有许可概念也没有执行机制。Shelf Protocol 要做的事情就是为商业数据访问定义一套类似 Robots.txt 的“规则文件”但比 Robots.txt 更丰富它允许站点声明爬虫可以访问哪些资源、可以用于哪些商业目的、哪些行为必须得到授权以及授权的条件是什么。这篇文章适合三类读者第一类是电商平台技术和运营人员想了解如何保护商品数据第二类是爬虫和数据服务开发者需要理解这类协议对自己的业务边界意味着什么第三类是关注 AI 数据合规的技术管理者想搞清楚“网站禁止 AI 训练抓取”这类要求如何在工程上落地。我会从概念、设计、示例、验证、排错和最佳实践六个层面展开尽量不堆空话给你可以直接测试的最小实现。2. 基础概念与核心原理从 Robots.txt 到 Shelf Protocol2.1 Robots.txt 解决了什么Robots.txt 是 1994 年提出的“机器人排除协议”本质上是一份放在网站根目录的纯文本文件。网络爬虫访问站点前会先检查https://example.com/robots.txt根据文件里的规则决定哪些路径可以爬、哪些不能爬。一个最简单的例子User-agent: * Disallow: /admin/ Disallow: /cart/ Allow: /products/它的核心特点是简单、静态、纯声明。服务器不需要身份验证不需要数据库不需要动态逻辑。这也是它生命力极强的原因——任何爬虫都能低成本理解并遵守。但它的局限同样明显它是“建议标准”不是“强制标准”。不遵守的爬虫没有任何技术上的阻碍。它只描述路径级别的访问控制不能描述“某个用户代理抓了价格数据后能不能用于转售”。它没有身份机制。恶意爬虫只需要不声明 User-Agent或者伪造一个搜索引擎的 User-Agent就能绕过大部分站点基于 UA 的拦截。它不涉及商业用途、数据授权、缓存策略、归属声明这些现代数据合作需要的内容。2.2 Shelf Protocol 想做什么从项目名称看Shelf Protocol 是“商业领域的 Robots.txt”。它试图把 Robots.txt 的“简单声明”模式扩展到电商和商业数据场景。它不是简单的路径排除而是对“谁、以什么身份、为什么目的、可以访问哪些数据、在什么条件下访问”这一整组关系的描述。如果把 Robots.txt 比作店门口的告示“非请勿入”那 Shelf Protocol 更像是店门口的一份《访客守则》普通顾客可以逛同行不能进授权供应商可以进后场但要出示工牌、登记时间、且不能拍照。一个典型的 Shelf Protocol 声明可能包含这些信息策略适用的数据范围比如商品页、价格数据、库存数据、评价数据。数据使用目的比如“允许搜索索引”“允许比价”“禁止转售”“禁止 AI 训练”。访问者的身份粒度比如“所有爬虫”“指定 User-Agent”“已认证的商业伙伴”。访问条件比如速率限制、是否需要署名、数据可缓存多久、是否允许二次分发。这种设计思路的核心是把过去“爬虫能不能抓”的二选一问题升级成“不同身份、不同用途、不同授权条件下数据如何被使用”的多维问题。2.3 两者对比维度Robots.txtShelf Protocol文件位置站点根目录/robots.txt约定路径如/.well-known/shelf-protocol.json内容格式纯文本规则简单结构化数据适合程序解析身份识别仅 User-Agent 字符串支持 UA、客户端 ID、签名令牌等表达维度路径级 Allow/Disallow资源 目的 身份 条件覆盖场景搜索引擎爬虫访问控制商业数据采集、AI 训练、数据合作授权执行机制依赖爬虫自觉依赖授权校验和访问控制网关生态成熟度30 年历史全行业认可早期阶段需要生态共建注意这张表里的 Shelf Protocol 是一种通用化描述不代表某个固定现行标准。项目处于早期具体实现细节要以官方规范为准。但从工程视角看“比 Robots.txt 更细粒度、更结构化、更强调商业用途”这个方向是确定的。2.4 它真正要改变的是什么从技术形态上看Shelf Protocol 只是多了一个配置文件。但从生态角度看它在尝试做一件更难的事让数据访问权的表达标准化让“数据所有者”和“数据使用者”之间的合作可以在机器层面自动协商。这件事一旦成立会带来三个变化第一站点可以“先声明后验证”。在协议里声明“价格数据只对持牌合作方开放”然后通过技术手段识别和拦截非授权请求。第二合规责任更清晰。数据采集方如果把“按协议声明使用数据”写进合同后续出现数据滥用可以更清晰地追溯到违反的是哪一条机器可读规则。第三AI 训练数据市场会有更明确的边界。过去大家争论“公开网页能不能用来训练模型”本质上是因为数据使用意愿没有被机器表达。Shelf Protocol 如果能普及站点可以直接在协议里声明“禁止 AI 训练”让数据采集方在工程层面就有据可依。3. 协议设计思路声明、身份、授权、执行要落地一个“商业版 Robots.txt”不能只写一个 JSON 文件。完整的协议设计至少需要四个层次。3.1 声明层规则文件放哪里Robots.txt 约定放在根目录Shelf Protocol 也应遵循类似的“约定优于配置”思路降低用户的发现成本。更现代的做法是放在/.well-known/目录下例如https://example.com/.well-known/shelf-protocol.json。/.well-known/是 IETF 定义的统一约定目录很多协议都使用这个路径比如安全联系信息、加密密钥发现等。好处是标准、稳定、不容易和业务路由冲突。3.2 身份层谁在访问规则要生效首先要搞清楚“谁”在访问。目前网络爬虫的身份识别非常混乱最常见的三个层次是User-Agent 字符串最容易被伪造。IP 段和 ASN可以识别常见云厂商和数据中心但可能误伤。客户端 ID / Token / 签名需要站点主动发放识别最准确但接入成本高。Shelf Protocol 要想真正落地必须在身份层给出可扩展的方案。它不太可能只依赖 User-Agent因为商业场景下利益冲突太大恶意方没有理由老实报身份。更可能的方向是在规则文件中声明“哪些身份允许哪些操作”同时对未声明身份的请求默认执行保守策略。3.3 授权层允许做什么授权层是协议的核心。一个好的授权模型应该让站点能写出类似这样的规则所有爬虫可以访问商品元数据但每分钟不超过 30 次。所有爬虫禁止抓取价格历史接口。已认证的比价合作伙伴可以使用价格数据但必须在用户页面展示来源链接。任何方禁止将本站数据用于模型训练或二次转售。这种规则的关键是“目的”维度的定义。技术上访问请求本身很难自动判断用途是“比价”还是“AI 训练”所以协议通常用行为类型来近似表达比如price-extraction、>{ protocol: shelf-protocol, version: 0.1.0, scope: commerce, issuer: https://example.com, policies: [ { principal: { type: user-agent, value: * }, allow: [ catalog-access, search-indexing ], deny: [ price-extraction, ai-training, data-resale ], rate_limit: { requests_per_minute: 20 } }, { principal: { type: user-agent, value: ExampleBot }, allow: [ catalog-access, search-indexing, price-extraction ], conditions: { attribution_required: true, max_cache_age_seconds: 3600, requires_token: true } } ], preferences: { preferred_reference_method: shelf-protocol-json, contact_email: data-contactsexample.com } }文件结构说明protocol和version标识协议名称和版本供消费者程序判断解析方式。issuer站点身份最好使用 HTTPS 域名。policies规则数组。每条规则声明一个身份对应的允许行为和禁止行为。principal身份主体。可以是通配 UA、指定 UA、或后续扩展的客户端 ID。allow/deny允许和禁止的行为类型。rate_limit访问速率限制。conditions附加条件如是否需要签名 Token、是否需要署名、缓存时间多长。preferences站点对数据使用者的偏好设置如联系方式也可用于存放隐私政策链接。这个文件的设计核心是把“行为类型”作为第一公民。站点不是为了某个爬虫单独写规则而是为了“某种商业用途”写规则。通配符规则兜底具体身份规则覆盖。5.2 在 Nginx 中暴露规则文件使用 Nginx 时在站点配置中添加一个 location指向静态 JSON 文件。# 文件路径/etc/nginx/sites-available/example.com.conf server { listen 443 ssl; server_name example.com; # SSL 配置省略 location /.well-known/shelf-protocol.json { alias /var/www/example/shelf-protocol.json; default_type application/json; add_header Cache-Control public, max-age3600; add_header Access-Control-Allow-Origin *; } location / { # 正常站点路由 proxy_pass http://127.0.0.1:8080; } }这里的关键点是location 精确匹配路径避免影响其他请求default_type确保返回application/jsonadd_header Cache-Control控制缓存方便策略更新后爬虫能在合理时间重新拉取。5.3 用 Python 读取和判断策略作为一个数据消费者你的爬虫程序可以在发起大规模请求前先拉取对方站点的 Shelf Protocol 文件判断某个行为是否被允许。# 文件路径shelf_client.py import json from urllib.request import urlopen from urllib.error import HTTPError, URLError def load_shelf_protocol(domain: str) - dict: url fhttps://{domain}/.well-known/shelf-protocol.json try: with urlopen(url, timeout10) as resp: if resp.status ! 200: raise RuntimeError(fUnexpected status code: {resp.status}) return json.loads(resp.read().decode(utf-8)) except HTTPError as e: # 404 或 403 都表示站点未启用协议按无约束处理 if e.code in (404, 403): return {} raise except URLError as e: raise RuntimeError(fFailed to reach {url}: {e}) from e def is_allowed(policy: dict, action: str, user_agent: str) - bool: # 如果没有声明协议默认认为允许访问与 robots.txt 缺失同理 if not policy: return True rules policy.get(policies, []) matched_rule None # 找到匹配 UA 的规则通配符规则放在最后做兜底 for rule in rules: principal rule.get(principal, {}) if principal.get(type) user-agent: if principal.get(value) *: matched_rule rule elif principal.get(value) user_agent: return action not in rule.get(deny, []) if matched_rule: return action not in matched_rule.get(deny, []) return True if __name__ __main__: policy load_shelf_protocol(example.com) test_actions [search-indexing, price-extraction, ai-training] for action in test_actions: print(f{action}: {is_allowed(policy, action, ExampleBot)})这段代码展示了消费者视角的解析逻辑先拉取/.well-known/shelf-protocol.json。根据 User-Agent 匹配规则。然后检查目标行为是否在deny列表里。如果站点没有协议文件按照 Robots.txt 缺失的惯例默认允许普通访问。这里要特别说明默认允许是当前 Robots.txt 生态的实际惯例但对商业数据保护来说更稳妥的策略应该是“没有声明就跑通默认禁止”。具体采用哪一种取决于站点是偏开放还是偏保守。5.4 在 Java 中做简单的规则拦截如果你的业务后端是 Java比如 Spring Boot可以把协议规则解析做成一个过滤器在网关层前置拦截。// 文件路径src/main/java/com/example/shelf/ShelfProtocolFilter.java package com.example.shelf; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class ShelfProtocolFilter implements Filter { private final ObjectMapper mapper new ObjectMapper(); private final HttpClient client HttpClient.newBuilder().build(); Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; if (!GET.equalsIgnoreCase(req.getMethod())) { chain.doFilter(request, response); return; } String action resolveAction(req.getRequestURI()); if (action null) { chain.doFilter(request, response); return; } try { JsonNode policy loadPolicy(req.getServerName()); JsonNode rules policy.path(policies); String ua req.getHeader(User-Agent); for (JsonNode rule : rules) { JsonNode principal rule.path(principal); String type principal.path(type).asText(); String value principal.path(value).asText(); if (user-agent.equals(type) (*.equals(value) || value.equalsIgnoreCase(ua))) { for (JsonNode denied : rule.path(deny)) { if (denied.asText().equals(action)) { resp.setStatus(403); resp.getWriter().write({\error\:\blocked by shelf protocol\}); return; } } break; } } } catch (Exception e) { // 协议解析失败时不阻塞正常请求但需要记录日志 chain.doFilter(request, response); return; } chain.doFilter(request, response); } private JsonNode loadPolicy(String domain) throws Exception { HttpRequest req HttpRequest.newBuilder() .uri(URI.create(https:// domain /.well-known/shelf-protocol.json)) .GET() .build(); HttpResponseString resp client.send(req, HttpResponse.BodyHandlers.ofString()); return mapper.readTree(resp.body()); } private String resolveAction(String uri) { if (uri.startsWith(/products/)) { return catalog-access; } if (uri.startsWith(/prices/)) { return price-extraction; } return null; } }这个过滤器的逻辑比较简化但它展示了关键思想把协议规则从“被动声明”变成“主动拦截”。当请求路径对应敏感行为时后端会拉取协议文件检查当前 User-Agent 是否有权执行没有则返回 403。实际生产环境不会每次请求都拉取远程 JSON而是会把协议文件加载到内存缓存里并定时刷新。同时对于已认证客户端应优先校验签名令牌而不是只依赖 User-Agent。6. 运行结果与效果验证完成配置后我们需要验证两件事规则文件是否可用以及拦截逻辑是否生效。6.1 验证规则文件可访问在本地执行curl -i https://example.com/.well-known/shelf-protocol.json预期输出是一个 HTTP 响应头和 JSON 内容。关键观察点有三个状态码必须是 200。Content-Type必须是application/json。JSON 文本的protocol字段是shelf-protocol。如果返回 404说明 Nginx 的 location 没有匹配上需要检查alias路径和文件名。如果返回 403可能是目录权限或 WAF 拦截了/.well-known/路径需要调整安全策略。6.2 验证策略解析使用之前提供的 Python 脚本做一次策略解析验证python3 shelf_client.py如果当前策略文件是示例里那份输出结果应该是search-indexing: True price-extraction: False ai-training: False这说明“搜索索引”被允许而“价格抽取”和“AI 训练”被拒绝。对于 ExampleBot 这个 UA由于规则里允许了price-extraction结果会变成 True。这种差异正是协议的核心能力不同身份获得不同权限。6.3 验证 Java 过滤器拦截把过滤器部署到一个测试接口上用普通 UA 请求一个价格接口curl -i -H User-Agent: Unofficial-DataCollector \ https://example.com/prices/10001预期返回 403并带 JSON 错误信息。这说明在后端层规则已经从“声明”变成了“可执行策略”。6.4 判断生效程度这里要特别提醒像 Proto 这类协议验证“规则生效”和验证“规则被执行”是两件事。上面的验证只能证明规则文件和拦截逻辑在工作不能证明所有爬虫都会遵守。真正有效的风控体系还需要叠加访问监控、IP 信誉库和异常行为检测。如果某次测试没有达到预期第一步先看两个地方策略 JSON 是否合法以及请求命中的规则是否被正确匹配。错误日志里如果有denied命中说明拦截生效如果没有命中则大概率是 UA 或路径跟规则不匹配。7. 常见问题与排查思路下面汇总几个实际接入时最容易遇到的问题。问题现象可能原因排查方式解决方案/.well-known/shelf-protocol.json返回 404Web 服务器未配置对应 location或文件路径错误检查 Nginx 配置的alias路径执行nginx -t修正路径重载 Nginx返回 403WAF 或 CDN 规则拦截了.well-known路径查看 CDN 访问日志、WAF 规则在安全策略中加入该路径的放行规则爬虫不遵守协议声明协议本身没有强制力或爬虫忽略了声明通过访问日志判断是否为高频非搜索引擎 UA在 CDN/网关层按策略强制限流和拦截策略更新后没有生效JSON 文件被缓存客户端拿到的还是旧版本检查响应头的Cache-Control比对版本号缩短缓存时间或在文件名中加入版本参数合法合作伙伴请求也被拦截User-Agent 被伪造或匹配规则顺序不正确查看拦截日志确认实际 UA 和规则匹配结果为合作伙伴分配 Token用 Token 识别身份协议文件被恶意爬虫利用暴露了关键数据边界站点把过于具体的数据路由放进了公开文件检查协议内容是否透露内网路径只声明业务层面的行为类型不暴露具体资源路径标准爬虫如搜索引擎访问异常部分搜索爬虫只认 Robots.txt不解析新协议对比 Robots.txt 和 Shelf Protocol 规则是否冲突基础索引控制继续用 Robots.txt新规则只做附加约束排查时的核心思路是“分层定位”先确认文件能不能访问再确认规则有没有解析最后确认执行逻辑有没有触发。不要一上来就怀疑协议有问题。8. 最佳实践与工程建议如果决定在自己的站点尝试 Shelf Protocol 的思路下面这些实践建议值得参考。8.1 把它当作 Robots.txt 的补充而不是替代Robots.txt 在搜索引擎生态里的地位短期不会被替代因为搜索引擎已经有一套成熟的发现、抓取、索引流程。Shelf Protocol 更适合做“更细粒度的商业数据使用边界声明”。两者可以共存Robots.txt 负责基础爬虫准入Shelf Protocol 负责商业行为授权。8.2 优先使用/.well-known/标准路径虽然协议早期可能没有强制约束但路径规范越早统一生态接入成本越低。你在自己站点采用/.well-known/shelf-protocol.json将来如果协议升级迁移成本会小很多。8.3 把规则设计的重点放在“行为类型”上不要只写哪个路径禁止访问而要思考“哪些数据使用行为需要管控”。一个商品价格接口既可以被比价爬虫用也可以被 AI 训练用。使用行为类型的表述方式才能在未来灵活调整。建议维护一份行为类型清单例如search-indexing搜索索引catalog-access商品目录访问price-extraction价格抽取inventory-monitoring库存监控review-scraping评论抓取ai-trainingAI 模型训练>