一、介绍:何为爬虫

网络爬虫(Web crawler)也叫做网络机器人 可以代替人 自动地在互联网中进行数据信息的采集和整理
是一种按照一定的规则 自动地抓取万维网信息的程序或者脚本
可以自动采集所有其能够访问到的页面的内容 以获取相关数据

在大数据时代 信息的采集是一项重要的工作
而互联网中的数据是海量的 如果单纯靠人力进行信息采集 不仅低效繁琐 搜集的成本也会提高
爬虫技术就是为了解决如何高效地获取互联网中重要的信息

从功能上讲 爬虫分为数据采集 处理 储存三个部分
爬虫从一个或若干个初始网页的URL开始 获取初始网页的URL
在抓取网页的过程中 不断从当前页面上抽取新的URL放入队列 直到满足系统的一定停止条件最后结束爬取

二、Java爬虫所使用技术

其实爬虫的话在Python中应用的会更加广泛 好歹是脚本语言
上学期上课也学到Python爬虫 但长久没使用 好多都忘了 (笑

扯远了

Java中 若要实现爬虫 可用HttpClient和Jsoup 这两个是一对
其它Java的爬虫框架大部分都是底层以此为基础进行封装的 例如WebMagic

HttpClient:抓取数据

在浏览器中 一直以来都是使用HTTP协议访问互联网的网页
网络爬虫需要编写程序 同样使用HTTP协议访问网页
那么 可以使用Java的HTTP协议客户端HttpClient这个技术来实现抓取网页数据

引入依赖:

<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.2</version>
</dependency>

Jsoup:解析数据

在抓取到页面后 页面是一大段的HTML代码 因此还需要对页面进行解析
可以使用字符串处理工具解析页面 也可使用正则表达式 但是这些方法都会带来很大的开发成本
因此需要使用一款专门解析HTML页面的技术 由此 就有了Jsoup

Jsoup是一款Java的HTML解析器 可直接解析某个URL地址或HTML文本内容
提供了一套非常省力的API 可通过DOM CSS以及类似于JQuery的操作方法来取出数据和操作数据

主要功能:

  • 1、从一个URL 文件或字符串中解析HTML
  • 2、使用DOM或CSS选择器查找或取出数据
  • 3、操作HTML元素 属性 文本

引入依赖:

<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.10.2</version>
</dependency><!--封装好的工具类(需要用到里面的fileUtils类)-->
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency><!--封装好的工具类(需要用到里面的StringUtils类)-->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.7</version>
</dependency>

★虽然 使用Jsoup也可以替代HttpClient来直接发起请求解析数据 但往往不会这么用
因为在实际的爬虫开发过程中 需要使用到多线程 连接池 代理等方式
Jsoup对这些的支持并不是很好 因此一般仅仅把Jsoup作为Html解析工具使用

三、使用

1、HttpClient

✧、基本操作✧

  • 1、创建HttpClient对象:模拟打开浏览器
CloseableHttpClient httpClient = HttpClients.createDefault();
  • 2、创建HttpGet对象:模拟输入网址 发起get请求
HttpGet httpGet=new HttpGet("http://www.baidu.com");
  • 3、使用HttpClient对象发起请求:模拟按下回车 发起请求 返回响应
CloseableHttpResponse response = httpClient.execute(httpGet);
  • 4、解析响应 获取数据
// 判断状态码是否为200
if (response.getStatusLine().getStatusCode()==200)
{HttpEntity httpEntity = response.getEntity();String data=EntityUtils.toString(httpEntity,"utf8");System.out.println(data);
}

✧、发起Get请求和Post请求✧

首先 当然是创建HttpClient对象

CloseableHttpClient httpClient = HttpClients.createDefault();

接下来 就是发起请求了 分为Get请求和Post请求

Get请求创建HttpGet对象:

不带参数

// 创建HttpGet对象 设置url地址
HttpGet httpGet=new HttpGet("http://www.baidu.com");

带单个参数

// 创建URIBuilder
URIBuilder uriBuilder=new URIBuilder("http://zp.zjitc.net/info/notice/detail");
// 设置参数
uriBuilder.setParameter("id","c5bab1524b974f9fbc7c456a2fa79844");

带多个参数

// 创建URIBuilder
URIBuilder uriBuilder=new URIBuilder("http://www.zjitc.net/newssjgy.jsp");
// 设置参数
uriBuilder.setParameter("urltype","tree.TreeTempUrl").setParameter("wbtreeid","1209");
// 创建HttpGet对象 设置url地址
HttpGet httpGet=new HttpGet(uriBuilder.build());

Post请求创建HttpGet对象:

不带参数

创建HttpPost对象 设置url地址
HttpPost httpPost=new HttpPost("http://www.zjitc.net/");

带参数

// 创建HttpPost对象 设置url地址
HttpPost httpPost=new HttpPost("http://yun.itheima.com/search");
// 声明List集合 封装表单中的参数
List<NameValuePair> params=new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("so","Java"));
params.add(new BasicNameValuePair("type","course"));
params.add(new BasicNameValuePair("realhash","6666cd76f96956469e7be39d750cc7d9_60eddf1e1638d1929ceae963fa334549"));
// 创建表单的Entity实体对象 第一个参数为封装好的表单数据 第二个参数为编码
UrlEncodedFormEntity urlEncodedFormEntity=new UrlEncodedFormEntity(params,"utf8");
// 设置表单的Entity实体对象到httpPost对象中
httpPost.setEntity(urlEncodedFormEntity);

