Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java实现Ip代理池

Java实现Ip代理池

作者头像
全栈程序员站长
发布于 2022-06-27 13:35:40
发布于 2022-06-27 13:35:40
99400
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
设置Ip代理很多时候都会有用到,尤其是在写爬虫相关项目的时候。虽然自己目前没有接触这种需求,但由于最近比较闲,就写着当作练习吧

爬取代理IP

爬取

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 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即成功。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /** * 检测代理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对象即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ipBean.getIp(), ipBean.getPort()));

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /** * @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方法参考了 这篇博客

全局代理

直接上代码,就几行代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 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://javaforall.cn/133017.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年6月9,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
django2.0+连接mysql数据库迁移时候报错
去到\python\lib\site-packages\django\db\backends\mysql\base.py"
小小咸鱼YwY
2020/06/19
1.2K0
Django迁移数据库报错你遇到了吗?
Adventure may hurt you, but monotony will kill you.
小闫同学啊
2020/03/25
6270
django2.2安装错误最全的解决方
mysqldb只支持python2,pymysql支持3,都是使用c写的驱动,性能更好
py3study
2020/01/02
6400
python3安装mysqlclient,解决django使用pymysql报错的问题
在django中为了使用MySQL,一般是在项目目录下的__init__.py中添加
用户1214487
2020/12/01
7.4K0
关于Django2.x安装mysql报
最近新建项目,想测一下Django的最新的版本,在集成Mysql的时候,安装pymysql,会遇到这个问题。(django.core.exceptions.ImporoperLyConfigured:mysqlclient1.3.13 or newer is required; you have 0.9.3)测试新版本的很多人都遇到这个问题。 出现问题的原因是 Django2.x之后不在支持python2了,而原来集成mysql的mysqlclient不支持python3。有一段时间,想用python3在Django中写代码,都是用了另一个包pymysql。它简单替换了mysqlclient。
py3study
2020/01/02
7240
博客将 Django 1.11+ 升级到 Django 2.2+ 遇到的问题及规避方法
之前就有人一直催我把博客的 Django 升级到 Django 2.0 以上,但是我一直懒得升级,因为我早就看过 Django 2.x 版本和 1.11.x 版本,其实没有太多的不同,所以没有找到需要升级的必要。但是,秉着向新技术看齐的态度,我还是花了些时间(大概半天)把博客依赖的 Django 升级到当前最新版的 Django 2.2.6 版本了,在升级的过程中也遇到了很多问题,这些问题也是之前考虑到的,所以基本都迎刃而解了,这篇文章就分享一下升级的过程。
Hopetree
2022/09/26
1.1K0
Django教程 —— 初步完善图书管理系统
我们写项目写东西的时候都要养成良好的习惯,不要一来就上手写代码,我们先要进行初步分析和设计,让大脑有整体的概念,需要用到什么技术实现什么效果。这个习惯也不能学的太死,我们要活学活用,学会变通。有时候只是简单的学习一下,或者简单的实现一个小功能。大脑已经可以大概掌握,就无须设计与分析。
忆想不到的晖
2021/09/29
5730
Django教程 —— 初步完善图书管理系统
几个django 2.2和mysql使用
可能是由于Django使用的MySQLdb库对Python3不支持,我们用采用了PyMySQL库来代替,导致出现各种坑,特别是执行以下2条命令的是时候:
py3study
2020/01/07
8320
模型基本使用
python3.x使用的是pymysql模块,所以需要在project/__init.py文件中添加如上代码
星哥玩云
2022/09/14
2350
模型基本使用
Django小总结
初始Git git init 初始化本地仓库,会在根目录下创建一个.git文件夹 git log 查看提交日志 git status 查看日志 git add 文件名 添加到缓存区 git commit -m loginfo 将缓存区文件提交,loginfo 为说明 git config --global user.email yourname@example.com 创建一个邮箱 git config --global user.name 创建一个名字 git reset --hard 版本号
爱喝水的木子
2022/01/12
1.1K0
Django安装数据库MySQLdb
在使用Django搭建与树莓派智能终端时,使用mysql作为数据库管理,遇到如下问题:
墨文
2020/02/28
1.1K0
Django配置MySQL数据库教程
当前项目的 shell 环境下,执行pip freeze > requirements.txt,其他环境直接安装requirements.txt就好了。
BigYoung小站
2020/05/21
4.5K0
django-数据库之连接数据库
(1)定位到自己django安装的地方,我的是E:\anaconda2\envs\python36\Lib\site-packages\django
西西嘛呦
2020/08/26
4950
django学习-day01
如果运行报错就在runserver 加上端口如8080 django-admin startproject 文件名,创建django项目文件夹 python manage.py runserver 启动dj服务器 python manage.py startapp 项目名字 创建app(也就是项目)
kirin
2020/05/09
4030
学习猿地 python教程 django教程2 模型配置及案例
`create database mydb default charset=utf8mb4;`
学习猿地
2020/03/23
3100
django学习-day05
# 加载静态文件的两种方法 首先需要确保setting的installed_app中有staticfiles这一项 setting最后面一项中static_url=’/static/’ 这里是静态文件的路径新建的文件夹必须命名为static 和tmplates一样的 然后在html页面中用到 {% load static %} static是静态文件存放目录,默认是static,一般是在setting最后一样static_url中 名字是可以改的,但是不推荐,因为改了名字之后所有的模板中static就失效了
kirin
2020/05/09
5630
Did you install mysqlclient?
django使用mysql报错,错误如下: django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module. Did
小贝壳
2020/03/05
6.3K0
Python学习之Django切换MySQL数据库
我们使用Django 来操作MySQL,实际上底层还是通过Python来操作的。因此我们想要用Django来操作MySQL,首先还是需要安装一个驱动程序。在Python3中,驱动程序有多种选择。比如有pymysql以及mysqlclient等。
小柒2012
2019/12/05
1.9K0
django安装了pymysql还报My
在 python2 中,使用 pip install mysql-python 进行安装连接MySQL的库,使用时 import MySQLdb 进行使用
py3study
2020/01/07
8910
Django之模型---ORM简介
  ORM,是“对象-关系-映射”的简称,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动。
py3study
2020/01/20
1.6K0
相关推荐
django2.0+连接mysql数据库迁移时候报错
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验