文章目录:

  • HttpClient(请求数据):
  • Jsoup解析筛选数据:
  • 通过httpclient+jsoup爬取代理ip网址上面的ip和端口,并存入数据库:
  • 筛选数据库中的有效代理IP,并实现代理IP访问:
  • 我的目录结构(service接口和实现层省略了没有贴出来):
  • 下面上几张效果图:

HttpClient(请求数据):

创建httpclient(介绍两种方式)
方式一:

CloseableHttpClient httpclient = HttpClients.createDefault();

方式二(使用连接池获取httpclient):

//创建连接池管理器PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();//设置最大连接数cm.setMaxTotal(200);//设置访问每个网站得最大连接数,不影响其它网站得访问cm.setDefaultMaxPerRoute(20);//返回httpclientreturn HttpClients.custom().setConnectionManager(cm).build();

生成URI(控制台打印出来可以看到是自动生成?来连接参数):

URIBuilder uriBuilder = new URIBuilder("http://www.baidu.com/s").// 设置参数setParameter("ie", "utf-8").// 第一个参数setParameter("f", "8").// 第二个参数setParameter("wd", "test");// 第三个参数URI uri = uriBuilder.build();

声明请求方式get/post(传入String类型参数,可以直接放入自己拼接的字符串URL):

HttpGet httpGet = new HttpGet(uri);
HttpPost httpPost = new HttpPost("https://www.xicidaili.com/nn/" + id);

配置请求参数以及代理IP:

// 代理IP设置,代理 ip查询地址:https://www.xicidaili.com/HttpHost httoHost = new HttpHost("118.181.226.166",44640);// 配置请求参数RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(3000).// 3秒,重连接池获取连接最长时间setConnectTimeout(5000).// 创建连接最长时间setSocketTimeout(20 * 1000).// 20秒,数据传输最长时间// setProxy(httoHost).// 设置代理build();httpGet.setConfig(config);

设置用户代理信息:

httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18363");

使用httpclient发起请求,判断状态码,并获取数据:

CloseableHttpResponse response = httpclient.execute(httpGet);// 判断状态码是否为200if (response.getStatusLine().getStatusCode() == 200) {// 获取响应数据HttpEntity entity = response.getEntity();String string = EntityUtils.toString(entity, "UTF-8");// 存入本地FileUtils.writeStringToFile(new File("C:/Users/17210/Desktop/test2.html"), string, "utf-8");}response.close();httpclient.close();

Jsoup解析筛选数据:

:jsoup也能实现请求,但是不大好使,下面举个例子

//第一个参数为URL类型,第二个应该是超时时间
Document dom = Jsoup.parse(url, timeoutMillis);

用jsoup读取本地html,并获取需要的内容:
注:之所以前面存入本地是为了方便查看返回的html结构,以此来寻找特征筛选需要的内容
方式一(不如方式二好使,看看就行):

String html = FileUtils.readFileToString(new File("C:/Users/17210/Desktop/test.html"), "utf-8");Document dom = Jsoup.parse(html);// 通过ID获取具体元素得idString Idtext = dom.getElementById("foot").id();// 直接解析dom中得元素,通过标签获取多个元素得文本String Tagtext = dom.getElementsByTag("title").first().text();// 通过属性获取多个元素的多个或单个属性值,文本内容,idAttributes Attrtext = dom.getElementsByAttribute("onclick").first().attributes();//默认取得全部匹配的属性值String strings = Attrtext.toString();String Attrtext1 = dom.getElementsByAttributeValue("onclick","return false;").get(2).attr("key");//获取元素html的string字符串String Attrtext2 = dom.getElementsByAttributeValueMatching("onclick","这里写正则表达式").get(2).html();// 通过属性获取第一个元素的多个或单个class名字String Classtext = dom.getElementsByClass("feedback").first().className();Set<String> Classtext2 = dom.getElementsByClass("feedback").first().classNames();

方式二,通过选择器的cssquery查找:

