Java实现Ip代理池

设置Ip代理很多时候都会有用到,尤其是在写爬虫相关项目的时候。虽然自己目前没有接触这种需求,但由于最近比较闲,就写着当作练习吧

爬取代理IP

爬取

关于爬取代理IP,国内首先想到的网站当然是 西刺代理 。首先写个爬虫获取该网站内的Ip吧。

先对 国内Http代理 标签页面进行爬取,解析页面使用的Jsoup ,这里大概代码如下

 private List<IPBean> crawl(String api, int index){
        String html = HttpUtils.getResponseContent(api + index);
        System.out.println(html);

        Document document = Jsoup.parse(html);
        Elements eles = document.selectFirst("table").select("tr");

        for (int i = 0; i < eles.size(); i++){
            if (i == 0) continue;
            Element ele = eles.get(i);
            String ip = ele.children().get(1).text();
            int port = Integer.parseInt(ele.children().get(2).text().trim());
            String typeStr = ele.children().get(5).text().trim();

            int type;
            if ("HTTP".equalsIgnoreCase(typeStr))
                type = IPBean.TYPE_HTTP;
            else
                type = IPBean.TYPE_HTTPS;

            IPBean ipBean = new IPBean(ip, port, type);
            ipList.add(ipBean);
        }
        return ipList;
    }

对某些不明白的变量,可以参考我Github
其中关键的就是css选择器语法,这里需要注意的是不要乱加空格,不然会导致找不到出现空指针。
css选择器语法具体参考这里 , 这里就不讲解了。

爬取的信息包括 ip地址、端口号、和代理类型(http或https), 这三个信息我放在IPBean这个类里面。

过滤

上面爬取完成后,还要进一步过滤,筛选掉不能使用的。

筛选大概原理就是先设置上代理,然后请求某个网页,若成功则代表此代理ip有效。
其中请求成功的标志我们可以直接获取请求的返回码,若为200即成功。

    /**
     * 检测代理ip是否有效
     *
     * @param ipBean
     * @return
     */
    public static boolean isValid(IPBean ipBean) {
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ipBean.getIp(), ipBean.getPort()));
        try {
            URLConnection httpCon = new URL("https://www.baidu.com/").openConnection(proxy);
            httpCon.setConnectTimeout(5000);
            httpCon.setReadTimeout(5000);
            int code = ((HttpURLConnection) httpCon).getResponseCode();
            System.out.println(code);
            return code == 200;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

注意这里要设置两个超时,连接超时和读取超时。连接超时还好,它默认只是有点长;然而读取超时如果不设置,它好像就会一直阻塞着。
时间设置为5s就够了,毕竟如果ip有效的话,会很快就请求成功的。这样过滤后,就得到有效的代理ip了

设置代理

单次代理

单次代理表示只在这一次连接中有效,即每次都需要代理。

http方式的代理非常简单,在URL对象的openConnection方法中加上个Proxy对象即可


 Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ipBean.getIp(), ipBean.getPort()));

 connection = (HttpsURLConnection) new URL(url).openConnection(proxy);

