一、前言简介

  在现在各个网站使用的反爬措施中,使用 JavaScript 加密算是很常用的了,通常会使用 JavaScript 加密某个参数,例如 token 或者 sign。在这次的例子中,就采取了这种措施来反爬,使用 JavaScript 加密了一个参数 antitoken,而本篇博客要写的就是如何应对和解决的。

二、站点分析

  本次爬取的站点链接为:https://www.ly.com/hotel/beijing53/?spm0=10002.2001.1.0.1.4.17

  等页面加载完毕后打开开发者工具,切换到 XHR 选项,然后找到如下请求:

  

  注意到参数中有一个 antitoken,这是一个加密后的字符串 ,那要怎么得到这个加密参数 antitoken 呢?

三、破解步骤

1.搜索加密方法

  在开发者工具中全局搜索 antitoken,找到名为 list-newest.js 的 JS 文件,切换到 Sources 页面,找到这个 JS 文件并打开,点击左下角的 “{}” 进行格式化便于我们进行查阅,如下图:

  

  在这个 JS 文件中搜索 antitoken,通过查找可以定位到一个获取 antitoken 的方法,具体代码如下:

e.getantitoken = function() {
    var t = $.cookie("wangba");
    t && void 0 !== t || (t = (new Date).getTime().toString(),
    $.cookie("wangba", t, {
        path: "/",
        domain: "ly.com"
    }));
    return (0,
    r["default"])(t)
}
;

  可以看到先是要从 Cookie 中获取一个名为 wangba 字段的值,wangba ?网吧?谁知道呢。如果 wangba 为空,则重新创建一个,而创建的其实就是一个十三位的时间戳。