最后 处理返回数据

CloseableHttpResponse response=null;
try
{// 使用HttpClient发起请求 获取responseresponse = httpClient.execute(httpGet);// 解析响应if (response.getStatusLine().getStatusCode()==200){HttpEntity entity = response.getEntity();String data = EntityUtils.toString(entity,"utf8");System.out.println(data.length());}
}
catch
(IOException e){e.printStackTrace();
}
finally{// 关闭responsetry{response.close();} catch (IOException e) {e.printStackTrace();}// 关闭httpClienttry { httpClient.close();} catch (IOException e) {e.printStackTrace();}
}

✧、连接池✧

每次请求都需要创建HttpClient 会产生频繁创建和销毁的问题 造成资源浪费和影响性能
可用连接池来解决此问题

①、创建连接池管理器

PoolingHttpClientConnectionManager connectionManager=new PoolingHttpClientConnectionManager();

②、配置参数

// 设置最大连接数
connectionManager.setMaxTotal(100);
// 设置每个主机(Host)的最大连接数
connectionManager.setDefaultMaxPerRoute(10);

③、使用连接池管理器发起请求
语法:doGet(connectionManager);

private static void doGet(PoolingHttpClientConnectionManager connectionManager)
{// ★并非每次创建新的HttpClient对象 而是从连接池中获取CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();HttpGet httpGet=new HttpGet("http://www.baidu.com");CloseableHttpResponse response=null;try {response = httpClient.execute(httpGet);if (response.getStatusLine().getStatusCode()==200){String data = EntityUtils.toString(response.getEntity(), "utf8");System.out.println(data.length());}} catch (IOException e) {e.printStackTrace();}finally {if (response!=null){try {response.close();} catch (IOException e) {e.printStackTrace();}}// 当使用连接池之后 不能手动关闭HttpClient 因为是由连接池管理的}
}

✧、设置请求参数(以Get请求为例)✧

①、配置请求信息

RequestConfig config=RequestConfig.custom().setConnectTimeout(1000)//创建连接的最长时间(单位毫秒).setConnectionRequestTimeout(500)//获取连接的最长时间(单位毫秒).setSocketTimeout(10*1000)//设置数据传输的最长时间(单位毫秒).build();

②、给请求设置请求信息

httpGet.setConfig(config);

2、Jsoup

Jsoup处理的步骤是 先解析 然后获取指定的元素

✧、解析✧