https 稍微复杂点了,中间加上了ssl协议


    /**
     * @param url
     * @param headerMap 请求头部
     * @param ipBean
     * @return
     * @throws Exception
     */
    public static String getResponseContent(String url, Map<String, List<String>> headerMap, IPBean ipBean) throws Exception {
        HttpsURLConnection connection = null;

        // 设置代理
        if (ipBean != null) {
            Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ipBean.getIp(), ipBean.getPort()));

            connection = (HttpsURLConnection) new URL(url).openConnection(proxy);

            if (ipBean.getType() == IPBean.TYPE_HTTPS) {
                SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
                connection.setSSLSocketFactory(sslContext.getSocketFactory());
                connection.setHostnameVerifier(new TrustAnyHostnameVerifier());
            }
        }

        if (connection == null)
            connection = (HttpsURLConnection) new URL(url).openConnection();

        // 添加请求头部
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36");
        if (headerMap != null) {
            Iterator<Map.Entry<String, List<String>>> iterator = headerMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, List<String>> entry = iterator.next();
                List<String> values = entry.getValue();
                for (String value : values)
                    connection.setRequestProperty(entry.getKey(), value);
            }
        }

        InputStream inputStream = connection.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

        StringBuilder stringBuilder = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
        }
        reader.close();
        inputStream.close();
        return stringBuilder.toString();
    }

    private static class TrustAnyTrustManager implements X509TrustManager {

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

这里https方法参考了 这篇博客

全局代理

直接上代码,就几行代码

package util;

import other.IPBean;

/**
 * @author Asche
 * @github: https://github.com/asche910
 * @date 2019年1月19日
 */
public class ProxyUtils {

    /**
     * 设置全局代理
     * @param ipBean
     */
    public static void setGlobalProxy(IPBean ipBean){
        System.setProperty("proxyPort", String.valueOf(ipBean.getPort()));
        System.setProperty("proxyHost", ipBean.getIp());
        System.setProperty("proxySet", "true");
    }

}

需要注意一点就是全局只是在该java项目中生效,它不会更改系统中的代理。

检测

设置完代理后,也可以用另外一种方法来判断是否代理成功,即直接获取当前ip地址。
这里我使用的是 https://www.ipip.net/ip.html 这个网站,请求获取html后再解析得到自己的当前ip


 private static final String MY_IP_API = "https://www.ipip.net/ip.html";

    // 获取当前ip地址,判断是否代理成功
    public static String getMyIp() {
        try {
            String html = HttpUtils.getResponseContent(MY_IP_API);

            Document doc = Jsoup.parse(html);
            Element element = doc.selectFirst("div.tableNormal");

            Element ele = element.selectFirst("table").select("td").get(1);

            String ip = element.selectFirst("a").text();

            // System.out.println(ip);
            return ip;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

优化

emmm 优化些啥呢???

速度

爬取ip时就几个网页,优化估计效果不大。而真正耗时的是检测ip是否有效,因此这里采用多线程,对每个ip的检测请求使用一个线程,最后副线程全部结束后再统计出有多少有效ip。然而问题又来了,怎么判断所有副线程全部结束了呢??? 脑中立刻想到的是join方法,然而仔细想想,才发现这样并不可取。最佳方法应该是设置一个计数器,每个线程结束后计数器加一,然后在主线程循环判断计数器的值是否与线程总数相等即可。由于涉及到并发,需要给某些方法加上锁。这里我代码中实现了,可以参考github

持久化

emmm 由于目前只是练练手,并没有这样的需求,比较懒, ~( ̄▽ ̄)~*
所以这个需求暂时放放吧,以后有时间再写

最后github入口:Asche910

原文地址:https://www.cnblogs.com/asche/p/10291701.html

时间: 2024-11-05 11:48:29

Java实现Ip代理池的相关文章

scrapy_随机ip代理池

什么是ip代理? 我们电脑访问网站,其实是访问远程的服务器,通过ip地址识别是那个机器访问了服务器,服务器就知道数据该返回给哪台机器,我们生活中所用的网络是局域网,ip是运营商随机分配的,是一种直接访问服务器的方式 代理服务器是一种间接方式,本地机器访问ip代理服务器,ip代理服务器帮我们发起服务请求,然后代理服务器接收数据返回给本机,由于中间有了层ip代理服务器,访问的速度和稳定性取决于代理服务器的性能 常规访问: 用户 >> ip  >> 服务器 代理访问: 用户用户 >

python开源IP代理池--IPProxys

今天博客开始继续更新,谢谢大家对我的关注和支持.这几天一直是在写一个ip代理池的开源项目.通过前几篇的博客,我们可以了解到突破反爬虫机制的一个重要举措就是代理ip.拥有庞大稳定的ip代理,在爬虫工作中将起到重要的作用,但是从成本的角度来说,一般稳定的ip池都很贵,因此我这个开源项目的意义就诞生了,爬取一些代理网站提供的免费ip(虽然70%都是不好使的,但是扛不住量大,网站多),检测有效性后存储到数据库中,同时搭建一个http服务器,提供一个api接口,供大家的爬虫程序调用. 好了,废话不多说,咱

ip代理池-基于mongodb数据库

代码用的python2.7,抓取xici免费代理,检测放入数据库中,为以后爬虫做准备.下面直接上代码 1 #-*-encoding=utf-8-*- 2 3 import requests 4 from lxml import etree 5 import time 6 import pymongo 7 from multiprocessing import Pool 8 9 10 class Getproxy(object): 11 def __init__(self): 12 self.he

小白也能做的IP代理池,好久没更新了,不知道你们想看什么呢!

IP代理池制作 GitHub主页: https://github.com/hfldqwe/ 使用工具: ip代理抓取: requests 后台搭建: Django+Redis 代理检测: ip地址查询:http://ip.chinaz.com/ 这个网站提供的接口:http://ip.chinaz.com/getip.aspx 代理抓取地址: 西刺代理:http://www.xicidaili.com/nn/ + num 设计思路 爬取代理ip,获取如下信息: IP地址 端口 服务器地址 类型

Python爬虫之ip代理池

可能在学习爬虫的时候,遇到很多的反爬的手段,封ip 就是其中之一. 对于封IP的网站.需要很多的代理IP,去买代理IP,对于初学者觉得没有必要,每个卖代理IP的网站有的提供了免费IP,可是又很少,写了个IP代理池 .学习应该就够了 ip代理池: 1,在各大网站爬去免费代理ip2,检查ip可用 可用存入数据库1和23,在数据库1中拿出少量代理ip存入数据库2(方便维护)4,定时检查数据库1和数据库2的代理数量,以及是否可用5,调用端口 1,在各大网站爬去免费代理ip 1 def IPList_61

【Python3爬虫】Scrapy使用IP代理池和随机User-Agent

在使用爬虫的时候,有时候会看到由于目标计算机积极拒绝,无法连接...,这就是因为我们的爬虫被识别出来了,而这种反爬虫主要是通过IP识别的,针对这种反爬虫,我们可以搭建一个自己的IP代理池,然后用这些IP去访问网站. 新建一个proxies.py,实现我们自己的代理池,主要模块有获取模块.验证模块和存储模块. (1)获取模块:爬取网上的免费代理,这一部分我就写了个爬取西刺代理的代码,除了获取网上的代理,还要对代理池中代理进行清洗,因为有些代理会失效: (2)验证模块:验证我们的代理是否可用,如果不

python爬虫+多线程+多进程+构建IP代理池

目标网站:静听网 网站url:http://www.audio699.com/ 目标文件:所有在线听的音频文件 附:我有个喜好就是晚上睡觉听有声书,然而很多软件都是付费才能听,免费在线网站虽然能听,但是禁ip很严重,就拿静听网来说,你听一个在线音频,不能一个没听完就点击下一集,甚至不能快进太快,否则直接禁你5分钟才能再听,真的是太太讨厌了... 于是我就想用爬虫给它爬下来存储本地就nice了. 我把我的大概分析步骤分享出来. 步骤1: 我查看静听网网页url有一个规律,基网址是http://ww

使用IP代理池和用户代理池爬取糗事百科文章

简单使用IP代理池和用户代理池的爬虫 import re import random import urllib.request as urlreq import urllib.error as urlerr #用户代理池 uapools = [ "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0", "Mozilla/5.0 (Windows NT 10.0; Win64; x

Flask开发系列之Flask+redis实现IP代理池

Flask开发系列之Flask+redis实现IP代理池 6.11-6.15号完善... 简易实现版 import requests import re import time import redis from bloom_filter import BloomFilter import ast pool = redis.ConnectionPool(host='localhost',password='xxx', port=6379, decode_responses=True) r = r