网页小说抓取 ios(红薯中文网网页版存在CSS伪类样式反爬,怎么办?)
优采云 发布时间: 2021-10-08 19:25网页小说抓取 ios(红薯中文网网页版存在CSS伪类样式反爬,怎么办?)
快过年了,好久没写文章了。我们今天要练习的网站是红书中文网站的网页版,手机版网站有CSS伪样式。爬吧,下次给大家解释一下。
目标分析
甘薯中文网站网站版的反爬虫主要在于小说的文字内容,所以我们可以找一本小说进行分析。值得注意的是,甘薯中文网在小说正文页禁用了鼠标右键。检查页面元素(Ctrl+Shift+I)或查看网页源代码(Ctrl+U)我们可以使用Chrome浏览器的快捷键:
在元素中呈现的页面
通过查看网页元素,我们可以发现浏览器渲染的数据没有出现乱码,说明没有我们上次讲的字体爬取。我们来看一下网页的源代码:
网页源代码
我们可以发现网页的源代码中并没有我们想要的数据,如果我们学过Django和Flask,可以发现网页使用了类似Django和Flask的模板语言。其实这就是前端模板语言,这也说明页面数据可能是通过ajax请求的,然后通过前端模板语言渲染到网页上。因此,我们可以使用 F12 来抓取和分析网页,然后找到这个请求数据:
Ajax 请求数据
我们找到了这个获取数据的请求,但是我们发现这个响应的json数据中加密了小说的内容。我们稍后会分析和处理这种加密。我们来分析一下获取这个Ajax请求所需的参数:
Ajax 请求详细信息
我们发现这个请求没有任何加密参数。至于post提交的参数,我们可以在小说目录页面上获取,这里就不多说了,通过postman模拟请求,我们也可以发现headers里面的参数其实并不是全部必需的:
邮递员模拟请求
既然拿到这个ajax请求是没有问题的,那我们就需要逆向破解小说的正文,因为这个请求是一个ajax请求,所以我们可以通过XHR/fetch Breakpoints进行调试,在XHR/fetch中添加断点名称断点并填写bookajax .do(加密文件名),然后刷新网页:
调试 Ajax 请求
然后我们按F10一步步调试,直到找到解密的小说内容:
解密前的代码
解密前的数据内容
解密后
解密后的数据内容
可以发现 data.content = utf8to16(hs_decrypt(base64decode(data.content), key)); 这段代码是解密的关键,为了找到解密方法,我们按照前面的分析方法分析解密函数,我们发现解密依赖于utf8to16函数,hs_decrypt函数(注意里面还有str2long和long2str函数这个我们需要获取的函数)、base64decode函数和key:
base64decode 函数.png
hs_decrypt 函数.png
然后我们把key反了,发现重新调试的key是在我们生成小说内容之前生成的:
反向键
我们还可以看到这个获取网络密钥的请求:
抓包请求中的key
获取内容的ajax api接口和之前一样,只是formdata提交的参数不同。这里就不介绍了。你可以自己研究一下,找到所有的解密依赖。我们可以分析解密逻辑或者用python js运行。该库用于运行js。由于时间问题,我不会研究解密逻辑。我直接使用js运行库。解密
至于发送请求获取密钥和加密内容的请求代码,我就不写了。解密代码我直接贴出来。如果需要,可以自己完成其余代码:
<p>import execjs
utf_to_changes = r"""
function utf8to16(str) {
var out, i, len, c;
var char2, char3;
out = "";
len = str.length;
i = 0;
while (i < len) {
c = str.charCodeAt(i++);
switch (c >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
out += str.charAt(i - 1);
break;
case 12:
case 13:
char2 = str.charCodeAt(i++);
out += String.fromCharCode(((c & 0x1F) 0; p--) {
z = v[p - 1];
mx = (z >>> 5 ^ y >> 3 ^ z >> 5 ^ y >> 3 ^ z >> 8 & 0xff, v[i] >>> 16 & 0xff, v[i] >>> 24 & 0xff);
}
if (w) {
return v.join('').substring(0, sl);
} else {
return v.join('');
}
}
function str2long(s, w) {
var len = s.length;
var v = [];
for (var i = 0; i < len; i += 4) {
v[i >> 2] = s.charCodeAt(i) | s.charCodeAt(i + 1)