简单PHP实现Pocket抓取知乎专栏文章

Pocket 抓取知乎专栏的问题

Pocket 是我平时用的比较多的 稍后阅读 类网络服务,其收集抓取网上文章正文的效果比较好,去除页面广告等无关内容还算给力,支持标记和搜索,同步速度也还可以,免费会员限制也挺少,所以看到一些来不及马上阅读消化的文章我都会先加到 Pocket 队列里,有空时再去查看归档。

只是由于目前抓取网页正文原理的限制,Pocket 对现在越来越多的 AJAX 动态网页基本上都支持的不太好,比较典型的就是知乎专栏文章了。知乎专栏之前曾经是支持 Pocket 直接抓取的,改为 AJAX 加载数据之后,发送文章到 Pocket 之后就是这种效果:

Pocket 抓取知乎专栏效果

Pocket 正常抓取的文章应该能显示摘要文字或者文章中的图片,知乎专栏文章则是空白的,而且点击文章条目也是直接跳转到知乎专栏链接,并没有显示 Pocket 抓取优化的效果。

问题分析

稍微看看知乎专栏网页代码可以发现,如果在浏览器中访问类似这样的专栏文章链接:

https://zhuanlan.zhihu.com/p/21542817

实际会加载下面的文章内容数据 API 链接,知乎专栏页面加载完数据之后才会显示:

https://zhuanlan.zhihu.com/api/posts/21542817

这种动态加载方式显然 Pocket 是不支持的,不过也好办,我们自己用 PHP 或者 Node.js 等实现一个简单的程序读取专栏文章内容并输出,然后放到 VPS 或者其它虚拟主机上运行,后面访问我自己的网址并发送到 Pocket 应该就可以使 Pocket 正确抓取了。另外这种方式比较好的一面就是输出内容里没有任何其它知乎相关的网页代码,只有专栏文章内容,更易于 Pocket 抓取处理。

PHP 程序 Pocket 抓取效果

这个 PHP 程序实在没有什么技术含量,我就直接写一个简单的 PHP 文件接受传入专栏页面 ID 的 page 参数然后输出文章内容即可:

<?php
if (!isset($_GET["page"])) {
	echo "need page id.";
	exit;
}

$PAGE_ID = $_GET["page"];
$P_HEADERS = getallheaders();

if (array_key_exists("Referer", $P_HEADERS) || (isset($_GET["redirect"]) && $_GET["redirect"] == '1')) {
	header("Location: https://zhuanlan.zhihu.com/p/" . $PAGE_ID);
	exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta name="referrer" content="never"/>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<?php
$PAGE_DATA = file_get_contents("https://zhuanlan.zhihu.com/api/posts/" . $PAGE_ID);
$PAGE_OBJ = json_decode($PAGE_DATA);
echo '<title>' . $PAGE_OBJ->{"title"} . '</title>';
?>
<link rel="shortcut icon" href="https://static.zhihu.com/static/favicon.ico" type="image/x-icon">
</head>
<body>
<h1>
<?php
echo $PAGE_OBJ->{"title"};
?>
</h1>
<div>
<?php
echo $PAGE_OBJ->{"content"};
?>
<div>
</body>
</html>

上面的程序只是简单做了下判断,如果请求头中包含 Referer 信息(例如从 Pocket 网站跳转等)或者请求地址中 redirect 参数值为 1 就会直接跳转到知乎专栏页面,默认则输出专栏文章内容。另外程序中使用了 getallheaders 函数得到 HTTP 请求头信息,默认只支持 Apache,如果你要在 nginx 等服务器上使用则稍微修改下即可。

另外程序中还将 referrer 值指定为 never 防止页面引用知乎图片等资源时触发知乎的防盗链机制。

把上面的 PHP 程序放到虚拟主机上,访问类似下面的链接(单纯演示用,需要翻墙哦):

http://devio.us/~nocwat/zhihu-grub.php?page=21542817

正确显示文章内容后,将上面的链接发送到 Pocket 稍等片刻就能在 Pocket 队列里看到抓取的专栏文章了。

提示

由于知乎专栏中的图片做了防盗链策略,直接访问上面的链接可能会出现文章中的图片不能正确显示的问题,不过没关系,Pocket 会自动为我们抓取保存文章中的图片的。

最后来看看我的 Pocket 队列里的显示效果:

Pocket 通过 PHP 抓取知乎专栏

而且点击文章条目进入也能看到 Pocket 优化过的文章内容,在 Pocket 中点击 查看原始文档 也能自动跳转到知乎的专栏文章页面,这样再也不用担心专栏作者删除文章之后就没办法查看咯。





*