前言

最近遇到了一个比较好玩的反爬--携程eleven参数的生成。

说好玩的原因是请求一个接口后,会返回js代码,只要稍微调试下,便可以在浏览器上得到eleven参数了。

但如果想要在node或者无头浏览器之类的东西完成的话,只会报错。

(需要代码的大佬可以跳到最后(node环境+油猴+py, 通过websocket给油猴和py代码通信))

爬取目标

说一下我们要爬的数据吧。(如下内容) https://hotels.ctrip.com/hotel/beijing1#ctm_ref=hod_hp_sb_lst

携程eleven参数

 

 

这些数据来自于此接口

携程eleven参数

 

是一个post请求,在请求体中便是著名的eleven参数了。

如果eleven参数错误的话,是不会返回上面的数据的。

 

 

Eleven参数

前面说过了,Eleven参数来自于一段js代码(这段js代码是请求一个url后直接返回的)

下面便是那个所要请求的url

携程eleven参数

 

请求此url后返回的js代码

携程eleven参数

 

 

 

1. 测试返回的js代码

我们新开一个标签页,然后将返回的js代码复制到控制台执行。会发现报了一个错

携程eleven参数

 

 应该是缺少了其它js代码造成的

// 这样可以产生一个与上图相似的错误 Function.prototype.toString.call(1);

 

 

我们还可以将返回的js代码复制到携程页面的控制台运行下,发现并没有报错,但我们的页面被重定向到了登陆页面

因此猜测返回的js代码的只能被执行一次(毕竟就是在携程的页面执行的。)

 

2. 下断点(看看返回的js代码是怎么运行的)

怎么下断点?搜索url中的关键字? 下xhr断点。

当时我用的方式是搜索url中的关键字, oceanball。那天是直接可以搜索到的。但今天没有了。

下xhr断点是不可能断下来的。因为他用到是jsonp来请求的。

 

那用啥方法呢?

看这个请求的发起者

鼠标移到下面红色箭头指的位置便可以看到这个请求的发起者

携程eleven参数

 

 

 

点击第二个发起者(js @cQuery_110421.js:formatted:823那行)

为什么是第二个,因为第一个不行,可以自行尝试

携程eleven参数

 

 

 

如图 下一个断点(823行,也是第二个发起者代码执行行数)

携程eleven参数

 

 

 

 

我们其实也可以在 "欢迎度排序" 和 "好评优先" 之间来回切换,不然总是刷新的话,效率不高

携程eleven参数

如果页面刷新了,或者如上切换了选项的话。页面会在我们之前下的断点停住。

 

注意下右边的 call stack(调用栈)

我们如下图点击一下 ,来到上一层的执行环境。

携程eleven参数

 

 

  

往上翻一下,就会发现这部分便是那个url从发起请求到处理返回结果的所有细节

如下图所示

携程eleven参数

 

 

其实只要在返回的js代码里加上如下内容

// 这里的o是请求url中callback参数。
window[o] = function (e){ console.log(e()); // 这样便可以输出结果了。 } // 下面是请求url后返回的js代码

这样代码便可以在浏览器中输出结果了

 

 

好了,重点部分来了。

 

3. 如何批量生成eleven参数

我不能说我手动复制到浏览器中运行,然后复制下结果吧。

在node环境中运行难度比较大,他会严格检测执行环境。

也别想断点调试。见过一个函数被调用18多万次吗?

 

是不是想问我是怎么知道这些的?

我是通过Object.defineProperty 劫持了 navigator.userAgent。

当这个js代码想要获取 navigator.userAgent 时,代码便会在此就会停住

Object.defineProperty(navigator, "userAgent", {
   get(){
          debugger;
          return  navigator.userAgent;     
    } 
})

 

然后慢慢堆栈时发现某一个函数貌似便是用于检测环境的函数啥的。然后那个函数被调用了18万多次。

检测的内容非常多,不光是node环境,还有无头浏览器啥的,你听过的没听过的都有。

 

处理方法

已经有大佬在node环境中模拟了这个浏览器环境了,像我这种菜鸡,估计是难做到了。

我的想法很简单,还是通过浏览器执行那些js代码,但是需要自动执行。

vscode的自动保存便刷新页面的插件给了我启发,他是通过websocket进行通信,服务器会将最新的html传给客户端,客户端可以做一定的处理

 

1. 首先需要使用nodejs搭建一个websocket的环境,可以使用 nodejs-websocket 模块搭建

 

代码如下

需要安装下node环境(node官网下载,像装软件一样安装即可。)

携程eleven参数
var ws = require("nodejs-websocket");
console.log("开始建立连接...")

var cached = {

}
var server = ws.createServer(function(conn){
    conn.on("text", function (msg) {
        if (!msg) return;
        // conn.sendText(str)
        // console.log(str);
        if (msg.length > 1000){
            console.log("msg 这是js代码")
        }else{
            console.log("msg", msg);
        }
        var key = conn.key;
        if ((msg === "Browser") || (msg === "Python")){
            // browser或者python第一次连接
            cached[msg] = key;
            console.log("cached",cached);
            return;
        }
        console.log(cached, key);
        if (Object.values(cached).includes(key)){
            console.log(server.connections.forEach(conn=>conn.key));
            var targetConn = server.connections.filter(function(conn){
                return conn.key !== key;
            })
            console.log(targetConn.key);
            console.log("将要发送的js代码");
            targetConn.forEach(conn=>{
                conn.send(msg);
            })
        }
        // broadcast(server, str);
    })
    conn.on("close", function (code, reason) {
        console.log("关闭连接")
    });
    conn.on("error", function (code, reason) {
        console.log("异常关闭")
    });
}).listen(8014)
console.log("WebSocket建立完毕")


// var server = http.createServer(function(request, response){
//     response.end("ok");
// }).listen(8000);
View Code

相关文章:

  • 2021-12-25
  • 2021-07-16
  • 2022-01-06
  • 2021-06-07
  • 2021-09-23
  • 2022-01-07
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-11-27
  • 2021-11-22
  • 2022-12-23
  • 2021-06-30
  • 2022-02-09
  • 2022-12-23
相关资源
相似解决方案