zoukankan      html  css  js  c++  java
  • 无忧代理免费ip爬取(端口js加密)

    起因

    为了训练爬虫技能(其实主要还是js技能…),翻了可能有反爬的网站挨个摧残,现在轮到这个网站了:http://www.data5u.com/free/index.shtml

    解密过程

    打开网站,在免费ip的列表页查看元素选一个端口,发现表示端口的元素class属性上有可疑的东西(代理ip类网站的反爬总是这么没有创意…):

    image

    上面的“GEA”很像是密文存储的东西,怀疑端口号是页面加载完再用js计算出来填充上的,要证明的话也很简单,只需要对照下这个元素当前的值和刚下载下来的时候值是否一致,在控制台查看元素看到的是内存中元素的当前状态,查看页面源代码的才是页面被下载来那一刻的状态,右键-->查看网页源代码。搜索“49.236.220.14”,发现端口号果然不一样,页面被下载下来时是8916,现在显示的却是80.

    image 

    解密逻辑在这个js中:http://www.data5u.com/theme/data5u/javascript/pde.js?v=1.0,原始的js进行了压缩,使用之前写过的展开eval的方法进行eval展开并格式化(注意需要eval展开两次):

    var _$ = ['x2ex70x6fx72x74', "x65x61x63x68", "x68x74x6dx6c", "x69x6ex64x65x78x4fx66", 'x2a', "x61x74x74x72", 'x63x6cx61x73x73', "x73x70x6cx69x74", "x20", "", "x6cx65x6ex67x74x68", "x70x75x73x68", 'x41x42x43x44x45x46x47x48x49x5a', "x70x61x72x73x65x49x6ex74", "x6ax6fx69x6e", ''];
    $(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) {}
        })
    })

    上面这段js仍然是不可读的,可以看到一些关键词被抽取出来放到了一个字典数组中,字典数组中的字面值还被十六进制编码了,所以接下来需要写点js将其转换为可读形式,下面是转换的代码:

    <html>
        <head></head>
        <body>
    <script type="text/code-template" id="functionBody">
            $(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) {}
            })
        })
    </script>
    <script type="text/javascript">
    
        var _$ = ['x2ex70x6fx72x74', "x65x61x63x68", "x68x74x6dx6c", "x69x6ex64x65x78x4fx66", 'x2a', "x61x74x74x72", 'x63x6cx61x73x73', "x73x70x6cx69x74", "x20", "", "x6cx65x6ex67x74x68", "x70x75x73x68", 'x41x42x43x44x45x46x47x48x49x5a', "x70x61x72x73x65x49x6ex74", "x6ax6fx69x6e", ''];            
        let functionBody = document.getElementById("functionBody").innerHTML;
        let readableFunctionBody = functionBody.replace(/_$[[0-9]+]/g, x =>  "'" + eval(x) + "'");
        document.write(readableFunctionBody);
    
    </script>
        </body>
    </html>

    转换并格式化:

    $(function() {
        $('.port')['each'](function() {
            var a = $(this)['html']();
            if (a['indexOf']('*') != -0x1) {
                return
            };
            var b = $(this)['attr']('class');
            try {
                b = (b['split'](' '))[0x1];
                var c = b['split']('');
                var d = c['length'];
                var f = [];
                for (var g = 0x0; g < d; g++) {
                    f['push']('ABCDEFGHIZ' ['indexOf'](c[g]))
                };
                $(this)['html'](window['parseInt'](f['join']('')) >> 0x3)
            } catch(e) {}
        })
    })

    可以看到解密逻辑已经很清晰了,就是把端口元素上第二个class(假定从1开始),也就是那个奇怪的字符串拿出来,然后在'ABCDEFGHIZ'中找其位置,最后把找到的位置坐标按顺序拼接并转为数字然后除以8,即得到最终的端口号,根据解密逻辑写出java代码:

    private static int decodePort(String rawContent) {
        String rawNum = Stream.of(rawContent.split(""))
            .map("ABCDEFGHIZ"::indexOf)
            .map(Object::toString)
            .collect(Collectors.joining());
        return Integer.parseInt(rawNum) >> 3;
    }

    一个简单的抓取demo:

    package org.cc11001100.t1;
    
    import javaslang.Tuple;
    import javaslang.Tuple2;
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.select.Elements;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.URL;
    import java.net.URLEncoder;
    import java.util.Collections;
    import java.util.List;
    import java.util.Objects;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    import static java.util.stream.Collectors.toList;
    
    /**
     * 这个网站的代理: http://www.data5u.com/free/index.shtml
     * 端口有加密
     *
     * @author CC11001100
     */
    public class Data5UProxyGrab {
    
        private static int decodePort(String rawContent) {
            String rawNum = Stream.of(rawContent.split(""))
                .map("ABCDEFGHIZ"::indexOf)
                .map(Object::toString)
                .collect(Collectors.joining());
            return Integer.parseInt(rawNum) >> 3;
        }
    
        private static List<Tuple2<String, Integer>> parse(String url) {
            try {
                Document document = Jsoup.parse(new URL(url), 3000);
                return document.select(".wlist ul li[style=text-align:center;] ul.l2")
                    .stream()
                    .map(elt -> {
                        String ip = elt.select("span").first().text();
                        Elements portElt = elt.select(".port");
                        if (!portElt.isEmpty() && !portElt.html().contains("*")) {
                            String[] ss = portElt.attr("class").split("\s+");
                            if (ss.length >= 2) {
                                return Tuple.of(ip, decodePort(ss[1]));
                            }
                        }
                        return null;
                    })
                    .filter(Objects::nonNull)
                    .collect(toList());
            } catch (IOException e) {
                e.printStackTrace();
            }
            return Collections.emptyList();
        }
    
        /**
         * 按照国家抓取
         */
        public static List<Tuple2<String, Integer>> grabByCountry() throws IOException {
            String url = "http://www.data5u.com/free/country/%s/index.html";
            return Jsoup.parse(new URL(String.format(url, urlEncode("中国"))), 3000)
                .select("#areaDist ul.bigr span")
                .stream()
                .map(elt -> elt.attr("title"))
                .flatMap(countryName -> parse(String.format(url, urlEncode(countryName))).stream())
                .distinct()
                .collect(toList());
        }
    
        private static String urlEncode(String raw) {
            try {
                return URLEncoder.encode(raw, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return "";
        }
    
        public static void main(String[] args) throws IOException {
            grabByCountry().forEach(System.out::println);
        }
    
    }
    

    更省力的方案

    上面都太麻烦了,只是为了锻炼一下js技能,其实观察一下发现这个网站的功能设计得很奇怪,比如ip列表提供的筛选功能,下面被圈起来的都是可以作为筛选条件的:

    image

    但是偏偏没有端口,鼠标移动到端口上点击是没有反应的,这是因为他要做端口加密啊,让你知道了端口不白做了,然而木用…

    下面是分别使用几种过滤条件时地址栏中显示的url:

    http://www.data5u.com/free/anoy/匿名/index.html
    http://www.data5u.com/free/type/https/index.html
    http://www.data5u.com/free/country/中国/index.html
    http://www.data5u.com/free/area/云南/index.html
    http://www.data5u.com/free/isp/电信/index.html

    根据以上已知基本可推出端口过滤的话可能是类似于下面这种:

    http://www.data5u.com/free/port/80/index.html

    然后试了一下,只一次就成功了 …

    image

    不知道作者怎么想的,这点不如蚂蚁代理了,蚂蚁代理也支持端口号筛选,不过它普通的情况下是这样的:

     image

    端口号是用图片显示的,按照端口筛选是这样的:

    image

    因为发请求的人已经知道端口号了,所以再图片显示端口号也没用了,不如干脆将ip地址的一部分按图片显示,这种设计还是比较好的,因为反爬虫对对方已知信息增加获取难度没有意义,应该对其未知信息设计获取门槛。

    不过没卵用,下一篇写破解蚂蚁代理的反爬。

  • 相关阅读:
    OpenCV IplImage FlyCapture2 Image Conversion 两种图像类的相互转化
    [FlyCapture2] Bumblebee XB3 Save Images to Three AVI Files (Left, Center and Right) 大黄蜂立体相机保存捕获的视频到左中右三个不同的文件
    Links About Point Grey FlyCapture2 and Triclops
    Android方法数methods超过65536
    Android studio 3.1.1 找不到DDMS
    Android Error:Could not run build action using Gradle installation
    Android Studio maven-metadata.xml 卡着不动原因和解决方法
    Android 4.4及以后将内容布局延伸到状态栏
    java 通过文件后缀名查找文件
    GreenDao 数据库升级 连接多个DB文件 或者指定不同的model&dao目录
  • 原文地址:https://www.cnblogs.com/cc11001100/p/8646066.html
Copyright © 2011-2022 走看看