var t = $.cookie("wangba");
t && void 0 !== t || (t = (new Date).getTime().toString(),

  在 return 那一行打上断点,然后刷新页面进行调试,跳转到 return 返回的方法,如下图:

  

  为了知道 antitoken 是怎么生成的,我们需要知道这个函数里各个参数 n,i,o,r 的含义,所以又得继续打断点进行调试了。

  首先是 n,通过代码知道 n = a(30),打断点后找到 n 参数对应的代码如下:

n = {
rotl: function(t, e) {
return t << e | t >>> 32 - e
},
rotr: function(t, e) {
return t << 32 - e | t >>> e
},
endian: function(t) {
if (t.constructor == Number)
return 16711935 & n.rotl(t, 8) | 4278255360 & n.rotl(t, 24);
for (var e = 0; e < t.length; e++)
t[e] = n.endian(t[e]);
return t
},
randomBytes: function(t) {
for (var e = []; t > 0; t--)
e.push(Math.floor(256 * Math.random()));
return e
},
bytesToWords: function(t) {
for (var e = [], a = 0, n = 0; a < t.length; a++,
n += 8)
e[n >>> 5] |= t[a] << 24 - n % 32;
return e
},
wordsToBytes: function(t) {
for (var e = [], a = 0; a < 32 * t.length; a += 8)
e.push(t[a >>> 5] >>> 24 - a % 32 & 255);
return e
},
bytesToHex: function(t) {
for (var e = [], a = 0; a < t.length; a++)
e.push((t[a] >>> 4).toString(16)),
e.push((15 & t[a]).toString(16));
return e.join("")
},
hexToBytes: function(t) {
for (var e = [], a = 0; a < t.length; a += 2)
e.push(parseInt(t.substr(a, 2), 16));
return e
},
bytesToBase64: function(t) {
for (var e = [], n = 0; n < t.length; n += 3)
for (var i = t[n] << 16 | t[n + 1] << 8 | t[n + 2], r = 0; r < 4; r++)
8 * n + 6 * r <= 8 * t.length ? e.push(a.charAt(i >>> 6 * (3 - r) & 63)) : e.push("=");
return e.join("")
},
base64ToBytes: function(t) {
t = t.replace(/[^A-Z0-9+\/]/gi, "");
for (var e = [], n = 0, i = 0; n < t.length; i = ++n % 4)
0 != i && e.push((a.indexOf(t.charAt(n - 1)) & Math.pow(2, -2 * i + 8) - 1) << 2 * i | a.indexOf(t.charAt(n)) >>> 6 - 2 * i);
return e
}
},

  然后是 i,通过代码知道 i = a(12).utf-8,打断点后找到 i 参数对应的代码如下:

{
stringToBytes: function(t) {
return a.bin.stringToBytes(unescape(encodeURIComponent(t)))
},
bytesToString: function(t) {
return decodeURIComponent(escape(a.bin.bytesToString(t)))
}
}

  然后是 o,通过代码知道 o = a(12).bin,打断点后找到 o 参数对应的代码如下:

{
stringToBytes: function (t) {
for (var e = [], a = 0; a < t.length; a++)
e.push(255 & t.charCodeAt(a));
return e
}
,
bytesToString: function (t) {
for (var e = [], a = 0; a < t.length; a++)
e.push(String.fromCharCode(t[a]));
return e.join("")
}
}

  这里可以定义一个 a12,然后从其中取出相应的方法就行了。

var a12 = {
utf8: {
stringToBytes: function (e) {
return a12.bin.stringToBytes(unescape(encodeURIComponent(e)))
},
bytesToString: function (e) {
return decodeURIComponent(escape(a.bin.bytesToString(e)))
}
},
bin: {
stringToBytes: function (e) {
for (var t = [], a = 0; a < e.length; a++)
t.push(255 & e.charCodeAt(a));
return t
},
bytesToString: function (e) {
for (var t = [], a = 0; a < e.length; a++)
t.push(String.fromCharCode(e[a]));
return t.join("")
}
}
};

  最后还剩一个 o 参数,通过断点调试可以定位到如下代码:

  

  可见这个参数 o 赋值为 null 就够了。到这里为止就已经得到加密方法里的各个参数了,接下来要说的就是如何实现加密得到 antitoken。

2.实现加密方法

  要实现加密方法,还需要知道一点,就是加密时传入了两个参数,一个是十三位时间戳,另一个是空值,通过调试可知,截图如下:

  

  将前面的各个参数和方法进行整理,得到如下 JavaScript 代码:

 //定义antitoken
function antitoken(e) {
var a12 = {
utf8: {
stringToBytes: function (e) {
return a12.bin.stringToBytes(unescape(encodeURIComponent(e)))
},
bytesToString: function (e) {
return decodeURIComponent(escape(a.bin.bytesToString(e)))
}
},
bin: {
stringToBytes: function (e) {
for (var t = [], a = 0; a < e.length; a++)
t.push(255 & e.charCodeAt(a));
return t
},
bytesToString: function (e) {
for (var t = [], a = 0; a < e.length; a++)
t.push(String.fromCharCode(e[a]));
return t.join("")
}
}
};
var t = null;
var n, i, o, s, r;
n = {
rotl: function (e, t) {
return e << t | e >>> 32 - t
},
rotr: function (e, t) {
return e << 32 - t | e >>> t
},
endian: function (e) {
if (e.constructor == Number)
return 16711935 & n.rotl(e, 8) | 4278255360 & n.rotl(e, 24);
for (var t = 0; t < e.length; t++)
e[t] = n.endian(e[t]);
return e
},
randomBytes: function (e) {
for (var t = []; e > 0; e--)
t.push(Math.floor(256 * Math.random()));
return t
},
bytesToWords: function (e) {
for (var t = [], a = 0, n = 0; a < e.length; a++,
n += 8)
t[n >>> 5] |= e[a] << 24 - n % 32;
return t
},
wordsToBytes: function (e) {
for (var t = [], a = 0; a < 32 * e.length; a += 8)
t.push(e[a >>> 5] >>> 24 - a % 32 & 255);
return t
},
bytesToHex: function (e) {
for (var t = [], a = 0; a < e.length; a++)
t.push((e[a] >>> 4).toString(16)),
t.push((15 & e[a]).toString(16));
return t.join("")
},
hexToBytes: function (e) {
for (var t = [], a = 0; a < e.length; a += 2)
t.push(parseInt(e.substr(a, 2), 16));
return t
},
bytesToBase64: function (e) {
for (var t = [], n = 0; n < e.length; n += 3)
for (var i = e[n] << 16 | e[n + 1] << 8 | e[n + 2], o = 0; o < 4; o++)
8 * n + 6 * o <= 8 * e.length ? t.push(a.charAt(i >>> 6 * (3 - o) & 63)) : t.push("=");
return t.join("")
},
base64ToBytes: function (e) {
e = e.replace(/[^A-Z0-9+\/]/gi, "");
for (var t = [], n = 0, i = 0; n < e.length; i = ++n % 4)
0 != i && t.push((a.indexOf(e.charAt(n - 1)) & Math.pow(2, -2 * i + 8) - 1) << 2 * i | a.indexOf(e.charAt(n)) >>> 6 - 2 * i);
return t
}
},
i = a12.utf8,
o = null,
s = a12.bin,
(r = function (e, t) {
e.constructor == String ? e = t && "binary" === t.encoding ? s.stringToBytes(e) : i.stringToBytes(e) : o(e) ? e = Array.prototype.slice.call(e, 0) : Array.isArray(e) || (e = e.toString());
for (var a = n.bytesToWords(e), l = 8 * e.length, c = 1732584193, d = -271733879, p = -1732584194, u = 271733878, m = 0; m < a.length; m++)
a[m] = 16711935 & (a[m] << 8 | a[m] >>> 24) | 4278255360 & (a[m] << 24 | a[m] >>> 8);
a[l >>> 5] |= 128 << l % 32;
a[14 + (l + 64 >>> 9 << 4)] = l;
var f = r._ff
, h = r._gg
, v = r._hh
, g = r._ii;
for (m = 0; m < a.length; m += 16) {
var y = c
, _ = d
, b = p
, $ = u;
d = g(d = g(d = g(d = g(d = v(d = v(d = v(d = v(d = h(d = h(d = h(d = h(d = f(d = f(d = f(d = f(d, p = f(p, u = f(u, c = f(c, d, p, u, a[m + 0], 7, -680876936), d, p, a[m + 1], 12, -389564586), c, d, a[m + 2], 17, 606105819), u, c, a[m + 3], 22, -1044525330), p = f(p, u = f(u, c = f(c, d, p, u, a[m + 4], 7, -176418897), d, p, a[m + 5], 12, 1200080426), c, d, a[m + 6], 17, -1473231341), u, c, a[m + 7], 22, -45705983), p = f(p, u = f(u, c = f(c, d, p, u, a[m + 8], 7, 1770035416), d, p, a[m + 9], 12, -1958414417), c, d, a[m + 10], 17, -42063), u, c, a[m + 11], 22, -1990404162), p = f(p, u = f(u, c = f(c, d, p, u, a[m + 12], 7, 1804603682), d, p, a[m + 13], 12, -40341101), c, d, a[m + 14], 17, -1502002290), u, c, a[m + 15], 22, 1236535329), p = h(p, u = h(u, c = h(c, d, p, u, a[m + 1], 5, -165796510), d, p, a[m + 6], 9, -1069501632), c, d, a[m + 11], 14, 643717713), u, c, a[m + 0], 20, -373897302), p = h(p, u = h(u, c = h(c, d, p, u, a[m + 5], 5, -701558691), d, p, a[m + 10], 9, 38016083), c, d, a[m + 15], 14, -660478335), u, c, a[m + 4], 20, -405537848), p = h(p, u = h(u, c = h(c, d, p, u, a[m + 9], 5, 568446438), d, p, a[m + 14], 9, -1019803690), c, d, a[m + 3], 14, -187363961), u, c, a[m + 8], 20, 1163531501), p = h(p, u = h(u, c = h(c, d, p, u, a[m + 13], 5, -1444681467), d, p, a[m + 2], 9, -51403784), c, d, a[m + 7], 14, 1735328473), u, c, a[m + 12], 20, -1926607734), p = v(p, u = v(u, c = v(c, d, p, u, a[m + 5], 4, -378558), d, p, a[m + 8], 11, -2022574463), c, d, a[m + 11], 16, 1839030562), u, c, a[m + 14], 23, -35309556), p = v(p, u = v(u, c = v(c, d, p, u, a[m + 1], 4, -1530992060), d, p, a[m + 4], 11, 1272893353), c, d, a[m + 7], 16, -155497632), u, c, a[m + 10], 23, -1094730640), p = v(p, u = v(u, c = v(c, d, p, u, a[m + 13], 4, 681279174), d, p, a[m + 0], 11, -358537222), c, d, a[m + 3], 16, -722521979), u, c, a[m + 6], 23, 76029189), p = v(p, u = v(u, c = v(c, d, p, u, a[m + 9], 4, -640364487), d, p, a[m + 12], 11, -421815835), c, d, a[m + 15], 16, 530742520), u, c, a[m + 2], 23, -995338651), p = g(p, u = g(u, c = g(c, d, p, u, a[m + 0], 6, -198630844), d, p, a[m + 7], 10, 1126891415), c, d, a[m + 14], 15, -1416354905), u, c, a[m + 5], 21, -57434055), p = g(p, u = g(u, c = g(c, d, p, u, a[m + 12], 6, 1700485571), d, p, a[m + 3], 10, -1894986606), c, d, a[m + 10], 15, -1051523), u, c, a[m + 1], 21, -2054922799), p = g(p, u = g(u, c = g(c, d, p, u, a[m + 8], 6, 1873313359), d, p, a[m + 15], 10, -30611744), c, d, a[m + 6], 15, -1560198380), u, c, a[m + 13], 21, 1309151649), p = g(p, u = g(u, c = g(c, d, p, u, a[m + 4], 6, -145523070), d, p, a[m + 11], 10, -1120210379), c, d, a[m + 2], 15, 718787259), u, c, a[m + 9], 21, -343485551),
c = c + y >>> 0;
d = d + _ >>> 0;
p = p + b >>> 0;
u = u + $ >>> 0;
}
return n.endian([c, d, p, u])
}
)._ff = function (e, t, a, n, i, o, s) {
var r = e + (t & a | ~t & n) + (i >>> 0) + s;
return (r << o | r >>> 32 - o) + t
}; r._gg = function (e, t, a, n, i, o, s) {
var r = e + (t & n | a & ~n) + (i >>> 0) + s;
return (r << o | r >>> 32 - o) + t
}; r._hh = function (e, t, a, n, i, o, s) {
var r = e + (t ^ a ^ n) + (i >>> 0) + s;
return (r << o | r >>> 32 - o) + t
}; r._ii = function (e, t, a, n, i, o, s) {
var r = e + (a ^ (t | ~n)) + (i >>> 0) + s;
return (r << o | r >>> 32 - o) + t
}; r._blocksize = 16;
r._digestsize = 16; var a = n.wordsToBytes(r(e, t));
return t && t.asBytes ? a : t && t.asString ? s.bytesToString(a) : n.bytesToHex(a);
}

  这就是使用 JavaScript 实现的加密方法了,传入的参数 e 是一个十三位时间戳,之后无论使用 JS 还是 Python 进行调用都可以了,这里可以进行一下验证。

  首先是开发者工具里的截图:

  

  然后是代码的运行结果:

  

【Python3爬虫】反反爬之破解同程旅游加密参数 antitoken的更多相关文章

  1. 【Python3爬虫】反反爬之解决前端反调试问题

    一.前言 在我们爬取某些网站的时候,会想要打开 DevTools 查看元素或者抓包分析,但按下 F12 的时候,却出现了下面这一幕: 此时网页暂停加载,也就没法运行代码了,直接中断掉了,难道这就能阻止 ...

  2. python3爬虫-快速入门-爬取图片和标题

    直接上代码,先来个爬取豆瓣图片的,大致思路就是发送请求-得到响应数据-储存数据,原理的话可以先看看这个 https://www.cnblogs.com/sss4/p/7809821.html impo ...

  3. python3 爬虫教学之爬取链家二手房(最下面源码) //以更新源码

    前言 作为一只小白,刚进入Python爬虫领域,今天尝试一下爬取链家的二手房,之前已经爬取了房天下的了,看看链家有什么不同,马上开始. 一.分析观察爬取网站结构 这里以广州链家二手房为例:http:/ ...

  4. python3爬虫-使用requests爬取起点小说

    import requests from lxml import etree from urllib import parse import os, time def get_page_html(ur ...

  5. 【Python3 爬虫】14_爬取淘宝上的手机图片

    现在我们想要使用爬虫爬取淘宝上的手机图片,那么该如何爬取呢?该做些什么准备工作呢? 首先,我们需要分析网页,先看看网页有哪些规律 打开淘宝网站http://www.taobao.com/ 我们可以看到 ...

  6. 【Python3爬虫】我爬取了七万条弹幕,看看RNG和SKT打得怎么样

    一.写在前面 直播行业已经火热几年了,几个大平台也有了各自独特的“弹幕文化”,不过现在很多平台直播比赛时的弹幕都基本没法看的,主要是因为网络上的喷子还是挺多的,尤其是在观看比赛的时候,很多弹幕不是喷选 ...

  7. 【Python3爬虫】破解时光网登录加密参数并实现模拟登录

    一.站点分析 MTime 时光网是一个电影媒体与电商服务平台,而这次做的模拟登录则是依靠其手机端站点,站点地址为:https://m.mtime.cn/#.切换到登录页面,再分别输入账号和错误的密码, ...

  8. python3 [爬虫实战] selenium 爬取安居客

    我们爬取的网站:https://www.anjuke.com/sy-city.html 获取的内容:包括地区名,地区链接: 安居客详情 一开始直接用requests库进行网站的爬取,会访问不到数据的, ...

  9. python3爬虫-通过requests爬取图虫网

    import requests from fake_useragent import UserAgent from requests.exceptions import Timeout from ur ...

随机推荐

  1. 04 namenode和datanode

    namenode元数据管理 1.什么是元数据? hdfs的目录结构及每一个文件的块信息(块的id,块的副本数量,块的存放位置<datanode>) 2.元数据由谁负责管理? namenod ...

  2. Nginx之负载均衡配置(二)

    前文我们聊到了nginx作为负载均衡的配置,前端nginx作为调度器调度http或https请求,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/12458159 ...

  3. go-admin基于Gin + Vue + Element UI的前后端分离权限管理系统

    ✨ 特性 遵循 RESTful API 设计规范 基于 GIN WEB API 框架,提供了丰富的中间件支持(用户认证.跨域.访问日志.追踪ID等) 基于Casbin的 RBAC 访问控制模型 JWT ...

  4. [code]poj3349 Snowflake Snow Snowflakes

    哈希+挂链.可以用next数组挂链. ; type arr=..]of longint; var a,b:Array[..]of arr; next:Array[..]of longint; i,j, ...

  5. Java学习笔记(3)——有关异常

    异常处理: try { }catch(ExceptionType0 e) { }catch(ExceptionType1 e) { }.....finally { } 有四种情况不执行finally语 ...

  6. Mol Cell Proteomics. | Proteomics Analysis of Extracellular Matrix Remodeling During Zebrafish Heart Regeneration (解读人:徐宁)

    文献名:Proteomics Analysis of Extracellular Matrix Remodeling During Zebrafish Heart Regeneration(斑马鱼心脏 ...

  7. .net core 依赖注入, autofac 简单使用

    综述 ASP.NET Core  支持依赖注入, 也推荐使用依赖注入. 主要作用是用来降低代码之间的耦合度. 什么是控制反转? 控制反转(Inversion of Control,缩写为IoC),是面 ...

  8. java 为什么重写equals一定要重写hashcode?

    前言 最近复习,又看到了这个问题,在此记录和整理,通过例子来说明这种情况的原因,使大家可以清晰明白这个问题. 初步探索 首先我们要了解equals方法是什么,hashcode方法是什么. equals ...

  9. TensorFlow系列专题(二):机器学习基础

    欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/ ,学习更多的机器学习.深度学习的知识! 目录: 数据预处理 归一化 标准化 离散化 二值化 哑编码 特征 ...

  10. dijskra算法(求正权图中最短路)

    思想:每次找到离原点最近的顶点,以这个点为中心扩展松弛,更新其余点到原点的最短路径. 注意:if(e[u][v]>x)e[u][v]=x; book[ ]数组标记最短路程的顶点集合 #inclu ...