我一直在使用在 shell 中运行的 PHP 程序来读取华盛顿邮报 RSS 提要。 它已经工作正常一年多了,但在 2024 年 8 月 2 日停止工作。这是一个非常简单的示例程序:
<?php
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://www.washingtonpost.com/arcio/rss/');
$result = curl_exec($curl);
if ($result === false) {
print "Error: " . curl_error($curl) . "\n";
} else {
print "$result\n";
}
?>
它曾经返回这样的 XML 文本:
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" version="2.0">
<channel>
<title>Washington Post</title>
<description>Washington Post News Feed</description>
etc etc etc
但现在它返回此错误:
HTTP/2 流 1 未完全关闭:INTERNAL_ERROR(错误 2)
我尝试了几种方法,例如将
CURLOPT_REFERER
和 CURLOPT_USERAGENT
设置为浏览器的值,但这没有帮助。 我还尝试将 CURLOPT_HTTP_VERSION
设置为 CURL_HTTP_VERSION_1_1
,虽然这使得错误消息消失,但尝试的 curl_get_contents()
调用会超时,即使超时设置为 60 秒也是如此。
然后,我稍微修改了程序,将其加载到本地开发网站上,从浏览器窗口运行它,并再次收到
HTTP/2 stream 1...
消息,因此它不是从浏览器外部运行,这是问题所在。
我尝试访问的 XML 文件仍然存在。 我知道这一点是因为在浏览器的地址框中输入其 URL 会导致 XML 文本页面显示在浏览器的窗口中。
file_get_contents()
也没有用。
有什么建议吗?
我最近找到了自己问题的答案。 《华盛顿邮报》以及许多其他网站无疑都使用可以检测请求是来自浏览器还是其他设备的软件。 ScrapFly 的此网页介绍了《华盛顿邮报》使用的 Akami 软件包用于检测非浏览器访问尝试的技术:Akamai 检测技术
虽然《华盛顿邮报》确实阻止抓取其网页(例如,在响应请求之前引入 10 秒的延迟),但他们确实允许这样做。 他们于 2024 年 8 月 2 日开始被非浏览器阻止的是他们自己的 RSS 源(例如,https://www.washingtonpost.com/arcio/rss/)。浏览器仍然可以访问这些源,但它们采用 XML 格式,链接显示为纯文本,在浏览器页面上显示时不是很有用,并且需要额外的步骤才能处理成有用的形式。
ScrapFly 网站提供的信息足以构建您自己的解决方案,但在 https://github.com/lwthiker/curl-impersonate 上有一个可使用curl_impersonate 的现成替代方案。 它可以模仿四种主要浏览器的行为:Chrome、Firefox、Safari 和 Microsoft Edge。
我需要一个 PHP 解决方案,因此另外使用了 kelvinzer0/curl-impersonate-php,它执行必要的设置并调用 curl_impersonate 可执行文件。