【aqistudy】Python爬虫aqistudy空气质量平台js爬虫(21-08代码已更新)

一、“有多优秀” ,“一枝独秀”

1、它在这里:AirHistory
2、环境:Python3.8、nodejs

二、我知道这将是我的一生热爱,我将为此一直奋斗。

该站点前端禁用了右击,直接通过工具栏进入开发者模式。
在这里插入图片描述
发现网站前端写了debug,在工具栏退出debug模式,进入正题。
在这里插入图片描述
找到加密解密js文件

eval(function(p, a, c, k, e, d) {
    e = function(c) {
        return (c < a ? '' : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36))
    }
    ;
    if (!''.replace(/^/, String)) {
        while (c--) {
            d[e(c)] = k[c] || e(c)
        }
        k = [function(e) {
            return d[e]
        }
        ];
        e = function() {
            return '\\w+'
        }
        ;
        c = 1
    }
    ;while (c--) {
        if (k[c]) {
            p = p.replace(new RegExp('\\b' + e(c) + '\\b','g'), k[c])
        }
    }
    return p
}('f 1c="2b";f 1e="1N";f 1M="1L";f 1K="1J";f 19="1I";f 1a="1H";f 1p="1G";f 1h="1F";f V=\'1E==\';f 10=\'1D\';2 x={j:6(4){2 b=r 17();g b.1C(4)},k:6(4){2 b=r 17();g b.1B(4)}};2 F={j:6(4,7,i){2 a=(3.w(7).h()).u(0,16);2 c=(3.w(i).h()).u(24,8);a=3.q.p.n(a);c=3.q.p.n(c);2 e=3.F.j(4,a,{i:c,t:3.t.I,M:3.L.J});g e.h()},k:6(4,7,i){2 a=(3.w(7).h()).u(0,16);2 c=(3.w(i).h()).u(24,8);a=3.q.p.n(a);c=3.q.p.n(c);2 e=3.F.k(4,a,{i:c,t:3.t.I,M:3.L.J});g e.h(3.q.p)}};2 B={j:6(4,7,i){2 a=(3.w(7).h()).u(16,16);2 c=(3.w(i).h()).u(0,16);a=3.q.p.n(a);c=3.q.p.n(c);2 e=3.B.j(4,a,{i:c,t:3.t.I,M:3.L.J});g e.h()},k:6(4,7,i){2 a=(3.w(7).h()).u(16,16);2 c=(3.w(i).h()).u(0,16);a=3.q.p.n(a);c=3.q.p.n(c);2 e=3.B.k(4,a,{i:c,t:3.t.I,M:3.L.J});g e.h(3.q.p)}};2 O={1m:6(m,1b){2 4=A.K(1b);4=x.j(4);4=B.j(4,V,10);21{G.15(m,4)}1P(18){l(18.m===\'27\'){1j.1t(\'28 29 2a\');G.25();G.15(m,4)}}},2c:6(m){g G.1d(m)},13:6(m){2 4=G.1d(m);2 e=R;l(4){4=B.k(4,V,10);4=x.k(4);e=A.n(4)}g e},2e:6(m){G.23(m)}};6 1l(7,y){l(22 y===\'20\'){y=0}2 d=F.j(7);d=x.j(7);2 9=O.13(7);l(9){f H=9.H;f 11=r s().X();l(r s().N()>=0&&r s().N()<5&&y>1){y=1}l(11-(y*12*12*1W)>H){9=R}l(r s().N()>=5&&r s(H).14()!==r s().14()&&y===24){9=R}}g 9}6 T(C){2 D={};1f.1q(C).1s().1r(6(7){D[7]=C[7]});g D}6 1o(9){9=x.k(9);9=F.k(9,19,1a);9=B.k(9,1c,1e);9=x.k(9);g 9}2 1n=(6(){6 T(C){2 D={};1f.1q(C).1s().1r(6(7){D[7]=C[7]});g D}g 6(E,o){2 P=\'1S\';2 U=\'1T\';2 S=r s().X();2 v={1U:P,1V:E,1X:S,1Y:U,1Z:o,1R:1k(P+E+S+U+A.K(T(o)))};v=x.j(A.K(v));v=F.j(v,1p,1h);g v}})();6 2d(E,Y,W,Z){f Q=1k(E+A.K(Y));f z=1l(Q,Z);l(!z){2 v=1n(E,Y);$.26({1Q:\'1A/1O.1x\',9:{1w:v},1v:"1u",1g:6(z){z=1o(z);o=A.n(z);l(o.1g){l(Z>0){o.e.H=r s().X();O.1m(Q,o.e)}W(o.e)}1i{1j.1t(o.1z,o.1y)}}})}1i{W(z)}}', 62, 139, '||var|CryptoJS|text||function|key||data|secretkey||secretiv||result|const|return|toString|iv|encrypt|decrypt|if|name|parse|oPKQj9|Utf8|enc|new|Date|mode|substr|pqq15DU|MD5|BASE64|period|dQgJN|JSON|AES|obj|newObject|mAfre3O9d|DES|localStorage|time|CBC|Pkcs7|stringify|pad|padding|getHours|localStorageUtil|a3JB|kHL5|null|toTJ9XN|osvnuOOjUj|cN0OK|aes_local_key|c9lW53jNA|getTime|oywGO2usiQ|prR3ENZ|aes_local_iv|current|60|getValue|getDate|setItem||Base64|oException|dskhXKbQZi19|dsizKZaAJQLb|value|askhyZESMiTa|getItem|asirwND73kx2|Object|success|dciZ7hxfi8SC|else|console|hex_md5|gHXWDFQIQgkKkVCY|save|p3cnrDIfVp|dSp17P6wE1CFXC6D|dckvUcTa9vft|keys|map|sort|log|post|type|hmebd5PRa|php|errmsg|errcode|api|decode|encode|emhlbnFpcGFsbWl2|emhlbnFpcGFsbWtleQ|ph4oq7nooy3NnkRE|oz2zCOI3ow8YN1gJ|xH8I8jYDZY33QzJJ|hKVw3rIJQJlHirdh|fZsaKttlA5A8GX7A|aciaallf8z0Q|dKyBVluERbCaupYE|ackQjV8pRLFF|bENVgtN9llqTCWPS|historyapi|catch|url|secret|94db838b2ef213aaf72dac81f2073805|WEB|appId|method|1000|timestamp|clienttype|object|undefined|try|typeof|removeItem||clear|ajax|QuotaExceededError|Local|limit|exceeded|aMq0Vk2QThOJ1qsK|check|srXY9Y1XQRaq7GPCj|remove'.split('|'), 0, {}))

