首页 / 文章 / IANA时区数据库引用的公共URL:链接失效情况统计

IANA时区数据库引用的公共URL:链接失效情况统计

对1,327个tzdata引用URL的统计:直接获取、代理解锁、Wayback恢复,以及存档失败时的剩余内容。

2135 词

IANA时区数据库记录了全球各地本地时钟的变更方式。不太为人所知的是,其注释部分还说明了这些规则的来源。该数据库的原始代码存储在https://github.com/eggert/tz上。

针对这些引用来源的统计调查提出了一个实际问题:注释中记载的公开URL中有多少至今仍能正常访问?研究人员收集了所有此类URL,进行测试,并在必要时通过能够绕过常见机器人拦截的解锁代理来访问,若目标网站已无法访问,则通过Wayback API尝试恢复链接。1,327个URL的代码、统计表格以及获取流程均发布在https://github.com/sixthextinction/tzdata-citation-census上。

这个“兔子洞”始于2008年志愿者Patrice Scattolin留下的一则笔记。他当时正在梳理摩洛哥2008年夏令时调整的准确起始时间(背景资料:https://en.wikipedia.org/wiki/Daylight_saving_time_in_Morocco),阅读了https://www.avmaroc.com/actualite/heure-dete-comment-a127896.html上的相关报道,同时遇到了法语与英语之间的表述歧义。他留下的笔记很典型:其中提到了2–08–224号法令,并承认当时无法在网络上找到该法令的正式文本。

历史数据库中充斥着这样的笔记——包括法令编号、政府公报链接、报纸网址、日期,以及解释为何某个资料比其他资料更可靠的原因。更大的问题是,经过多年变化后,这些公开网址还有多少仍然能提供有效信息。

tzdata到底是什么?

IANA时区数据库是一组由贡献者维护的文本文件。操作系统和语言运行时在需要某个时区的标准时间时会参考这些文件。最终用户很少会打开这些文件,但几乎所有的Linux发行版和编程运行时都会将其包含在内。每当某个地区调整时间时,就必须更新该数据集,否则所有依赖它的应用程序都会显示错误的本地时间。

贡献者在提出修改建议时,可以参考托管在https://data.iana.org/time-zones/tz-how-to.html上的修正指南。

相关规则本身往往十分简短。2008年摩洛哥的夏令时调整仅在africa文件中的两行纯文本中有所体现:

# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
Rule Morocco 2008 only - Jun 1 0:00 1:00 -
Rule Morocco 2008 only - Sep 1 0:00 0 -

这两行定义了全球机器必须遵守的6月1日及9月1日的时区切换时间。

周围的注释记录了该建筑的历史沿革。维护者会留存各种证据:法令编号、政府公报、部门公告、报纸文章,或是提供线索的人的信息,通常还会注明备注的添加日期。

不同来源的信息有时会存在差异。维护者偶尔会记录这些矛盾,并说明自己更信任哪一方的说法。2006年,Paul Eggert放弃了地图集中的日期信息,转而采用奥地利国家计量局的资料(https://www.bev.gv.at/):

# From Paul Eggert (2006-03-22): Shanks & Pottenger give 1918-06-16 and
# 1945-11-18, but the Austrian Federal Office of Metrology and
# Surveying (BEV) gives 1918-09-16 and for Vienna gives the "alleged"
# date of 1945-04-12 with no time. For the 1980-04-06 transition
# Shanks & Pottenger give 02:00, the BEV 00:00. Go with the BEV,
# and guess 02:00 for 1945-04-12.

这种信息来源的确定方式是最初就设计好的,还是逐渐形成的,目前尚不清楚。但无论哪种情况,它都为三十多年来共同维护过程中所做的决策留下了可用的审计轨迹,尤其是在证据不足或相互矛盾时。

那么当真正去查看这些引用来源时会发生什么?

所有URL均从九个tzdata源文件中的注释块中提取。此次扫描共发现1609个包含URL提及的注释块,总计有1352次URL出现,最终归类为623个主机上的1327个不同地址。仅提及书籍、法令或邮件而未包含URL的注释块不在统计范围内。

针对每个地址,我们使用了普通的HTTP GET请求、符合MDN User-Agent文档描述的常规浏览器身份标识头,同时还设置了严格的超时时间,以防止某些主机挂起而影响统计进程。

初次扫描后,有663个URL返回了可用的内容。其余664个URL因不同原因失败,因此我们对其进行了仔细分类:404错误与那些拒绝自动化访问的活跃页面并非同一概念。

失败案例包括:

  • 433个地址无法直接访问,需通过代理才能连接。其中178个地址拒绝了直接请求(多为HTTP 403错误,部分为429错误)。另有255个地址因家庭网络中的DNS问题、超时或TLS错误而无法访问,并非明确被屏蔽为机器人访问。这两组地址均通过Bright Data的Web Unlocker工具重新尝试后成功恢复。
  • 123个地址确实已不存在。它们返回了HTTP 404或410错误。通过Internet Archive的Wayback Machine查询后,除两个地址外其余均存在完整存档版本——共121个地址成功恢复。
  • 108个地址仍未解决(57个无存档记录,39个通过解锁工具仍无法访问,12个返回HTTP 500错误)。在未解决的地址中,有18个位于墨西哥的政府网站,出现了证书错误——很可能是主机配置问题而非页面被删除,但超出了人口普查的覆盖范围。

已消失的网站意味着保存失败;而能够响应自动GET请求但拒绝访问的网站则属于访问失败。这两种情况都会阻碍简单的爬虫访问,但它们对于相关数据是否依然存在这一问题的说明各不相同。

仅凭数字无法完整反映实际情况。663次直接访问成功包括那些至今仍可正常访问的政府门户、报纸档案以及个人主页。433次通过代理获取的成功案例则显示了“无法访问”的引用实际上往往是反自动化策略导致的。121次通过Wayback Machine获取的记录则表明互联网档案馆有多少次保存了可用的快照——不过其中有两例出现了404/410错误,甚至连档案馆本身也没有相关内容。将这些数据分类处理,才能让后续进行相同检测的人能够理解其含义。

为何引用链接会首先被屏蔽?

如今大多数网站都会将脚本客户端与普通浏览器区分对待。那些跳过JavaScript处理或未能通过浏览器指纹检测的请求可能会被限制访问频率、直接拒绝,或是遭到进一步验证。

这给大量旧引用文献的验证带来了麻烦。某个维护者曾经能成功访问的URL可能依然有效,但多年后却会拒绝简单的自动化请求。

官方公报和法律数据库在数据集中出现频率很高——比如葡萄牙的dre.pt、土耳其的resmigazete.gov.tr、以色列的nevo.co.il法律新闻网站以及类似平台。维护者们大量重复使用这些资源,但其中一些页面仍然无法直接获取。

因此,请求失败并不能证明该资源已消失。它可能意味着该资源已被删除,也可能只是因为当前的获取方式不再被允许。数据恢复流程会将这类情况视为不同的类别来处理。

这真的是tzdata的问题吗?

并非主要目的。该实验旨在衡量由长期保存的历史数据集记录的外部资源在保存过程中的完好程度。

tzdata无法保留其所引用的内容。相关规则存储在版本控制的系统中,并通过操作系统传播到全球各地,但被引用的页面仍存在于独立的网站、政府门户及报纸数据库中。

访问问题并非新现象。2014年就有关于埃及夏令时的记录指出,内阁公告页面(http://www.cabinet.gov.eg/Media/CabinetMeetingsDetails.aspx?id=347)无法从国外访问。早在本次统计之前,地理限制带来的访问问题就已属于维护方面的难题。

数据恢复流程究竟是怎样的?

数据恢复分多轮进行,以便将不同类型的故障区分开来。

对每个网址尝试所有方法——直接访问、通过代理访问、使用存档版本——虽然会提高“已恢复”的数量,但会导致分类变得模糊不清。404错误与临时屏蔽是不同的情况。存档快照也与维护人员实际看到的页面并不完全相同,它只是某个更早或更晚时刻的抓取版本。

有一组数据仅用于记录直接请求及对应的精确HTTP状态码。返回404或410状态的网址会被送到另一个经过速率限制的流程中,通过Internet Archive的可用性API进行查询。在那个阶段,超时或被屏蔽的网址不会被发送到存档中。

从概念上来说:

async function checkCitation(url) {
  const direct = await get(url); // one plain GET, no tricks
  if (isOk(direct)) return { status: "live", via: "direct" };

  if (direct.status === 404 || direct.status === 410) {
    const archived = await wayback(url); // only for confirmed-dead
    if (archived.hit) return { status: "recovered", via: "wayback" };
  }

  return { status: "unresolved" };
}

代理传递是另一个处理阶段。它针对的是因屏蔽或访问失败而无法通过直接传递获取的URL,而非那些已经返回404或410状态的URL。被屏蔽的URL会通过Bright Data的Web Unlocker作为原生HTTPS代理,以普通GET请求的方式重新尝试访问:

import { ProxyAgent, fetch as proxyFetch } from "undici";

const AUTH = process.env.BRIGHT_DATA_UNLOCKER_AUTH; // format like USER:PASS

const dispatcher = new ProxyAgent({
  uri: `@brd.superproxy.io:44445`">http://${AUTH}@brd.superproxy.io:44445`,
  requestTls: { rejectUnauthorized: false },
  proxyTls: { rejectUnauthorized: false },
});

const res = await proxyFetch(url, {
  dispatcher,
  headers: { "User-Agent": UA, Accept: "*/*" },
  redirect: "follow",
});

该路径并非浏览器渲染的结果,只是通过解锁工具路由的HTTP请求。凭证应存储在.env文件中:

BRIGHT_DATA_UNLOCKER_AUTH=brd-customer-XXXXX-zone-web_unlocker:PASSWORD
BRIGHT_DATA_UNLOCKER_PROXY_HOST=brd.superproxy.io
BRIGHT_DATA_UNLOCKER_PROXY_PORT=44445

分开的传递方式使得最终表格能够区分直接访问、代理恢复、归档恢复以及无法解析的引用。

从方法论上来看,解锁码非常重要,因为它能够区分“页面因挑战而仍然存在”与“页面已消失”这两种情况。如果没有这种区分,简单的爬虫就会过度统计链接失效的情况。同样,仅向 Wayback 发送 404/410 响应,可以避免那些只是阻止爬虫的网站充斥到归档 API 中,从而不会扰乱恢复统计结果,也不会让低价值请求耗尽速率限制。

获得这些资源后你能做些什么?

这里的关键在于可用性:所引用的 URL 是否仍能被获取?如果无法获取,是否能在其他地方找到该文档?

对于历史数据集,进一步的步骤是保留从恢复的页面中获取的内容。对于公报或法律数据库而言,这意味着需要提取法令编号、日期、标题及相关文本,并将这些字段与原始引用信息一同存储。这样一来,即便相关URL日后失效,这些证据依然存在,无需再次进行爬取来重新找到链接。

重复出现的主机特别适合自动化处理。在解除获取限制后,结构化的收集工具可以定义所需字段,并在同一基础设施上运行。普通的HTTP页面适合使用基于代码的处理器,而包含大量JavaScript的页面则需要浏览器插件来处理。

那么当档案库中没有相关内容时,还剩下什么?

仍有108个引用URL未能被解析——占1,327个唯一URL的约8%——这一比例虽小,却代表着一批无法追溯出来源的记录。虽然占比不高,但每个URL都曾对应过具体的时区规则。

这些规则仍保存在tzdata中,所缺失的只是该地址对应的部分或全部外部页面。

在108个URL中,有57个返回404或410错误,且没有Wayback的存档记录。39个URL仍无法通过代理访问(其中18个是墨西哥证书错误)。还有12个URL出现了其他HTTP错误,既没有尝试重新访问,也没有发送到Wayback进行存档。

虽然还有其他更复杂的恢复方法,但此次统计需要一个明确的终止标准:用统一的流程来评估引用情况,而非无限地追查那越来越少的剩余URL。

引用作为保存方式的局限性

历史数据集及其引用的页面具有不对称的保存特性。

时区规则被存储在版本控制系统中,并通过无数软件分发版本传播开来。一旦被纳入,这些规则可能会比最初制定它们的依据存在更久。

被引用的资料则没有这样的保障。它可能存在于某个机构的某个网址下。如果该机构迁移、删除、更改访问权限或放弃该项服务,引用内容就会变得难以获取甚至无法检索。这种故障模式通常被称为链接失效。

tzdata的维护者数十年来一直在记录相关来源,并常常注明其中的不确定性。这使得后续的调查比那些没有依据的断言要容易得多。尽管如此,仔细的引用仍无法保存被引用的内容,而且维护者也没有义务复制他们所参考的所有资料。

因此,这项统计并非是对tzdata的批评,而是展示外部URL作为历史参考的可靠性究竟如何。大多数引用都能以某种形式被找到,但有一小部分却无法检索到。该数据库仍保留着这些来源设定的规则;在108个案例中,它已无法再获取对应的URL。

若在一年后再次进行这项统计,由于网站会更改TLS设置、CDN规则或机器人协议,一些URL很可能会在不同的分类中变动。真正有意义的指标并非某个固定不变的百分比,而是引用从“可直接访问”变为“需要代理”或“仅能通过存档获取”的速度,以及有多少引用仍属于无法通过自动化方式解决的未解决类别。

对于那些维护其他长期存在的数据集的从业者——如CLDR区域设置数据、地理名称数据集、立法信息爬取结果——同样适用这一评估方法。需在注释或来源字段中列出所有公共URL,根据HTTP语义对故障类型进行分类;仅当故障表现为访问策略限制时才通过解锁工具尝试恢复,而只有当数据源声明该资源已丢失时才查阅备份档案。应将存储桶数量与原始URL列表一同公布,以便后续读者能够重复执行相同流程,而无需仅依赖某个汇总百分比。