看到首页上一种绕过限制下载论文的思路的文章,刚好笔者前几天给小学妹做了一个下载器,也凑热闹来讨论一下。

“一种绕过限制下载论文的思路”一文中,作者采用的是使用脚本操作浏览器,然后获取图片的链接的方式,可以说是简单粗暴有效。但是问题也很明显,就是效率低,在作者基础上进行提高的一个思路就是直接获取到图片的链接,可以从网站本身的显示逻辑来下手。

先放代码吧,页面有一个百度云的下载链接,下载后可以直接使用,需要先按安装JRE

https://github.com/wxynihao/book118-downloader

以下面的链接为例:

https://max.book118.com/html/2017/0504/104201745.shtm

一、分析页面的js

1.1 预览框的显示逻辑

预览的时候会弹一个框出来,然后显示前几页,可以顺着弹出的代码找到获取链接的代码。

查看页面源代码可以找到show.js,其中包含一个openfull函数,这个函数中间又包含一段ajax请求的代码,如下:

$.ajax({ url : '/index.php?g=Home&m=View&a=viewUrl', type : 'GET', data : { cid:tmp_doc_aid, flag:1     }, async : false, success : function(data){ openUrl = data;
    }
});

构造一个请求测试一下 

https://max.book118.com/index.php?g=Home&m=View&a=viewUrl&cid=104201745&flag=1

可以看到返回:

//view46.book118.com/?readpage=63pU7jqloamXmUqHxeARYw==&furl=YOQStEpojXDVWEMEMy2zbvH4iMigQCjbdHMZ8zyLAF6JTE93kuMR3Q26RVkJZ6jdR5Oiuypy9hB0x@nksHt6wRqyluwxwSyCHFm5r3rbGmboJpu3Y7iugg==&n=1

打开这个链接可以看到正是纯粹的预览页面。

1.2 加载的逻辑

查看获取到的预览页面的源代码,可以看到一个内嵌的js函数getNextPage,这个函数也包含一个ajax请求。

$.ajax({ type: "get", url: "GetNextPage/", data: { f: $("#Url").val(), img: $("#Img").val(), isMobile: $("#IsMobi").val(), isNet: $("#IsNet").val(), readLimit: $("#ReadLimit").val(), furl: $("#Furl").val()
    }, dataType: "json", success: function (data) {
        $("#loading").hide(); switch (data.NextPage) { case "!": return false; break; case "Over": nextpage = -1; return false; break; case "Error": alert(data.ErrorMsg); break; case "Response": location.href = data.ErrorMsg; nextpage = -1; return false; break; case "ReadLimit": var insertPos = $("#Url"); insertPos.after("<divstyle='text-align:center;margin:30px auto 100px auto'>-- 试读结束只能查看 " + data.ErrorMsg + " 页。继续阅读,请关闭本窗口,再点击付费阅读按钮。 --</div>"); nextpage = -1; return false; break;
        }

上半部是请求,后半部是对返回结果的处理。根据上半部可以获取每一个下一页的链接,根据后半部可以作为获取到最后一页或出错的判断。

请求中的页全部在页面中,为hiddeninput

   <input type="hidden"id="Url"value="QzpcT2ZmaWNlV2ViMzY1XE9mZmljZVdlYlxjYWNoZVxQREZcMTE3MDUwNDA2MjQzNDEzNjMwMjEwMTU1ODRfNTQ3ODRcMjgyMjQyMC01OTBhNThhMjNlZmJjLmRvYy50ZW1w"autocomplete="off" />
    <input type="hidden"id="Img" value="Hs92T42xAvvI2Q9XNLpZjPD2G_91o9mUfZ0TmOh2aZwu_A@FsflB5o41TClbHy2D"autocomplete="off" />
    <input type="hidden"id="IsMobi" value="false" autocomplete="off"/>
    <input type="hidden"id="IsNet" value="True" autocomplete="off" />
    <input type="hidden"id="Furl" value="YOQStEpojXDVWEMEMy2zbvH4iMigQCjbdHMZ8zyLAF6JTE93kuMR3Q26RVkJZ6jdR5Oiuypy9hB0x@nksHt6wRqyluwxwSyCHFm5r3rbGmboJpu3Y7iugg=="autocomplete="off" />
    <input type="hidden"id="ReadLimit" value="63pU7jqloamXmUqHxeARYw=="autocomplete="off" />

构造请求测试一下(注意furl要使用URLEncoder编码):

https://view46.book118.com//pdf/GetNextPage/

?f=QzpcT2ZmaWNlV2ViMzY1XE9mZmljZVdlYlxjYWNoZVxQREZcMTE3MDUwNDA2MjQzNDEzNjMwMjEwMTU1ODRfNTQ3ODRcMjgyMjQyMC01OTBhNThhMjNlZmJjLmRvYy50ZW1w
&img=Hs92T42xAvvI2Q9XNLpZjPD2G_91o9mUfZ0TmOh2aZwu_A%40FsflB5o41TClbHy2D
&isMobile=false
&isNet=True&readLimit=yTkhuLJ4vjF8dah5bBrJrw%3D%3D
&furl=YOQStEpojXDVWEMEMy2zbvH4iMigQCjbdHMZ8zyLAF6JTE93kuMR3Q26RVkJZ6jdR5Oiuypy9hB0x%40nksHt6wRqyluwxwSyCHFm5r3rbGmboJpu3Y7iugg%3D%3D

获取到如下json

{ NextPage: "Hs92T42xAvvI2Q9XNLpZjPD2G_91o9mUfZ0TmOh2aZwu_A@FsflB5nLMusDqiT9avqCPgOtUecY=", PageCount: 4, ErrorMsg: "", PageIndex: 1, PageWidth: 792, Width: 792, Height: 1120 }

拼接前缀可以得到图片地址:

http://view46.book118.com/img/?img=Hs92T42xAvvI2Q9XNLpZjPD2G_91o9mUfZ0TmOh2aZwu_A@FsflB5nLMusDqiT9avqCPgOtUecY=

替换请求中的img则可以继续向后获取图片。

直到最后json中不再包含正确的NextPage则表示到了末尾。

二、实现

实现部分主要讲讲技术选型吧,我使用java开发。

2.1 页面的请求

最直接的当然还是使用httpclient,因为不需要处理中文,乱码问题可不考虑。

2.2 页面的解析

原本打算使用jsoup,想着倒也不多,直接使用正则撸完了。

2.3 pdf的生成

使用了itex,唯一的坑就是构造时指定了页面大小后,再修改第一次是不起作用的。

2.4 ocr

这部分功能我打算有空补上,目前测试了腾讯优图的在线OCR,识别率还可以。tesseract原生的识别率实在是太差。

三、后话

这里提供的是一种下载思路,说不上破解,我理解的破解是直接把原本的文件而不是预览图下载下来,希望有大神指指路。

*本文作者:过客匆匆打酱油