Python反反爬之JS混淆---源码乱码(详细教程)

高级实战案例:Python反反爬之JavaScript混淆 写在前面 很早之前在吾爱破解论坛上看见了【猿人学】Web端爬虫攻防大赛,当时进入他们官网的时候,比赛已经结束了。看着那些题目还挺有意思的,但由于各种原因一直没有机会去做那些题目。最近比较闲,就去把猿人学官网打开看了一下,尝试着完成了第一道题目---JS混淆[源码乱码] """ 当然在学习Python的道路上肯定会困难,没有好的学习资料,怎么去学习呢? 学习Python中有不明白推荐加入交流群号:928946953 群里有志同道合的小伙伴,互帮互助, 群里有不错的视频学习教程和PDF! 还有大牛解答 阅读详情

写在前面

很早之前在吾爱破解论坛上看见了【猿人学】Web端爬虫攻防大赛,当时进入他们官网的时候,比赛已经结束了。看着那些题目还挺有意思的,但由于各种原因一直没有机会去做那些题目。最近比较闲,就去把猿人学官网打开看了一下,尝试着完成了第一道题目—JS混淆[源码乱码],当然我也去看了两位大佬的讲解,一位是吾爱论坛的漁滒,另一位是B站的暗螟蛉

由于这是一篇迟到的教程,所有我写比较详细,希望对大家有所帮助
文章原链接https://syjun.vip/archives/278.html

题目

抓取所有(5页)机票的价格,并计算所有机票价格的平均值,填入答案。
题目看着挺简单,就是抓取机票的价格,并算出平均值,但是当我们打开开发者调试工具的时候,就会遇到第一个坑

关闭断点

当我们打开调试工具的时候,会弹出这么一个页面

这是一个debug断点,会阻拦我们后面的操作,但是并没有什么关系,很简单就能把它关闭

查看数据来源

接着,我们点击【Network】,按ctrl+f5刷新网页,又会出现阻拦的操作,我们依然点击刚才箭头符号,就可以解决

接着,我们回到【Network】,点击【XHR】,就会发现多了一条信息
至于,为什么要去点击【XHR】而不是点击其他的地方;其实也很简单,你稍微去检测一下这个网页,就会发现,机票的价格是通过XHR请求获取到的
有些小伙伴可能就要问了,什么是XHR请求,你可以去这篇文章看看XHR 请求
回过头来,我们来看看多出来的那条信息

查看这条信息的Header,发现它的URL很有意思,特别是画蓝色下划线的地方,这里我们先不管,我们接着看一下Preview
这就更有意思了,如我们所预料的,机票的价格都包含在这里面

分析URL

链接和数据都找了,我们去访问一下刚刚的链接(间隔了一段时间),理所当然的报错了

{"error": "token failed"}

我们看一下这条链接

http://match.yuanrenxue.com/api/match/1?m=f289e3140053a9320c137b67e8723ba3%E4%B8%A81608971657

经常写爬虫的同学就会发现,后面的数字串【1608971657】,一定是一个时间戳
也就是说,要想正常的访问这条链接拿到数据,一定要有正常的时间戳
那么,何为正常的时间戳,一定和前面的字符串有关(m=f289e3140053a9320c137b67e8723ba3%E4%B8%A8)

我们继续刷新页面,发现【m=…】里面的字符串随着时间的推移都在进行变化,唯独[%E4%B8%A8]没变

[%E4%B8%A8],这个我想大家只要用过百度搜索就应该很熟悉吧,它是经过UrlEncode处理得到的,我们只需要反解码就能知道[%E4%B8%A8]到达是个什么东东
我们来到,站长工具,将它进行解码

很容易的,我们得到了它的值------> 丨 (没错就是这么一个中文符号)

寻找丨符号

根据题目的提示[js混淆 源码乱码],我们可以想到一个很清晰的思路,就是去源码当中查找 丨
回到页面,点击鼠标右键,点击[查看网页源代码]
按crtl+F ,搜索丨 符号,会找到唯一的一处代码
仔细地查看代码,发现它是写在script标签里面的
我们将整个script标签复制下来,到notepad++里面打开

<script>window.url='/api/match/1';request=function(){var timestamp=Date.parse(new Date()) + 100000000;var m=oo0O0(timestamp.toString())+window.f;var list={"page":window.page,"m":m+'丨'+timestamp/1000};$.ajax({url:window.url,dataType:"json",async:false,data:list,type:"GET",beforeSend:function(request){},success:function(data){data=data.data;let html='';let us_sign=`<div class="b-airfly"><div class="e-airfly"data-reactid=".1.3.3.2.0.$KN5911.0"><div class="col-trip"data-reactid=".1.3.3.2.0.$KN5911.0.0"><div class="s-trip"data-reactid=".1.3.3.2.0.$KN5911.0.0.0"><div class="col-airline"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.0"><div class="d-air"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.0.0:$0"><div class="air"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.0.0:$0.0"><span data-reactid=".1.3.3.2.0.$KN5911.0.0.0.0.0:$0.0.1">中国联合航空</span></div><div class="num"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.0.0:$0.1"><span class="n"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.0.0:$0.1.0">KN5911</span><span class="n"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.0.0:$0.1.1">波音737(中)</span><noscript data-reactid=".1.3.3.2.0.$KN5911.0.0.0.0.0:$0.1.2"></noscript></div></div><noscript data-reactid=".1.3.3.2.0.$KN5911.0.0.0.0.1"></noscript></div><div class="col-time"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1"><div class="sep-lf"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.0"><h2 data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.0.0">13:50</h2><p class="airport"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.0.1"><span data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.0.1.0">大兴国际机场</span><span data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.0.1.1"></span></p></div><div class="sep-ct"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.1"><div class="range"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.1.0">3小时40分钟</div><div class="line"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.1.1"></div></div><div class="sep-rt"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.2"><noscript data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.2.0"></noscript><h2 data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.2.1">17:30</h2><p class="airport"data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.2.2"><span data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.2.2.0">宝安机场</span></p></div><noscript data-reactid=".1.3.3.2.0.$KN5911.0.0.0.1.3"></noscript></div></div></div><div class="col-price"data-reactid=".1.3.3.2.0.$KN5911.0.1"><p class="prc"data-reactid=".1.3.3.2.0.$KN5911.0.1.0"><span data-reactid=".1.3.3.2.0.$KN5911.0.1.0.0"><i class="rmb"data-reactid=".1.3.3.2.0.$KN5911.0.1.0.0.0">&yen;</i><span class="fix_price"data-reactid=".1.3.3.2.0.$KN5911.0.1.0.0.1"><span class="prc_wp"style="width:48px">price_sole</span></span></span></p><div class="vim"data-reactid=".1.3.3.2.0.$KN5911.0.1.1"><span class="v dis"data-reactid=".1.3.3.2.0.$KN5911.0.1.1.$0"></span></div></div><div class="col-fold"data-reactid=".1.3.3.2.0.$KN5911.0.2"><p class="fd"data-reactid=".1.3.3.2.0.$KN5911.0.2.0">收起</p></div></div><noscript data-reactid=".1.3.3.2.0.$KN5911.1"></noscript></div>`;let choice=['中国南方航空','吉祥航空','奥凯航空','九元航空','长龙航空','东方航空','中国国际航空','深圳航空','海南航空','春秋航空','上海航空','西部航空','重庆航空','西藏航空','中国联合航空','云南祥鹏航空','云南英安航空','厦门航空','天津航空','山东航空','四川航空','华夏航空','长城航空','成都航空有','北京首都航空','中华航空','意大利国家航空公司','印度百捷航空','越南航空','远东航空','印度航空公司','印度捷特航空有限公司','以色列航空公司','意大利航空','伊朗航空公司','印度尼西亚鹰航空公司','英国航空公司','西方天空航空','西捷航空','西班牙欧洲航空公司','西班牙航空公司','中国南方航空','吉祥航空','奥凯航空','九元航空','长龙航空','东方航空','中国国际航空','深圳航空','海南航空','春秋航空','上海航空','西部航空','重庆航空','西藏航空','中国联合航空','云南祥鹏航空','云南英安航空','厦门航空','天津航空','山东航空','四川航空','华夏航空','长城航空','成都航空有','北京首都航空','中华航空','意大利国家航空公司','印度百捷航空','越南航空','远东航空','印度航空公司','印度捷特航空有限公司','以色列航空公司','意大利航空','伊朗航空公司','印度尼西亚鹰航空公司','英国航空公司','西方天空航空','西捷航空','西班牙欧洲航空公司','西班牙航空公司'];let op=1; let jic=['北京首都国际机场','上海虹桥国际机场','上海浦东国际机场','天津滨海国际机场','太原武宿机场','呼和浩特白塔机场','沈阳桃仙国际机场','大连周水子国际机场','长春大房身机场','哈尔滨阎家岗国际机场','齐齐哈尔三家子机场','佳木斯东郊机场','厦门高崎国际机场','福州长乐国际机场','杭州萧山国际机场','合肥骆岗机场','宁波栎社机场','南京禄口国际机场','广州白云国际机场','深圳宝安国际机场','长沙黄花机场','海口美亚机场','武汉天河机场','济南遥墙机场','青岛流亭机场','南宁吴墟机场','三亚凤凰国际机场','重庆江北国际机场','成都双流国际机场','昆明巫家坝国际机场','昆明长水国际机场','桂林两江国际机场','西安咸阳国际机场','兰州中川机场','贵阳龙洞堡机场','拉萨贡嘎机场','乌鲁木齐地窝堡机场','南昌向塘机场','郑州新郑机场','北京首都国际机场','上海虹桥国际机场','上海浦东国际机场','天津滨海国际机场','太原武宿机场','呼和浩特白塔机场','沈阳桃仙国际机场','大连周水子国际机场','长春大房身机场','哈尔滨阎家岗国际机场','齐齐哈尔三家子机场','佳木斯东郊机场','厦门高崎国际机场','福州长乐国际机场','杭州萧山国际机场','合肥骆岗机场','宁波栎社机场','南京禄口国际机场','广州白云国际机场','深圳宝安国际机场','长沙黄花机场','海口美亚机场','武汉天河机场','济南遥墙机场','青岛流亭机场','南宁吴墟机场','三亚凤凰国际机场','重庆江北国际机场','成都双流国际机场','昆明巫家坝国际机场','昆明长水国际机场','桂林两江国际机场','西安咸阳国际机场','兰州中川机场','贵阳龙洞堡机场','拉萨贡嘎机场','乌鲁木齐地窝堡机场','南昌向塘机场','郑州新郑机场'];if(window.page){}else{window.page=1}$.each(data,function(index,val){html+=us_sign.replace('price_sole',val.value).replace('中国联合航空',choice[op*window.page]).replace('大兴国际',jic[parseInt(op*window.page/2)+1]).replace('宝安机场',jic[jic.length-parseInt(op*window.page/2)-1]);op+=1});$('.m-airfly-lst').text('').append(html)},complete:function(){},error:function(){alert('数据拉取失败。可能是触发了风控系统,若您是正常访问,请使用谷歌浏览器无痕模式,并且校准电脑的系统时间重新尝试');alert('生而为虫,我很抱歉,请刷新页面,查看问题是否存在');$('.page-message').eq(0).addClass('active');$('.page-message').removeClass('active')}})};request()</script>

粘贴到notepad++,你会发现全部的代码都浓缩成一行了
不要慌,我们可以使用notepad++自带的插件JSTool里面的JSFormat,即可将JS的代码格式化,得到如下结果
(如果没有JSTool插件,可以在notepad++里面安装一下)

ajax里面的内容可以不用管,我们删除多余的代码,可以得到简化后的代码

<script>
request = function () {
    var timestamp = Date.parse(new Date()) + 100000000;
    var m = oo0O0(timestamp.toString()) + window.f;
    var list = {
        "page": window.page,
        "m": m + '丨' + timestamp / 1000
    };
};
request()
</script>

var list 里面的内容,也可以不用管,这里面主要就是包含页码,和m值,于是我们可以再次精简

var timestamp = Date.parse(new Date()) + 100000000;
var m = oo0O0(timestamp.toString()) + window.f;

这里的变量m,是不是很熟悉,我们再来看一下之前的链接

http://match.yuanrenxue.com/api/match/1?m=f289e3140053a9320c137b67e8723ba3%E4%B8%A81608971657
大胆的猜测一下,m后面的值肯定是通过这里的代码实现的
我们先来看一下var m 后面的内容

  • oo0O0(),肯定是一个函数
  • timestamp.toString(),有一点编程基础的同学应该能猜到,这是将时间戳的一串数字转化成字符串类型
  • window.f,窗口这个对象调用了f,至于f是什么东东,我们先不管

很显然,我们又有了一个新的突破口,**oo0O0()**函数

分析oo0O0()函数

我们回到包含网页源码的页面,搜索[oo0O0]
会找到两处代码,一处肯定是定义此函数的代码,而另一处就是调用函数的代码
我们将定义此函数的代码复制下来

function oo0O0(mw) {
    window.b = '';
    for (var i = 0, len = window.a.length; i < len; i++) {
        console.log(window.a[i]);
        window.b += String[document.e + document.g](window.a[i][document.f + document.h]() - i - window.c)
    }
    var U = ['W5r5W6VdIHZcT8kU', 'WQ8CWRaxWQirAW=='];
    var J = function (o, E) {
        o = o - 0x0;
        var N = U[o];
        if (J['bSSGte'] === undefined) {
            var Y = function (w) {
                var m = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=',
                T = String(w)['replace'](/=+$/, '');
                var A = '';
                for (var C = 0x0, b, W, l = 0x0; W = T['charAt'](l++); ~W && (b = C % 0x4 ? b * 0x40 + W : W, C++ % 0x4) ? A += String['fromCharCode'](0xff & b >> (-0x2 * C & 0x6)) : 0x0) {
                    W = m['indexOf'](W)
                }
                return A
            };
            var t = function (w, m) {
                var T = [],
                A = 0x0,
                C,
                b = '',
                W = '';
                w = Y(w);
                for (var R = 0x0, v = w['length']; R < v; R++) {
                    W += '%' + ('00' + w['charCodeAt'](R)['toString'](0x10))['slice'](-0x2)
                }
                w = decodeURIComponent(W);
                var l;
                for (l = 0x0; l < 0x100; l++) {
                    T[l] = l
                }
                for (l = 0x0; l < 0x100; l++) {
                    A = (A + T[l] + m['charCodeAt'](l % m['length'])) % 0x100,
                    C = T[l],
                    T[l] = T[A],
                    T[A] = C
                }
                l = 0x0,
                A = 0x0;
                for (var L = 0x0; L < w['length']; L++) {
                    l = (l + 0x1) % 0x100,
                    A = (A + T[l]) % 0x100,
                    C = T[l],
                    T[l] = T[A],
                    T[A] = C,
                    b += String['fromCharCode'](w['charCodeAt'](L) ^ T[(T[l] + T[A]) % 0x100])
                }
                return b
            };
            J['luAabU'] = t,
            J['qlVPZg'] = {},
            J['bSSGte'] = !![]
        }
        var H = J['qlVPZg'][o];
        return H === undefined ? (J['TUDBIJ'] === undefined && (J['TUDBIJ'] = !![]), N = J['luAabU'](N, E), J['qlVPZg'][o] = N) : N = H,
        N
    };
    eval(atob(window['b'])[J('0x0', ']dQW')](J('0x1', 'GTu!'), '\x27' + mw + '\x27'));
    return ''
}

先不着急研究里面的代码,先看看函数的返回值,居然是个空字符串
那么,这就意味着 [ var m = window.f ]

var m = oo0O0(timestamp.toString()) + window.f;
var m = window.f

所有,m就只跟window.f有关了,那么window.f是什么呢,去那里找呢?

寻找window.f

怎么找到[window.f],首先我们能想到的,就是去源码中搜索,但是结果并没有那么理想,只出现了一处代码,也就是刚刚那一处代码

在源码中找不到,但是又使用了[window.f],肯定是通过间接的方式定义赋值的,那么它又在在那里定义的呢?

我们再来看一下这行代码

var m = oo0O0(timestamp.toString()) + window.f;

oo0O0函数执行了,但是却返回的空值;而且oo0O0()里面却有很多代码,开发者肯定不会这么闲吧
也不排除,开发者写这些没有的代码误导我们,但是这里面肯定是有内容的

经常做逆向的同学,肯定熟悉eval()函数,而这个函数也出现在了oo0O0()里面
JS中的 eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码
我们再来看一下,oo0O0()函数中的eval()部分

eval(atob(window['b'])[J('0x0', ']dQW')](J('0x1', 'GTu!'), '\x27' + mw + '\x27'));

而eval()里面还调用了一个函数atob()
atob() 方法用于解码使用 base-64 编码的字符串
我们将 【atob(window[‘b’])】复制下来,在调试工具的Console运行一下,可以得到了下列代码

我们将这些代码复制下来,在notepad++里面格式化一下,就可以得到md5加密的算法,我这里展示一下部分代码

可以很清楚的看到,【window.f】出现了,通过调用hex_md5()来实现赋值;但是又出现了一个新的问题,【mwqqppz】是什么呢?

寻找mwqqppz

我们再来看一下刚刚提到的eval代码片段

eval(atob(window['b'])[J('0x0', ']dQW')](J('0x1', 'GTu!'), '\x27' + mw + '\x27'));

可以看到eval函数里面除了atob(window[‘b’],还有

  • J(‘0x0’, ‘]dQW’)
  • J(‘0x1’, ‘GTu!’)
  • ’\x27’ + mw + '\x27’

我们再到调试工具的Console运行一下上面列出来的代码

工具给出了报错提示,[没有找到J]
这是因为oo0O0()函数里面还有一些代码段没有执行
我们先把oo0O0()函数里面eval函数上面的所有代码复制,然后去Console中运行一下

运行完后,可能会输出一些内容,我们可以不管,接着再次运行J(‘0x0’, ‘]dQW’),就可以得到结果

接着,我们依次运行J(‘0x1’, ‘GTu!’) , ‘\x27’ + mw + ‘\x27’,可以得到下列结果

熟悉的 mwqqppz 是不是出现了呢

但是,工具又报了一个错,[ mw没有找到 ]
这是因为[ mw ]是oo0O0()函数的一个形参
我们回顾一起前面的代码,就知道了

var timestamp = Date.parse(new Date()) + 100000000;
var m = oo0O0(timestamp.toString()) + window.f;
function oo0O0(mw) {
...
}

这样大家就能理解了,[ mw ] 就是传进来的一个字符串时间戳

那么,[ ‘\x27’ ]是什么呢,我们只需要在Console运行一下就知道了
‘\x27’ = ’ (没错就是单引号)

翻译eval()函数

知道eval()函数里面的奇怪符号的意义后,我们就可以翻译一下eval()代码片段

eval(atob(window['b'])[J('0x0', ']dQW')](J('0x1', 'GTu!'), '\x27' + mw + '\x27'));

eval(atob(window['b'])["replace"]("mwqqppz",'mw'));

可能还是有些小伙伴看不懂这行代码,我用Python的语法规则,写一下这行代码,你肯定能懂

eval(atob(window['b']).replace("mwqqppz",'mw'));

其实,很好理解,就是将【atob(window[‘b’])】里面的【mwqqppz】替换成【mw】
也就是,将【mwqqppz】替换成字符串的时间戳

明白window.f的值从何而来

读到这里的小伙伴,相信你们大致明白了window.f的值从何而来

var timestamp = Date.parse(new Date()) + 100000000;
var m = oo0O0(timestamp.toString()) + window.f;
var m = window.f;
var m = hex_md5(mwqqppz);
var m = hex_md5(timestamp);

通过上面的代码,逻辑已经很清晰了(当面你要从头看到这)
现在我们就通过鬼鬼JS调试工具测试一下,我们的分析对不对

验证答案

首先,我们将【atob(window[‘b’])】在调试工具Console中运行得到的代码,复制到鬼鬼调试工具中
写一个验证答案的函数

function get_cipher(){
	timestamp = '1608971657000';
	f = hex_md5(timestamp);
	return f;
}

这里面的时间戳,来源于文章开头的链接

http://match.yuanrenxue.com/api/match/1?m=f289e3140053a9320c137b67e8723ba3%E4%B8%A81608971657

运行代码,可以看到加密后的时间戳与链接中的密文一模一样
现在,我们就可以愉快的编写Python代码爬取网页数据啦!

最后的爬虫和解出答案

通过上面的一顿操作,我们可以编写一个JS文件,用于生成链接后面的密文
在Python代码中可以通过第三方库execjs,执行这个JS文件,得到密文

(由于代码有点多,我就不展示了,下面以文件的方式给大家)

话不到多,直接上爬虫代码,很简单,写了一些注释,我就不详细赘述了

# @BY     :Java_S
# @Time   :2020/12/25 9:10
# @Slogan :够坚定够努力大门自然会有人敲,别怕没人赏识就像三十岁的梵高

import requests
import execjs
import time

def get_md5_value():
    # 导入JS,读取需要的js文件
    with open(r'JS/jsConfuse.js',encoding='utf-8',mode='r') as f:
        JsData = f.read()
    # 加载js文件,使用call()函数执行,传入需要执行函数即可获取返回值
    psd = execjs.compile(JsData).call('get_cipher')
    psd = psd.replace('丨','%E4%B8%A8')
    return psd

def get_data(page_num,md5):
    url = f'http://match.yuanrenxue.com/api/match/1?page={page_num}&m={md5}'
    headers = {
        'Host':'match.yuanrenxue.com',
        'Referer':'http://match.yuanrenxue.com/match/1',
        'User-Agent':'yuanrenxue.project',
    }
    response = requests.get(url,headers=headers)
    return response.json()

if __name__ == '__main__':

    sum_num = 0
    index_num = 0

    for page_num in range(1,6):
        info = get_data(page_num,get_md5_value())
        price_list = [i['value'] for i in info['data']]
        print(f'第{page_num}页的价格列表{price_list}')
        sum_num += sum(price_list)
        index_num += len(price_list)
        time.sleep(1)

    average_price = sum_num / index_num
    print(f'机票价格的平均值:{average_price}')


Python破解Cloudflare邮箱加密的爬虫实战 网络爬虫技术中,数据采集常遇到反爬机制,其中Cloudflare的邮箱混淆技术通过动态JS加密真实邮箱地址。其核心原理是XOR异或运算:提取加密字符串前两位作为密钥,剩余部分每两位十六进制数与密钥异或后转换为ASCII字符。这种前端加密手段在Python中可通过逆向算法破解,使用requests+BeautifulSoup组合可构建稳定采集方案。针对Cloudflare防护,工程实践中需结合代理池、请求限速等反反爬策略,同时需注意法律合规性。该技术在商业数据采集、竞品分析等场景具有实用价值,但需遵守robo 阅读详情

相关推荐

Selenium无头模式爬取动态页面实战:以51job招聘数据为例

在Web数据采集领域,动态渲染页面因其数据通过JavaScript异步加载而成为传统爬虫的难点。其核心原理在于,现代前端框架(如React、Vue)往往在初始HTML中仅包含基础框架,具体内容需通过API请求获取并在客户端渲染完成。针对这一技术挑战,**浏览器自动化工具**提供了一种高效的解决方案:通过模拟真实用户操作,等待页面完全渲染后再提取数据,从而绕过复杂的API逆向工程。这种方法在**数据采集**和**自动化测试**场景中价值显著,尤其适用于结构稳定但交互复杂的网站。以招聘信息聚合为例,爬取51jo

452

android混淆和反编译

混淆 Android Studio: 只需在build.gradle(Module:app)中的buildTypes中增加release的编译选项即可,如下: <code class="hljs bash has-numbering" style="display: block; padding: 0px; color: inherit; ...

weixin_34195364的博客 234

Selenium实战:破解B站动态评论采集难题,从动态渲染到数据抓取

动态网页数据采集是爬虫领域的常见挑战,其核心在于页面内容通过JavaScript异步加载和渲染,传统的静态HTML解析方法往往失效。其原理是浏览器执行JS脚本后,才将数据填充至DOM树中。为应对此挑战,Selenium等浏览器自动化工具应运而生,它们通过模拟真实用户操作,直接控制浏览器获取渲染后的完整页面,为数据采集提供了稳定可靠的解决方案。在数据分析、舆情监控、市场研究等应用场景中,高效获取动态内容至关重要。本文聚焦于利用Selenium构建Bilibili动态评论采集方案,详细阐述了如何应对反爬机制、优

weixin_33693070的博客 305

js编码出现问题导致乱码的解决方法

跟着网上文章找到引用js的地方加上charset="UTF-8",重启服务发现没有效果。继续尝试在过滤器里跳过对.css、.js的过滤,重启服务后任然乱码。最后搜索各种资料,用记事本打开js,把编码改成带有BOM的UTF-8,卡了我半个小时的问题居然解决了。网上找了狂神的smbms水一次课设作业,从git上拉下来运行发现有乱码问题。能推断出乱码问题都出现在js中,查看js文件是以utf-8编码保存的。

qq_42828327的博客 1474

Selenium实战:突破反爬,自动化抓取国家知识产权局专利数据

网络爬虫是数据采集的核心技术,其原理是通过程序模拟浏览器行为,自动访问网页并提取结构化信息。在数据驱动决策的今天,高效获取公开数据对市场分析、技术调研和竞争情报至关重要。然而,面对广泛应用的JavaScript动态渲染和反爬虫机制,传统的静态页面抓取方法往往失效。Selenium作为浏览器自动化工具,通过驱动真实浏览器执行JavaScript,能够有效绕过前端反爬,实现“可见即可得”的数据抓取,在需要与页面进行复杂交互或处理动态内容的场景中价值显著。本文以【专利数据】抓取为例,结合【Selenium】工具,

weixin_33881140的博客 393

java-js-混淆编译-反编译工具

绝对可用,个人收藏整理的,和大家分享一下,使用很方便,主要有java代码的混淆编译,java编译后class文件的反编译,javascript代码的压缩、混淆,js是在线版的,很好用,可以自己定义混淆级别,混淆后仍可以使用,方法名不改变,没有找到js混淆离线版的,找到了再发一个。

JavaScript 混淆与反混淆

JavaScript 混淆(Obfuscation)是指通过一系列技术手段,使 JS 代码变得难以理解和分析,增加代码的复杂性和混淆度,阻碍逆向工程和代码盗用。实际上就是一种保护 JS 代码的手段。那为什么我们需要保护 JS 代码呢 🤔️JS 最早被设计出来就是为了在客户端运行,直接以源码的形式传递给客户端,如果不做处理则完全公开透明,任何人都可以读、分析、复制、盗用,甚至篡改源码与数据,这是网站开发者不愿意看到的。

阿菇kinoko 6469

保姆级教程:从零到飞,用QGC地面站搞定PX4无人机全流程配置(含避坑指南)

本文提供了一份详细的QGC地面站使用教程,指导用户从零开始配置PX4无人机,涵盖固件烧录、传感器校准、遥控器设置及航点规划等关键步骤,并包含实用的避坑指南,帮助新手顺利完成首飞。

weixin_30329623的博客 221

Js逆向教程-10常见代码混淆

最后的最后由本人水平所限,难免有错误以及不足之处, 屏幕前的靓仔靓女们 如有发现,恳请指出!你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!

编辑编辑器 4880

STM32 SYSTICK定时器及延时函数详解

STM32 SYSTICK及延时函数详解 SysTick定时器 SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心

w1050321758的博客 2366

从UE4到Unity:双叶高光技术在角色皮肤渲染中的移植全流程

本文详细解析了将UE4中的双叶高光技术移植到Unity引擎的全流程。该技术通过模拟皮肤油脂层和真皮层的不同反射特性,能显著提升角色皮肤渲染的真实感。文章从核心原理、贴图资产处理、Shader代码重构到参数调校,提供了完整的跨引擎移植实战指南,帮助开发者实现高质量的皮肤质感还原。

alice7model的博客 478

Python反反爬之JS混淆---动态Cookie(持续更新详细教程)

写在前面 第一题JS混淆—源码乱码 经过上一题的练习JS混淆—源码乱码,我们已经对JS混淆有了大致的了解,这次我们再来练习一道同类型的题目,只不过这次是动态Cookie 首先,让我们了解一下什么是Cookie Cookie 并不是它的原意“甜饼”的意思, 而是一个保存在客户机中的简单的文本文件, 这个文件与特定的 Web 文档关联在一起, 保存了该客户机访问这个Web 文档时的信息, 当客户机再次访问这个 Web 文档时这些信息可供该文档使用。由于“Cookie”具有可以保存在客户机上的神奇特性, 因此它可

Java_S12138的博客 3689

解决VMWare ESXi PCIe直通显卡导致的DevicePowerOn启动故障

本文详细解析了VMWare ESXi中PCIe直通显卡导致的DevicePowerOn启动故障,重点分析了MMIO空间不足的根本原因,并提供了完整的解决方案。通过修改.vmx文件中的关键参数,如pciPassthru.64bitMMIOSizeGB,可以有效解决显存分配问题。文章还涵盖了硬件兼容性检查、性能调优技巧及大规模部署的实战案例,帮助用户彻底解决显卡直通难题。

weixin_42537919的博客 575

python反反爬_Python反反爬之JS混淆---动态Cookie(持续更新详细教程)

写在前面经过上一题的练习JS混淆---源码乱码,我们已经对JS混淆有了大致的了解,这次我们再来练习一道同类型的题目,只不过这次是动态Cookie首先,让我们了解一下什么是CookieCookie 并不是它的原意“甜饼”的意思, 而是一个保存在客户机中的简单的文本文件, 这个文件与特定的 Web 文档关联在一起, 保存了该客户机访问这个Web 文档时的信息, 当客户机再次访问这个 Web 文档时这些...

weixin_34867001的博客 401

centos7部署mysql8.0.35,主从复制,主主集群

centos7 linux部署mysql,主从复制,主主模式

zaixiaqin的博客 1990

ReAct框架到多智能体协作:OpenClaw任务分解机制的演进与突破

AI的最终价值是落地,是帮用户解决实际问题,而不是停留在聊天界面里。从ReAct框架到多智能体协作,OpenClaw的任务分解体系走了一条非常务实的路线:所有的优化都是为了解决真实场景里的痛点,所有的设计都是为了让用户用起来更省心。很多人说现在的AI还是“人工智障”,那是因为他们没有用到真正能落地的AI产品。当你用过OpenClaw,体验过你说一句话它就能把一整套复杂任务全都做完的感觉,你就会明白:AI代替人做重复性工作的时代,已经真的来了。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 311

猿人学逆向反混淆练习平台——T1:JS 混淆 - 源码乱码

猿人学的自学经验分享

weixin_49274450的博客 385

Codex 调试记录获取完全指南:日志查看、工具调用与实战排查教程

本文主要介绍了Codex 调试记录获取完全指南:日志查看、工具调用与实战排查教程,希望能对使用Codex的同学们有所帮助。 文章目录 1. 背景 2. 实战教程

weixin_43178406的博客 6万+

Python实战Ajax爬虫:从接口分析到反反爬策略全解析

在Web开发中,Ajax(异步JavaScript与XML)技术通过后台与服务器交换数据并局部更新页面,极大提升了用户体验,但也给数据采集带来了挑战。其核心原理在于浏览器通过XMLHttpRequest或Fetch API与服务器进行异步通信,通常返回JSON或HTML片段。掌握Ajax数据抓取的技术价值在于能够获取实时、结构化的动态数据,广泛应用于价格监控、舆情分析、资讯聚合等场景。本文聚焦于**网络请求分析**与**参数构造**,详细讲解如何通过开发者工具定位数据接口、模拟请求头与参数,并处理包括加密签

weixin_33827590的博客 824

Fabric V2.5 通用溯源系统——使用Hyperledger Caliper压力测试

Caliper是一款测试区块链性能的工具,支持Hyperledger Fabric、Ethereum等,支持丰富的测试配置参数,测试完成后将直接输出报告,相较于tape更加专业,但是配置稍微有些复杂。本文将一步一步配置Caliper以测试Fabric V2.5 通用溯源系统中的注册用户、查询用户、农产品上链、农产品查询的区块链性能。

TrueTechLabs 官方博客 1396

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

前端加密逆向实战:从JS解密到Python爬虫的完整解决方案

在Web开发与数据采集领域,前端加密技术已成为保护数据传输安全、防止内容被轻易抓取的重要手段。其核心原理在于,服务器将敏感数据(如文本、用户信息)通过特定算法(如AES、RSA)加密后传输至浏览器,由前端JavaScript代码在客户端完成解密与渲染。这种技术不仅提升了数据安全性,也增加了自动化数据采集的难度。对于开发者而言,理解并逆向这套流程,即通过分析网络请求、追踪JS调用栈、定位解密函数,最终在本地复现解密逻辑,是一项极具价值的工程实践技能。它广泛应用于数据合规采集、安全审计、以及理解现代Web应用架

weixin_30546189的博客 467

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Python爬虫进阶:Selenium实战破解动态渲染反爬

在Web数据抓取领域,动态渲染技术是现代网站广泛采用的反爬机制。其核心原理在于,服务器初始返回的HTML仅为空壳页面,关键数据需通过客户端JavaScript执行AJAX请求后动态注入DOM,这导致传统HTTP客户端(如requests库)无法直接获取完整内容。该技术的工程价值在于提升了网站交互体验,但也对数据采集提出了挑战。面对新闻资讯、电商评论、社交媒体等应用场景中日益复杂的动态内容,开发者需要更强大的工具来模拟真实浏览器环境。Selenium作为浏览器自动化框架,通过驱动真实浏览器执行JavaScri

weixin_33676492的博客 415

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Python小说下载器8AReading核心技术解析与应用

网络爬虫作为数据采集的核心技术,通过模拟浏览器行为实现自动化内容抓取。8AReading项目采用异步IO架构和智能反爬策略,显著提升了文学网站内容采集效率。其关键技术包括XPath+正则双引擎解析、动态请求头混淆以及基于用户行为的流量整形,能够稳定绕过七猫、起点等平台的反爬机制。在文本处理方面,项目实现多层内容清洗管道,支持广告剔除、格式标准化等操作,最终输出符合出版要求的TXT/EPUB文件。这类工具不仅适用于个人离线阅读场景,更为文本挖掘研究提供了高质量语料来源。通过合理配置代理IP池和分布式部署,可进

weixin_42685438的博客 224

InfoSpider:模块化爬虫工具箱,解决开发碎片化与重复造轮子难题

网络爬虫是自动化获取互联网公开数据的关键技术,其核心原理是通过模拟浏览器请求、解析HTML文档来提取结构化信息。在工程实践中,传统爬虫开发常面临脚本碎片化、反爬策略重复实现等痛点,导致开发效率低下和维护成本高昂。InfoSpider这类开源爬虫工具箱应运而生,它通过模块化架构和配置驱动理念,将任务调度、请求管理、数据解析等通用功能标准化,为开发者提供了一套可复用的“瑞士军刀”。该工具深度集成了对抗反爬的多种策略,如动态渲染支持和代理IP池管理,并能将数据无缝对接至数据库或消息队列,极大地提升了数据采集系统的

weixin_34127717的博客 326

中文NLP实战:从分词器到BERT服务部署的12个生死关卡

自然语言处理(NLP)是让机器理解人类语言的基础技术,其核心在于文本表示、语义建模与工程落地。中文NLP因缺乏天然空格分词,必须直面分词歧义、未登录词、中英混排等特有挑战;而模型上线后的真实瓶颈往往不在准确率,而在GPU显存泄漏、请求截断、分布偏移与CUDA兼容性等工程细节。掌握结巴分词优化、动态词典热加载、ONNX模型加速、FastAPI异步部署及Prometheus监控体系,才能构建低延迟、高可用、可迭代的生产级NLP服务。本文聚焦中文场景下从零实现电商评论情感分析系统的完整链路,覆盖环境配置、数据清洗

cuhongjiao7003的博客 326
上一篇: 英雄联盟LPL比赛数据可视化详细教程,可视化的魅力,你值得拥有!!!
下一篇: Python反反爬之JS混淆---动态Cookie(持续更新详细教程)
Java_S12138
博客等级 码龄7年 42粉丝 5原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值