//通过标签名选择获取元素,对获取到的元素操作同上Elements Tagname = dom.select("title");String text = Tagname.first().text();//名命空间查找:c|if查找<c:if>String text2 = dom.select("c|if").first().text();//#id查找String text3 = dom.select("#foot").text();//.class查找String className = dom.select(".feedback").get(2).className();//[attribute]属性名查找String text4 = dom.select("[onclick]").get(2).text();//[attr=value]属性值查找String text5 = dom.select("[οnclick=return false;]").first().text();//选择器组合使用(可以多个任意组合)//元素+ID,如div#titleString text6 = dom.select("div#title").text();//元素+class的名字,如a.feedbackString text7 = dom.select("a.feedback").text();//元素+[属性名],如a[onclick]String text8 = dom.select("a[onclick]").text();//查找指定元素的全部指定子元素,ancestor child,中间空格隔开String texts = dom.select("div#title a").text();//查找指定元素的指定直接子元素-----下一级中的元素,>两边有空格String texts1 = dom.select("div#title > a").text();//查找指定元素的全部直接子元素-----下一级中的元素,>两边有空格String texts2 = dom.select("div#title > *").text();

通过httpclient+jsoup爬取代理ip网址上面的ip和端口,并存入数据库:

最近学到了springboot和mybatis于是就用这个框架去实现了。
请求的地址:“https://www.xicidaili.com/nn/” + id
id为网站分页显示的页码,也是方法传入的参数。

创建实体,用来存放ip和port:

@Component
public class IpAndPort {private int id;private String ip;private int port;
/**
这里是get和set方法
**/
}

筛选html中的ip和port并存入数据库:

