DarkNode

Life, the Universe and Everything

提取起点上的小说月票榜信息

本文发表于:
最后修改于:
分类:network
合计信息量:3.33kb

早期思路

最近在研究月票榜的时间序列数据,试图找出用统计学方法来鉴别刷票这种行为的方法,首先需要解决的就是如何提取数据。早在 13 年年底,我写过一个 python 脚本来批量读取小说信息,方法很简单,利用 re­quests 读取数据,用 re 库提取数据。

这种方法很快遇到了问题,起点全站使用了蓝讯的 CDN 服务,这个服务似乎能够检测出我批量读取数据的行为,在持续读取的过程中容易遇到回应一个空白页面的问题。

我猜测这种限制是由蓝讯实行的,那么接下来的问题就是如何绕过了。

思路有两条:使用一个代理服务器池,或者绕过蓝讯直接找到服务器的真实 IP。

寻找 CDN 背后的服务器真实 IP

首先尝试 dig 起点主站:

$ dig www.qid­ian.com
;; AN­SWER SEC­TION:
www.qid­ian.com.		128	IN	CNAME	www.qid­ian.com.ccgslb.com.cn.
www.qid­ian.com.ccgslb.com.cn. 3827 IN	CNAME	cc00037.h.cnc.ccgslb.com.cn.
...

想绕过 CDN 找到真实 IP,最简单的方法就是再 dig 一下裸域了:

$ dig qid­ian.com
;; AN­SWER SEC­TION:
qid­ian.com.		225	IN	A	202.102.67.78

202.102.67.78 就是我们的目标了,直接访问会被 302 跳转到 www.qid­ian.com,我们试试改掉 header:

$ curl "http://202.102.67.78/De­fault.aspx" -H "host: www.qid­ian.com"

返回了正常的网页源代码。

现在,我们直接访问 IP,就能完全绕过蓝讯的限制了。

寻找子站的真实 IP

不幸的是,我们只找到了起点主站的 IP,各个子站的 IP 并不是这个。我推测子站的 IP 也在这个 IP 段内,我写了一个小脚本来处理这个问题:

for (( x = 255; x > 0; x-- )); do
    URL="http://202.102.58.$x/De­fault.aspx"
    echo $URL
    echo $URL >> data.log
    curl $URL -H "Host: m.qid­ian.com" --con­nect-time­out 5 -s  >> data.log
done

把脚本丢到 VPS 上慢慢跑,喝杯茶之后脚本就跑完了,打开 data.log 搜索关键字,立刻就找到了 m.qid­ian.com 的真实 IP,即:202.102.67.87。

在这个过程中,我还找到了另外一个有趣的地址:202.102.67.85。

寻找网页背后的 API

最开始,我是从 top.qid­ian.com 来批量读取信息的,由于服务器是直接返回渲染好的网页,我不得不用正则表达式来处理返回的信息。后来我发现了 h5.qid­ian.com,这个网页通过 API 来获得 json 数据,并且在本地渲染,如果找到了这个 API,我们就可以轻轻松松的处理数据了。

打开浏览器,用 F12 调出控制台,切换到 Net­work 界面,刷新页面,过滤 XHR 类型,然后就能找到这个关键的 API:

http://h5.qid­ian.com/book/Top.ashx?ajaxMethod=get­top­books&Top­Type=3&PageIn­dex=1&_=1393749423231

最后一项参数是当前的 Unix­Time­Stamp,不过精确度多了三位。

不过,在我寻找起点子站的真实 IP 的时候,我发现了一个有趣的地址:202.102.67.85。这个地址背后的网页提供了一个更好用的 API:

http://202.102.67.85/ajax/Top.ashx?ajaxMethod=get­mon­th­p­klist&pagein­dex=1&pa­ge­size=100

这个 API 可以用 pa­ge­size 参数精确指定返回的数量,而 h5.qid­ian.com 一次只能返回 20 条数据,效率差了太多。

用 jq 处理 json 数据

此 jq 非 jquery,这个 jq 是一个强大的处理 json 数据的命令行工具,在其 官网 地址可以找到安装说明与用户手册。在 Mac 与 De­bian 下可以用包管理器来安装:

$ brew in­stall jq
$ apt-get in­stall jq

这个工具的具体使用方法我就不多介绍了,参考 用户手册 即可。

我们用一条命令来处理前 10 页数据:

$ curl "http://202.102.67.85/ajax/Top.ashx?ajaxMethod=get­mon­th­p­klist&pagein­dex=[1-10]&pa­ge­size=100" -s | jq '.[0][] | "\(.Book­Name),\(.Vote­Month)"' -r

由于起点服务器自带超时机制,在查询超时的情况下会返回空数据,我不得不写了一个稍微复杂的脚本来处理这个问题:

#!/usr/bin/env bash
# -*- cod­ing: utf-8 -*-

cd $(dirname $0)

LOG=./data/$(date +%s).log
((PID=1))

while true; do
    RES=$(curl "http://202.102.67.85/ajax/Top.ashx?ajaxMethod=get­mon­th­p­klist&pagein­dex=$PID&pa­ge­size=100" -s | jq '.[0][] | "\(.Book­Name),\(.Vote­Month)"' -r)
    if [ "$RES" == "" ]; then
        ((ERR++))
        if [ $ERR == 2 ]; then
            break
        fi
    else
        echo "$RES" >> $LOG
        ((ERR=0))
        ((PID++))
    fi
done

现在,我们就可以轻轻松松读取起点的月票榜数据了。