昨晚写了一个 Python 程序,可以自动忽略知乎上的全部邀请。欢迎大 V 们试用!
链接:https://github.com/MaigoAkisame/zhihu-ignore-invites
下面是原理介绍。
一、忽略邀请时发生了什么
在“邀请我回答的问题”页面(下文简称“邀请页面”),点击一个邀请后的“忽略”按钮,可以发现这个邀请消失了,但页面并没有刷新。由此推测,点击“忽略”按钮时页面向服务器发送了一个 AJAX 请求。
在 Chrome 中按 F12 键调出开发者工具窗口,并切换至 Network → XHR 标签页。再点击一个邀请后的“忽略”按钮,发现果然出现了一个请求。


利用 Unix 或 Cygwin 中的 curl 工具,可以在命令行发送 POST 请求,如下。当然,这里的 qid 要换成下一个邀请的编号。
结果返回一串乱码,刷新邀请页面,发现邀请并未消失。这是因为刚刚发送的 POST 请求不带 cookies,被服务器拒绝了。
在 Cookies 标签页下可以找到浏览器发送的 POST 请求所带有的 cookies,它们是各种意味不明的字符串。经试验,其中只有 _xsrf 和 z_c0 两项是必需的;_xsrf 的值与表单参数中的相同。把这两个 cookies 添加到用 curl 发送的 POST 请求中去,发现返回一个 json 对象;刷新邀请页面,第一个邀请果然就消失了。

二、批量忽略邀请
弄懂了忽略一个邀请是怎么操作的,就容易写出批量忽略邀请的脚本了。首先模拟登录,然后反复读取邀请页面(页面上会有最近的 20 个邀请),提取出页面上的问题编号,逐一发送 POST 请求忽略,直到不再有邀请为止。
利用 Python 里的 requests 库,可以发送 GET 或 POST 请求。与 curl 不同,它发送的请求必须带有 headers,不过我发现,必需的 headers 只有 User-Agent 这一项,而且值为空就行。 requests 库里有个 Session 类,其对象可以把 cookies 记忆起来,于是手动提取 _xsrf 和 z_c0 两项 cookies 的工作就可以省去了。
下面是各个步骤的做法,和它们的返回结果:
- 模拟登录:需要向 https://www.zhihu.com/login/email 页面发送一个 POST 请求,表单数据只需要 email(账号)和 password(密码),并不需要 captcha(验证码)。如果登录成功,会返回状态码 200(OK)和一个 json 对象,其中 msg(消息)项的值为字符串“登陆成功”(是的,有错别字)。
- 读取邀请页面:只需向 https://www.zhihu.com/question/invited 发送一个 GET 请求,不需要任何表单数据。如果读取成功,会返回状态码 200(OK)和 HTML 格式的页面内容。由于我在手工打开邀请页面的时候,经常遇到 500 页面(“服务器提了一个问题”),所以我的脚本会重复读取直至成功。
- 忽略邀请:需要向 https://www.zhihu.com/question/askpeople 发送一个 POST 请求,表单数据包括 op(值为 pass)、qid(问题编号)、uid(用户身份)、_xsrf。Cookies 由 Session 对象自动搞定。如果忽略成功,会返回状态码 200(OK)和一个 json 对象 {"r": 0, "msg": ""}。
忽略邀请时所需的 qid、uid、_xsrf 三项数据,都可以在邀请页面中找到。qid 就在邀请本身里面,在附近还可以找到邀请者的信息。uid 在页面中的一处脚本里,是“user_hash”后面的一串十六进制数;_xsrf 在页面底部的一个隐藏输入框里。



有了上面的准备,就可以写脚本了。忽略一个邀请大约用时 0.5 秒,效率还可以。不过,当忽略了几百个邀请后,我发现我的知乎账号因为访问太快被暂时冻结了╮( ̄▽ ̄)╭,不过好在 1 个多小时后就恢复了正常。在现在的版本中,我只能每 5 秒忽略一个邀请,并在忽略 20 个页面(400 个邀请)后休息 1 分钟。
三、隐藏的“全部忽略”功能?
我在探索的过程中,意外地发现知乎可能有未公开的“全部忽略”功能。我是这么发现的:
首先,我试图定位忽略邀请的 POST 请求是在哪里发起的。邀请页面上的“忽略”按钮(其实是个超链接),其 href 值为“javascript:;”,也就是说发起 POST 请求的代码并不在此处。我依次打开邀请页面所加载的各个 JavaScript 文件,并搜索“askpeople”、“pass”等关键字,最终发现发起 POST 请求的代码位于 https://www.zhihu.com/static/revved/-/js/closure/page-misc.13415dac.js 这个脚本中。将脚本美化后,我发现了这样几个函数:

不知道知乎可不可以把这个“忽略全部邀请”功能公开出来呢?⊂(●∧●)⊃ @知乎小管家
四、参考文献
我在写脚本的过程中参考了下面两篇文章,在此向作者致谢。