@Component
public class DataAnalysis {@Resourceprivate IpAndPortMapper andPortMapper;@Resourceprivate IpAndPort andPort;public void GetIP() throws IOException {String html = FileUtils.readFileToString(new File("C:/Users/17210/Desktop/test2.html"), "utf-8");Document dom = Jsoup.parse(html);
for(org.jsoup.nodes.Element el:dom.select("img[alt=Cn][src]")) {String ip = el.parent().nextElementSibling().text();String port = el.parent().nextElementSibling().nextElementSibling().text();int port2=Integer.valueOf(port).intValue();//将字符串port变成intandPort.setIp(ip);andPort.setPort(port2);andPortMapper.save(andPort);//调用save方法存入数据库System.out.println("ip地址为:"+ip+"port为"+port2+"------保存至数据库成功");}}}

mapper和mapper.xml(采用mapper动态代理,无需手动实现接口):

@Repository
//@Mapper // 表明当前接口是一个Mapper,被Mybatis框架扫描,也在springboot配置自动扫描,就不用在这里声明了。
public interface IpAndPortMapper {List<IpAndPort> findAll();IpAndPort findById(Integer id);void save(IpAndPort ipAndPort);void update(IpAndPort ipAndPort);void delete(Integer id);
}
<mapper namespace="cu.ip.port.mapper.IpAndPortMapper">//注意这里的namespace是匹配的接口,别错了<select id="findAll" resultType="ipAndPort">select * from ip_port</select><select id="findById" parameterType="Int" resultType="ipAndPort">select * from ip_port where id=#{id}</select><insert id="save" parameterType="ipAndPort">INSERT into ip_port(ip,port) VALUES (#{ip},#{port})</insert><update id="update" parameterType="ipAndPort">update ip_port setip=#{ip},port=#{port}where id=#{id}</update><delete id="delete" parameterType="Int">delete from ip_port whereid=#{id}</delete>

配置application.properties:

#数据库MySQL
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.password=root
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://127.0.0.1/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
#Mybatis
#扫描--实体,而不是mapper接口
mybatis.type-aliases-package=cu.ip.port.entity
#扫描.xml
mybatis.mapper-locations=classpath:mapper/*Mapper.xml

筛选数据库中的有效代理IP,并实现代理IP访问:

:主要思路,捕获连接超时异常,然后迭代调用当前方法,传入的参数变为id+1去数据库查找下一条有效信息

@Component
public class DataCapture {@Resourceprivate IpAndPortService andPortService;
public HttpGet httpGet = new HttpGet("https://www.xicidaili.com/nn/");@Resourcepublic IpAndPort proxy;public String ip;public int port;public void dataCaptureWithProxy(int id) {// 使用连接池获取httpclientCloseableHttpClient httpclient = PoolManager.GetHpptClient();proxy = andPortService.findById(id);ip = proxy.getIp();port = proxy.getPort();HttpHost httoHost = new HttpHost(ip, port);// 配置请求参数RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(3000).// 3秒,重连接池获取连接最长时间setConnectTimeout(10000)//创建连接最长时间setSocketTimeout(10 * 1000).// 210秒,数据传输最长时间setProxy(httoHost).// 设置代理build();httpGet.setConfig(config);// 设置用户代理信息httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18363");// 使用httpclient发起请求,获得responsetry {CloseableHttpResponse response = httpclient.execute(httpGet);if (response.getStatusLine().getStatusCode() == 200) {System.out.println("有效代理IP,IP地址为:" + ip + "端口号为:" + port);//这里可以继续迭代,对有效代理做其他处理dataCaptureWithProxy(id + 1);}response.close();httpclient.close();} catch (SocketTimeoutException | ConnectTimeoutException ex) {System.out.println("请求连接超时"+ "当前id为:"+id);dataCaptureWithProxy(id + 1);} catch (Exception ex) {System.out.println("请求异常,异常信息:" + ex.getMessage() + ","+ "当前id为:"+id+"正在尝试下一条IP");dataCaptureWithProxy(id + 1);//这里开始迭代}}

controller中的方法介绍:

@Controller
//@ResetController相当于加了个@response,返回文本内容而不是jsp跳转
public class IpAndPortController {@Resourceprivate IpAndPortService andPortService;@Resourceprivate DataAnalysis da;@Resourceprivate DataCapture ca;//将数据库中的全部ip和port输出到浏览器页面
@GetMapping("/findAll")@ResponseBodypublic List<IpAndPort> findAll() {return andPortService.findAll();}//查询单条记录@GetMapping("/findById/{id}")public IpAndPort findById(@PathVariable("id") Integer id) {return andPortService.findById(id);}
//删除单条记录
@GetMapping("/delete/{id}")public void delete(@PathVariable("id") Integer id) {andPortService.delete(id);}//这个方法需要post请求,并将表单传入的参数映射成对象@PostMapping("/update")public void update(@RequestBody IpAndPort IpAndPort) {andPortService.update(IpAndPort);}//这个方法执行数据插入方法,即将桌面刚刚存入的html进行筛选并存入数据库,//当定页面获取到的数据正常后可以在前面将获取到的数据进行直接筛选保存@GetMapping("/do")@ResponseBodypublic String statrt() {try {da.GetIP();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return  "数据插入数据库成功!";}//这个方法执行数据抓取,并存入桌面,当肯定抓取到的数据没有问题时可以省略,在前面改为直接筛选并存入数据库@GetMapping("/find/{id}")@ResponseBodypublic String findip(@PathVariable("id") String id) throws Exception {try {ca.dataCaputure(id);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return  "数据成功复制到桌面!";}
//这个方法用于筛选数据库中有效的IP和port
//页面传过来的参数为数据库中查询的起始地址@GetMapping("/getProxyIp/{id}")@ResponseBodypublic String getProxyIp(@PathVariable("id") int id) throws Exception {ca.dataCaptureWithProxy(id);return  "请在控制台查看查询结构"}

我的目录结构(service接口和实现层省略了没有贴出来):


pom.xml依赖—application.properties在上面目录3中配置mapper代理时贴出来了:

<!-- 添加父工程 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.10.RELEASE</version></parent><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.10</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.6</version></dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version></dependency><!-- 添加web开发得支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.10.2</version></dependency><!-- 文字处理 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.8.1</version></dependency><!-- 文件处理 --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency><!-- mysql连接依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version></dependency><!-- mybatis依赖 --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.0.0</version></dependency>

下面上几张效果图:


注:本人也是刚开始接触springboot,代码有些地方不规范,欢迎指正!

JAVA之HttpClient+Jsoup实现代理IP爬虫相关推荐

  1. java图片简单爬虫_[Java教程]使用jsoup进行简单的爬虫操作爬取图片

    [Java教程]使用jsoup进行简单的爬虫操作爬取图片 0 2015-12-01 17:00:27 package com.guanglan.util;import java.io.File;imp ...

  2. 代理ip如何使用_为什么在使用代理IP爬虫时会出现超时?

    相信很多朋友在使用代理IP爬虫时都遇到过这类状况:做了充足的准备,刚刚开始一天的爬虫工作时,就出现提示"访问网站地址请求超时",使用免费代理IP时这种情况更为频发. 为什么在使用代 ...

  3. ProxyPool proxy-pool: java 基于springboot框架获取代理ip

    PROXY-POOL: java 基于springboot框架获取代理ip

  4. python 使用代理ip爬虫

    Python 使用代理ip爬虫 爬虫定义 代理ip 为什么要用代理ip 代理ip来源 如何代理 简单吗 结束 爬虫定义 网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者 ...

  5. Java HttpClient 如何使用代理IP请求接口

    实际场景中,可能会遇到需要使用代理IP请求接口的需求,所以这里给大家分享一下如何通过代理IP请求接口. proxyServer 代理IP proxyPort 代理端口 HttpClient httpC ...

  6. 【转载】Jsoup设置代理ip访问

    转载地址:https://blog.csdn.net/qq_36980713/article/details/80913248 import java.io.IOException; import j ...

  7. 在代码中,给java程序自身设置网络代理来爬虫相关站点或使用相关api。

    在开发中,我们可能会使用到某些api. 但是这些api(如谷歌云)因为一些因素,我们本机是无法直接访问的. 最要命的是,我们开发中必然要用到这些api,而尽管本机开启了代理,但是java程序本身却不走 ...

  8. python爬虫ip代理没有作用_可能是一份没什么用的爬虫代理IP指南

    写在前面 做爬虫的小伙伴一般都绕不过代理IP这个问题. PS:如果还没遇到被封IP的场景,要不你量太小人家懒得理你,要不就是人家压根不在乎... 爬虫用户自己是没有能力维护一系列的代理服务器和代理IP ...

  9. 可能是一份没什么用的爬虫代理IP指南

    写在前面 做爬虫的小伙伴一般都绕不过代理IP这个问题. PS:如果还没遇到被封IP的场景,要不就是你量太小人家懒得理你,要不就是人家压根不在乎- 爬虫用户自己是没有能力维护一系列的代理服务器和代理IP ...

最新文章

  1. 双非的我科研如何超越双一流!
  2. Docker学习(2)——图文并茂讲解Docker基础命令
  3. 泛型排序器TComparer
  4. Amazon S3和Swift鉴权机制分析
  5. ios html图片相对路径,iOS 下加载本地HTML/js/css/image 等路径问题
  6. C#学习笔记(十一):类和对象
  7. java的异常处理块的形式_Java 异常处理详细解读
  8. 服务器可以修改cookie吗,是否可以为您拥有的网站/服务器设置Cookie?
  9. SUSE Labs Con 2018有感
  10. 计算机做无线AP共享文件,Win7开启AP无线一键共享网络(包括闪讯)给wifi设备使用!...
  11. Boss说:你要是能搞懂这六个分布式技术栈,我给你薪资翻倍
  12. arduino 智能车组装步骤_Arduino 自动避障智能小车制作教程
  13. Cadence快捷键设置
  14. 七、torch.nn
  15. Linux搭建Postfix邮件服务器
  16. 基于多任务学习的快件送达时间预测方法
  17. 项管行知02--工作环境
  18. connectbot本地安装php,Android studio下编译connectbot
  19. SSM餐饮管理点餐系统
  20. 毕业设计 单片机智能录音器设计与实现 - 物联网 嵌入式

热门文章

  1. 坚果pro android版本,坚果Pro有几个版本 哪个版本好?坚果Pro各版本的区别
  2. IC后端物理效应WPE--Well Proximity Effect(阱临近效应)
  3. Laravel symlink() has been disabled for security reasons
  4. 产品经理必看电影:当幸福来敲门
  5. 转回来慢慢看.挑着吃.
  6. LGA1155、LGA1156、LGA1366、LGA2011的CPU插槽对应的都是什么型号的CPU
  7. Android 自定义歌词滚动
  8. 电脑录屏软件帧率设置详解
  9. 触摸DevOps,从现在开始DevOps之旅
  10. 【转载】超简单集成HMS ML Kit 人脸检测实现可爱2D贴纸