上述代码在运行时会生成一段完整的js加密程序,如下:

const askhyZESMiTa = "aMq0Vk2QThOJ1qsK";
const asirwND73kx2 = "bENVgtN9llqTCWPS";
const ackQjV8pRLFF = "dKyBVluERbCaupYE";
const aciaallf8z0Q = "fZsaKttlA5A8GX7A";
const dskhXKbQZi19 = "hKVw3rIJQJlHirdh";
const dsizKZaAJQLb = "xH8I8jYDZY33QzJJ";
const dckvUcTa9vft = "oz2zCOI3ow8YN1gJ";
const dciZ7hxfi8SC = "ph4oq7nooy3NnkRE";
const aes_local_key = 'emhlbnFpcGFsbWtleQ==';
const aes_local_iv = 'emhlbnFpcGFsbWl2';
var BASE64 = {
    encrypt: function (text) {
        var b = new Base64();
        return b.encode(text)
    },
    decrypt: function (text) {
        var b = new Base64();
        return b.decode(text)
    }
};
var DES = {
    encrypt: function (text, key, iv) {
        var secretkey = (CryptoJS.MD5(key).toString()).substr(0, 16);
        var secretiv = (CryptoJS.MD5(iv).toString()).substr(24, 8);
        secretkey = CryptoJS.enc.Utf8.parse(secretkey);
        secretiv = CryptoJS.enc.Utf8.parse(secretiv);
        var result = CryptoJS.DES.encrypt(text, secretkey, {
            iv: secretiv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return result.toString()
    },
    decrypt: function (text, key, iv) {
        var secretkey = (CryptoJS.MD5(key).toString()).substr(0, 16);
        var secretiv = (CryptoJS.MD5(iv).toString()).substr(24, 8);
        secretkey = CryptoJS.enc.Utf8.parse(secretkey);
        secretiv = CryptoJS.enc.Utf8.parse(secretiv);
        var result = CryptoJS.DES.decrypt(text, secretkey, {
            iv: secretiv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return result.toString(CryptoJS.enc.Utf8)
    }
};
var AES = {
    encrypt: function (text, key, iv) {
        var secretkey = (CryptoJS.MD5(key).toString()).substr(16, 16);
        var secretiv = (CryptoJS.MD5(iv).toString()).substr(0, 16);
        secretkey = CryptoJS.enc.Utf8.parse(secretkey);
        secretiv = CryptoJS.enc.Utf8.parse(secretiv);
        var result = CryptoJS.AES.encrypt(text, secretkey, {
            iv: secretiv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return result.toString()
    },
    decrypt: function (text, key, iv) {
        var secretkey = (CryptoJS.MD5(key).toString()).substr(16, 16);
        var secretiv = (CryptoJS.MD5(iv).toString()).substr(0, 16);
        secretkey = CryptoJS.enc.Utf8.parse(secretkey);
        secretiv = CryptoJS.enc.Utf8.parse(secretiv);
        var result = CryptoJS.AES.decrypt(text, secretkey, {
            iv: secretiv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return result.toString(CryptoJS.enc.Utf8)
    }
};
var localStorageUtil = {
    save: function (name, value) {
        var text = JSON.stringify(value);
        text = BASE64.encrypt(text);
        text = AES.encrypt(text, aes_local_key, aes_local_iv);
        try {
            localStorage.setItem(name, text)
        } catch (oException) {
            if (oException.name === 'QuotaExceededError') {
                console.log('Local limit exceeded');
                localStorage.clear();
                localStorage.setItem(name, text)
            }
        }
    },
    check: function (name) {
        return localStorage.getItem(name)
    },
    getValue: function (name) {
        var text = localStorage.getItem(name);
        var result = null;
        if (text) {
            text = AES.decrypt(text, aes_local_key, aes_local_iv);
            text = BASE64.decrypt(text);
            result = JSON.parse(text)
        }
        return result
    },
    remove: function (name) {
        localStorage.removeItem(name)
    }
};

function gHXWDFQIQgkKkVCY(key, period) {
    if (typeof period === 'undefined') {
        period = 0
    }
    var d = DES.encrypt(key);
    d = BASE64.encrypt(key);
    var data = localStorageUtil.getValue(key);
    if (data) {
        const time = data.time;
        const current = new Date().getTime();
        if (new Date().getHours() >= 0 && new Date().getHours() < 5 && period > 1) {
            period = 1
        }
        if (current - (period * 60 * 60 * 1000) > time) {
            data = null
        }
        if (new Date().getHours() >= 5 && new Date(time).getDate() !== new Date().getDate() && period === 24) {
            data = null
        }
    }
    return data
}

function osvnuOOjUj(obj) {
    var newObject = {};
    Object.keys(obj).sort().map(function (key) {
        newObject[key] = obj[key]
    });
    return newObject
}

function dSp17P6wE1CFXC6D(data) {
    data = BASE64.decrypt(data);
    data = DES.decrypt(data, dskhXKbQZi19, dsizKZaAJQLb);
    data = AES.decrypt(data, askhyZESMiTa, asirwND73kx2);
    data = BASE64.decrypt(data);
    return data
}

var p3cnrDIfVp = (function () {
    function osvnuOOjUj(obj) {
        var newObject = {};
        Object.keys(obj).sort().map(function (key) {
            newObject[key] = obj[key]
        });
        return newObject
    }

    return function (mAfre3O9d, oPKQj9) {
        var a3JB = '94db838b2ef213aaf72dac81f2073805';
        var cN0OK = 'WEB';
        var toTJ9XN = new Date().getTime();
        var pqq15DU = {
            appId: a3JB,
            method: mAfre3O9d,
            timestamp: toTJ9XN,
            clienttype: cN0OK,
            object: oPKQj9,
            secret: hex_md5(a3JB + mAfre3O9d + toTJ9XN + cN0OK + JSON.stringify(osvnuOOjUj(oPKQj9)))
        };
        pqq15DU = BASE64.encrypt(JSON.stringify(pqq15DU));
        pqq15DU = DES.encrypt(pqq15DU, dckvUcTa9vft, dciZ7hxfi8SC);
        return pqq15DU
    }
})();

function srXY9Y1XQRaq7GPCj(mAfre3O9d, oywGO2usiQ, c9lW53jNA, prR3ENZ) {
    const kHL5 = hex_md5(mAfre3O9d + JSON.stringify(oywGO2usiQ));
    const dQgJN = gHXWDFQIQgkKkVCY(kHL5, prR3ENZ);
    if (!dQgJN) {
        var pqq15DU = p3cnrDIfVp(mAfre3O9d, oywGO2usiQ);
        $.ajax({
            url: 'api/historyapi.php',
            data: {
                hmebd5PRa: pqq15DU
            },
            type: "post",
            success: function (dQgJN) {
                dQgJN = dSp17P6wE1CFXC6D(dQgJN);
                oPKQj9 = JSON.parse(dQgJN);
                if (oPKQj9.success) {
                    if (prR3ENZ > 0) {
                        oPKQj9.result.time = new Date().getTime();
                        localStorageUtil.save(kHL5, oPKQj9.result)
                    }
                    c9lW53jNA(oPKQj9.result)
                } else {
                    console.log(oPKQj9.errcode, oPKQj9.errmsg)
                }
            }
        })
    } else {
        c9lW53jNA(dQgJN)
    }
}

经过调试p3cnrDIfVp为加密程序。dSp17P6wE1CFXC6D为解密程序

三、你并不是征服了这片土地,你只是战胜了你的对手。

完整代码:它在这里


  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
爬取空气质量检测网的部分城市的历年每天质量数据 思路----------------------------------------- 从某城市的空气质量网页获取某市每月的链接,再爬取每个月的表格数据。连云港市:https://www.aqistudy.cn/historydata/daydata.php?city=连云港 连云港2014年5月的空气质量:https://www.aqistudy.cn/historydata/daydata.php?city=连云港&month=2014-05 遇到的问题----------------------------------------- 获取的网页中的表格数据隐藏,尝试requests无法获取。判断可能是动态加载的网页 尝试----------------------------------------- 1. 通过XHR,js查找隐藏数据的加载网页,没有找到。 2. 使用phantomjs.get() result=pd.read_html ,可以获得隐藏的表格数据,但是并不稳定,只是偶尔出现加载的表格数据,无法大规模的获取 解决方法----------------------------------------- 查找资料得知这个网站的表格数据在Console里的items中, 使用selenium的webdriver.firefox(),driver.execute_script("return items") 数据可获得。 仍遇到的问题:----------------------------------------- 爬取一个网页可获得数据,但是连续的获取网页,会出现两个错误。 1.Message: ReferenceError: items is not defined 2.connection refused 解决方法: 1.connection refused问题,可能是网页开太多,使用driver.quit() 2. 如果 execute_script 还是出错,可尝试pd.read_html获取信息。之前用phantomjs获取的时候输出空的表格,可能由于加载不够,用 Waite直到table出现之后再获取网页 Element=wait.until(EC.element_to_be_clickable((By.XPATH,"/html/body/div[3]/div[1]/div[1]/table/tbody"))) 3.之后出现偶尔出现输出为空,使用循环,如果输出表格为空,再重新获取。 if len(result)>1: filename = str(month) + '.xls' result.to_excel('E:\python\案例程序\data\\' + filename) print('成功存入'+filename) driver.quit() else: driver.quit() return getdata(monthhref,month)
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值