代理IP的用途
当爬取网站时由于是程序爬取,往往访问网站的频率会很高,很多网站对于这样的情况会做IP限制,高频访问的IP在一段时间无法再获取服务器响应,例如:
代理IP就是为了解决这种情况,遇到这种情况时使用代理IP继续爬取网站数据。
代理IP来源
下面几个网址会放出一些免费的代理IP:
- http://www.data5u.com/
- http://www.data5u.com/free/gngn/index.shtml
- http://www.data5u.com/free/gwgn/index.shtml
爬取代理IP
通过代码自动爬取代理IP,使用Java编写。
我使用这个库来获取网页数据:
<dependency>
<groupId>net.dongliu</groupId>
<artifactId>requests</artifactId>
<version>4.18.2</version>
</dependency>
使用这个库解析网页数据:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
这两个库如何使用在这里不赘述。
通过分析,访问http://www.data5u.com/
链接即可获取代理数据:
通过上文中提到的库将页面数据爬取并将代理数据解析出来。
端口号解密
当我们将代理数据解析出来后,发现解析出来的端口号与浏览器网页上显示的端口号不同,网页上显示的IP+端口号可以爬取数据,而我们通过程序解析出来的却不可爬取。这说明通过程序解析出来的端口号是不对的。
经过分析,浏览器访问时服务端的返回的端口号经过了加密,经过解密显示在网页上。
解密的JS:
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;}('1M(17(p,a,c,k,e,r){e=17(c){18(c<a?\'\':e(1w(c/a)))+((c=c%a)>1s?1b.1r(c+1q):c.1v(1u))};19(!\'\'.1a(/^/,1b)){1c(c--)r[e(c)]=k[c]||e(c);k=[17(e){18 r[e]}];e=17(){18\'\\\\w+\'};c=1};1c(c--)19(k[c])p=p.1a(1t 1y(\'\\\\b\'+e(c)+\'\\\\b\',\'g\'),k[c]);18 p}(\'i h$=[\\\'\\\\E\\\\n\\\\x\\\\s\\\\j\\\',"\\\\l\\\\m\\\\v\\\\o","\\\\o\\\\j\\\\G\\\\p","\\\\r\\\\q\\\\H\\\\l\\\\I\\\\J\\\\K",\\\'\\\\M\\\',"\\\\m\\\\j\\\\j\\\\s",\\\'\\\\v\\\\p\\\\m\\\\k\\\\k\\\',"\\\\k\\\\n\\\\p\\\\r\\\\j","\\\\O","","\\\\p\\\\l\\\\q\\\\Q\\\\j\\\\o","\\\\n\\\\R\\\\k\\\\o",\\\'\\\\S\\\\T\\\\V\\\\z\\\\A\\\\B\\\\C\\\\D\\\\u\\\\F\\\',"\\\\n\\\\m\\\\s\\\\k\\\\l\\\\u\\\\q\\\\j","\\\\16\\\\x\\\\r\\\\q",\\\'\\\'];$(y(){$(h$[0])[h$[1]](y(){i a=$(t)[h$[2]]();L(a[h$[3]](h$[4])!=-w){N};i b=$(t)[h$[5]](h$[6]);P{b=(b[h$[7]](h$[8]))[w];i c=b[h$[7]](h$[9]);i d=c[h$[10]];i f=[];U(i g=W;g<d;g++){f[h$[11]](h$[12][h$[3]](c[g]))};$(t)[h$[2]](X[h$[13]](f[h$[14]](h$[15]))>>Y)}Z(e){}})})\',1A,1B,\'|||||||||||||||||1C|1x|1z|1p|1h|1i|1d|1e|1f|1m|1n|1o|1g|1k|1l|1j|1W|17|1X|1Y|1V|1S|1T|1U|1Z|23|25|24|20|21|19|22|18|1R|1H|1I|1J|1G|1D|1E|1F|1O|1P|1Q|1N|||||||1K\'.1L(\'|\'),0,{}))',62,130,'|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||function|return|if|replace|String|while|x70|x68|x6c|this|x65|x61|0x1|x49|x63|x6e|x69|x72|x73|29|fromCharCode|35|new|36|toString|parseInt|var|RegExp|x74|62|69|_|x42|for|x43|x41|try|x67|x75|x6a|split|eval|catch|0x0|window|0x3|x20|x47|x48|x2e|x46|x6f|x44|x45|x5a|x4f|x66|x2a|x6d|x78|x64'.split('|'),0,{}))
这类加密的破解思路是:见eval就去掉。
去掉eval后,将JS放到Console中执行一下,发现又解析出eval包裹的代码:
继续去掉eval:
格式化后的代码:
var _$ = ['\x2e\x70\x6f\x72\x74', "\x65\x61\x63\x68", "\x68\x74\x6d\x6c", "\x69\x6e\x64\x65\x78\x4f\x66", '\x2a', "\x61\x74\x74\x72", '\x63\x6c\x61\x73\x73', "\x73\x70\x6c\x69\x74", "\x20", "", "\x6c\x65\x6e\x67\x74\x68", "\x70\x75\x73\x68", '\x41\x42\x43\x44\x45\x46\x47\x48\x49\x5a', "\x70\x61\x72\x73\x65\x49\x6e\x74", "\x6a\x6f\x69\x6e", ''];
$(function () {
$(_$[0])[_$[1]](function () {
var a = $(this)[_$[2]]();
if (a[_$[3]](_$[4]) != -0x1) {
return
}
;var b = $(this)[_$[5]](_$[6]);
try {
b = (b[_$[7]](_$[8]))[0x1];
var c = b[_$[7]](_$[9]);
var d = c[_$[10]];
var f = [];
for (var g = 0x0; g < d; g++) {
f[_$[11]](_$[12][_$[3]](c[g]))
}
;$(this)[_$[2]](window[_$[13]](f[_$[14]](_$[15])) >> 0x3)
} catch (e) {
}
})
})
上面代码中_$
变量是一个数组,这个数组中的内容难以理解,经过分析发现数组中的十六进制数字是ASCII码。例如,'\x2e\x70\x6f\x72\x74'
翻译过来就是.port
。