①、从URL中解析
调用Jsoup的parse方法:parse(new URL,超时时长)
Document document = Jsoup.parse(new URL("http://www.baidu.com"), 1000);使用标签选择器获取<title>标签中的内容
String title=document.getElementsByTag("title").first().text();System.out.println(title);
②、从字符串中解析
使用工具类的方法读取文件 获取字符串:readFileToString(new File,编码格式)
String content=FileUtils.readFileToString(new File("F:/IdeaProjects/crawler-first/src/JsoupTest.html"),"utf8");Document document = Jsoup.parse(content);String title=document.getElementsByTag("title").text();System.out.println(title);
③、从文件中解析
调用Jsoup的parse方法:parse(new File,编码格式)
Document document = Jsoup.parse(new File("F:/IdeaProjects/crawler-first/src/JsoupTest.html"), "utf8");String title = document.getElementsByTag("title").text();System.out.println(title);

✧、获取元素✧

①、dom方式获取元素

首先 解析网页数据
(这里举个栗子从本地的文件中解析

Document document = Jsoup.parse(new File("F:/IdeaProjects/crawler-first/src/JsoupTest.html"), "utf8");

然后 就是获取元素了

// 根据【id】获取元素 getElementById()
String data = document.getElementById("myspan1").text();// 根据【标签】获取元素 getElementsByTag()
// 获取第一个
String data = document.getElementsByTag("span").first().text();
// 获取第二个
String data = document.getElementsByTag("span").eq(1).text();// 根据【class类名】获取元素 getElementsByClass()
// 获取第一个
String data = document.getElementsByClass("ms").first().text();
// 获取第二个
String data = document.getElementsByClass("ms").eq(1).text();// 根据【属性名】获取元素 getElementsByAttribute()
// 获取第一个
String data = document.getElementsByClass("ms").first().text();
// 获取第二个
String data = document.getElementsByClass("ms").eq(1).text();// 根据【属性和属性值】获取元素
String data = document.getElementsByAttributeValue("test", "aaa").text();

获取完了 最后 是对元素进行处理

System.out.println(data);

如此 即为dom方式获取元素的一个基本流程


②、Selector选择器方式获取元素

同样的 首先 是解析网页数据
(这里举个栗子从本地的文件中解析

Document document = Jsoup.parse(new File("F:/IdeaProjects/crawler-first/src/JsoupTest.html"), "utf8");

然后获取元素

// 根据id获取元素 #name
Elements elements = document.select("#myspan1");// 根据标签获取元素 name
Elements elements = document.select("span");// 根据class获取元素 .name
Elements elements = document.select(".ms");// 根据属性获取元素 [name]
Elements elements = document.select("[abc]");// 根据属性和属性值获取元素 [name=value]
Elements elements = document.select("[test=aaa]");

获取完了 最后 是对元素进行处理

for (Element e:elements)
{System.out.println(e.text());
}

如此 即为选择器方式获取元素的一个基本流程


③、Selector组合选择器方式获取元素

元素和id:el#id
元素和class:el.class
元素和属性名:el[attr]
任意组合:例如el[attr].class
所有子元素:parent child
指定直接子元素:parent>child
所有直接子元素:parent>*

使用的时候 同样也是使用select()方法

document.select()

详解用Java实现爬虫:HttpClient和Jsoup的介绍及使用(请求方式、请求参数、连接池、解析获取元素)相关推荐

  1. java基础(十三)-----详解内部类——Java高级开发必须懂的

    java基础(十三)-----详解内部类--Java高级开发必须懂的 目录 为什么要使用内部类 内部类基础 静态内部类 成员内部类 成员内部类的对象创建 继承成员内部类 局部内部类 推荐博客 匿名内部 ...

  2. Java类加载机制详解【java面试题】

    Java类加载机制详解[java面试题] (1)问题分析: Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数 ...

  3. scrapy爬虫储存到mysql_详解Python之Scrapy爬虫教程NBA球员数据存放到Mysql数据库

    获取要爬取的URL 爬虫前期工作 用Pycharm打开项目开始写爬虫文件 字段文件items # Define here the models for your scraped items # # S ...

  4. java访问修饰符详解——学java,零基础不怕,不只要理论,更要实践+项目,a href=http://www.bjweixin.com太原维信科技提供 /a...

    java访问修饰符详解--学java,零基础不怕,不只要理论,更要实践+项目 <a href=http://www.bjweixin.com>太原维信科技提供 </a> pub ...

  5. java 泛型详解、Java中的泛型方法、 java泛型详解

    本文参考java 泛型详解.Java中的泛型方法. java泛型详解 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用. 什么是泛型?为什么要使用泛型? 泛型,即& ...

  6. java web几百万分页_举例详解用Java实现web分页功能的方法

    举例详解用Java实现web分页功能的方法 发布于 2020-11-25| 复制链接 摘记: 分页问题是一个非常普遍的问题,开发者几乎都会遇到,这里不讨论具体如何分页,说明一下Web方式下分页的原理. ...

  7. 接口详解(JAVA)

    接口详解(JAVA) 文章目录 接口详解(JAVA) 接口 接口的定义和使用 练习 接口的细节:成员特点和接口的各种关系 接口中成员的特点 接口和类之间的关系 接口中新增方法,接口应用和适配器设计模式 ...

  8. mencoder和ffmpeg参数详解 (Java处理视频)

    本系列文章导航 Windows下FFmpeg快速入门 ffmpeg参数解释 mencoder和ffmpeg参数详解(Java处理视频) Java 生成视频缩略图(ffmpeg) 使用ffmpeg进行视 ...

  9. 算法问题:整数除法详解(Java方向)

    算法问题:整数除法详解(Java方向) 1.力扣题目 2.结果代码分析 3.完整的结果代码 4.代码出处和教学出处 5.博主 边学习边记录算法的学习 1.力扣题目 1.给定两个整数 a 和 b ,求它 ...

最新文章

  1. python stm32-尝试一下使用Python来开发STM32
  2. 计算字符串相似度算法—Levenshtein
  3. 5.1.3 IO控制方式
  4. SAP ABAP关键字在Chrome浏览器里高亮显示的实现原理 - How is ABAP keyword highlight implemented in Chrome
  5. SAP S/4HANA使用ABAP获得生产订单的状态 1
  6. C++之STL理论基础
  7. XSS常见攻击与防御
  8. BZOJ2137: submultiple(生成函数,二项式定理)
  9. 如何使用Java将字符串保存到文本文件?
  10. 大数据开发之Hadoop---初始Hadoop
  11. python编程语言_Python编程语言的历史
  12. Jsoup进阶之获取指定数据
  13. 服务站: WCF 消息传递基础 -- MSDN Magazine, April 2007
  14. 护眼html颜色,在电脑中设置护眼颜色、更换网页背景色、一键护眼
  15. 小刘同学的sansen-virtuosoIC618电路仿真记录
  16. ossfs挂载到本地磁盘
  17. Windows下常用网络命令
  18. 常用的七种数据分析方法有哪些?
  19. 联通物联卡为什么没有网络_联通物联网卡怎么样?联通物联卡的查询官网是什么?...
  20. 本科以下请注意!在职低学历直升本科!免试入学,无需到校,灵活在岗就读,名额有限,速看!...

热门文章

  1. 机器学习-线性模型及广义线性模型
  2. 如何调整Thinkpad x230的mini DP输出分辨率?
  3. 利用C#编写一个高斯正反算程序
  4. php mail 垃圾邮件,如何避免我的邮件从PHP邮件()被标记为垃圾邮件? - 程序园
  5. Could not find parameter map
  6. TCP与UDP 的区别
  7. 鸿蒙轻内核源码分析:文件系统LittleFS
  8. Framework学习之旅:Zygote进程
  9. flask_pagedown小修改
  10. 从 RHEL 6 升级至 RHEL 7