Java爬虫
以sougou图片为例:https://pic.sogou.com/
JDK17、SpringBoot3.2.X、hutool5.8.24实现Java爬虫,爬取页面图片
项目介绍
开发工具:IDEA2023.2.5
JDK:Java17
SpringBoot:3.2.x
通过 SpringBoot 快速构建开发环境,通过 Jsoup 实现对网页的解析,并获取想要的资源数据
使用 hutool 工具,将所需要的字符串转成 JSON 对象,并从 JSON 对象中获取对应的数据资源
爬取网页图片资源,并将爬取到的资源下载到本地文件夹,对于大量的资源使用多线程下载
核心Jar包
org.jsoup jsoup 1.15.3
项目依赖
pom.xml
4.0.0 org.springframework.boot spring-boot-starter-parent 3.2.1 cn.molu jsoup 0.0.1-SNAPSHOT jsoup java网络爬虫;更多技术分享地址请关注:https://blog.csdn.net/qq_51076413 17 17 17 17 UTF-8 UTF-8 cn.hutool hutool-all 5.8.24 org.jsoup jsoup 1.15.3 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true · org.springframework.boot spring-boot-maven-plugin org.projectlombok lombok
爬取思路
一、解析网页:获取资源网页,从网页中解析想要的资源数据;
- 查看网页资源的位置,分析资源渲染到页面的规律;
- 根据分析到的规律,统一提取资源数据,得到列表;
- 对列表数据进行进一步解析,最终拿到想要的资源;
- 对资源数据进行处理,保存到数据库或是下载资源;
二、调用接口:直接获取想要的图片资源;
- 需要分析资源网站,获取资源数据加载的时机和请求接口;
- 分析接口的请求参数,入参是否有加密,是否有请求限制;
- 测试接口,拿到结果,查看结果是否是自己所需要的资源;
- 处理资源数据,保存到数据库或者将资源文件下载到本地;
三、缓存资源:从页面JS中直接获取资源
- 页面加载后,我们下滑或者分页时,没有请求日志;
- 页面没有重新加载,但是数据在不断更新和加载中;
- 当超过一定数量时,会有一次的请求日志显示出来;
- 最后分析得到,数据是缓存到页面中的JS变量中了;
一、解析网页
1.1、过程与思路
分析资源:
- 打开资源网站,分析和定位资源所在位置,并分析资源渲染到页面的规律;
- 如图,定位到资源位置,并发现了资源渲染的规律,使用document.querySelectorAll('xxx')可以得到页面中所有的资源
网站地址:https://pic.sogou.com/pic/searchList.jsp?from=homeHotSearch&rcer=&spver=0&keyword=美女壁纸#top=1395.199951171875&more=false
定位资源所在位置
使用css选择器获取资源:
- 根据分析到的规律,统一提取资源数据,得到列表;
- document.querySelectorAll('div#result div.similar div.similar-item a.single-box') 得到所有的资源列表
获取资源链接和标题:
- 对列表数据进行进一步解析,最终拿到想要的资源;
- document.querySelector('xxx')提取资源标题和资源链接
示例代码如下:
let divElement = document.querySelectorAll('div#result div.similar div.similar-item a.single-box'), result = []; for (let tag of divElement ) { let title = (tag.querySelector('h4.info-title').innerText||'').replace(/\s*/g,''); // 拿到标题,去除所有空格和特殊字符 let url = tag.querySelector("div.img-height img").currentSrc||''; // 拿到资源链接 result.push({title,url}); // 收集资源数据 } console.log(result); // 打印资源列表
处理资源数据:
- 对资源数据进行处理,保存到数据库或是下载资源;
1.2、Java代码实现
按照以上思路,我们使用Java代码来实现以上操作;
页面地址:https://pic.sogou.com/pic/searchList.jsp?from=homeHotSearch&rcer=&spver=0&keyword=美女壁纸#top=1395.199951171875&more=false
public static void main(String[] args) { // 获取网页资源 Document document = Jsoup.parse(HttpUtil.get("https://pic.sogou.com/pic/searchList.jsp?from=homeHotSearch&rcer=&spver=0&keyword=美女壁纸#top=1395.199951171875&more=false", 15000)); // 只获取标签中的元素 Element body = document.body(); // 使用css选择器提取所有资源,得到列表数据 Elements aElements = Optional.of(body.select("div#result")) .orElseGet(Elements::new).select("div.similar div.similar-item a.single-box"); // 进一步解析,获取资源链接和标题,将资源收集成集合中 Setresult = aElements.stream().map(tag -> { JSONObject resource = new JSONObject(); String title = tag.select("div.img-info h4.info-title").text(); String src = tag.select("div.img-height img").attr("src"); return resource.set("title", title).set("src", src); }).filter(ObjUtil::isNotEmpty).collect(Collectors.toSet()); // 打印数据集 System.out.println(result); System.out.println("共获取到:" + result.size() + "条数据"); }
1.3、爬取结果展示
[{"title":"每日更新 颜值美女壁纸,男人看了都会 珍藏 颜值","src":"https://i04piccdn.sogoucdn.com/485013ec7340e4f6"}, {"title":"美女 手机壁纸","src":"https://i02piccdn.sogoucdn.com/25a5aad0f9df1e0f"}, {"title":"美女 手机壁纸","src":"https://i04piccdn.sogoucdn.com/d4fe1d8d67d92d03"}, {"title":"美女 手机壁纸","src":"https://i01piccdn.sogoucdn.com/c9363d03d43130cd"}, {"title":"亭亭玉立,美若天仙","src":"https://i04piccdn.sogoucdn.com/51ea6e33666f6e57"}] 共获取到:5条数据
二、调用接口
2.1、过程与思路
分析网站资源得到资源接口:
- 需要分析资源网站,获取资源数据加载的时机和请求接口;
- 分析接口的请求参数,入参是否有加密,是否有请求限制;
- 测试接口,拿到结果,查看结果是否是自己所需要的资源;
- 处理资源数据,保存到数据库或者将资源文件下载到本地;
2.2、Java代码实现
按照上述,找到接口https://pic.sogou.com/napi/wap/searchlist,拿到参数,直接发起POST请求,得到资源;
请求参数
{ "initQuery": "美女手机壁纸", "queryFrom": "wap", "from": "homeHotSearch", "rcer": "", "spver": "0", "keyword": "美女壁纸", "start": 48, "reqType": "client", "reqFrom": "wap_result", "prevIsRedis": "n", "qua": "", "headers": {}, "pagetype": 0, "amsParams": [] }
Java代码
接口地址:https://pic.sogou.com/napi/wap/searchlist
请求方式:POST
public static void main(String[] args) { // 查询接口 String postUrl = "https://pic.sogou.com/napi/wap/searchlist"; // 查询参数 String params = """ { "initQuery": "美女手机壁纸", "queryFrom": "wap", "from": "homeHotSearch", "rcer": "", "spver": "0", "keyword": "美女壁纸", "start": 48, "reqType": "client", "reqFrom": "wap_result", "prevIsRedis": "n", "qua": "", "headers": {}, "pagetype": 0, "amsParams": [] } """; // 发起post请求,得到上图所述的结果数据 String json = HttpUtil.post(postUrl, params, 15000); // 解析结果数据,拿到最终的资源节点 JSONArray jsonArray = JSONUtil.parseObj(json).getJSONObject("data").getJSONObject("picResult").getJSONArray("items"); // 进一步解析提取所需要的资源数据,排除不需要的数据,将资源收集成集合中 Setresult = jsonArray.stream().map(item -> { JSONObject resource = new JSONObject(); if (item instanceof JSONObject jsonObject) { String title = jsonObject.getStr("title"); // 资源标题 String picUrl = jsonObject.getStr("picUrl"); // 图片链接 String thumbUrl = jsonObject.getStr("thumbUrl"); // 缩略图链接 String oriPicUrl = jsonObject.getStr("oriPicUrl"); // 原图链接 String locImageLink = jsonObject.getStr("locImageLink"); // 原图链接 return resource.set("title", title).set("picUrl", picUrl) .set("thumbUrl", thumbUrl).set("oriPicUrl", oriPicUrl) .set("locImageLink", locImageLink); } return null; }).filter(ObjUtil::isNotEmpty).collect(Collectors.toSet()); // 打印数据集 System.out.println(result); System.out.println("共获取到:" + result.size() + "条数据"); }
2.3、爬取结果展示
三、缓存资源
3.1、过程与思路
- 页面加载后,我们下滑或者分页时,没有请求日志;
- 页面没有重新加载,但是数据在不断更新和加载中;
- 当超过一定数量时,会有一次的请求日志显示出来;
- 最后分析得到,数据是缓存到页面中的JS变量中了;
3.2、Java代码实现
变量名:window.__INITIAL_STATE__
缓存中有很多数据,我们以searchlist -> groupFixedResult -> groupPic中的数据为例,获取并解析里面的资源
资源地址:https://pic.sogou.com/pic/searchList.jsp?from=homeHotSearch&rcer=&spver=0&tagQSign=%E9%AB%98%E6%B8%85,3636d5ad&showMode=0&routeName=searchlist&keyword=美女
public static void main(String[] args) { // 请求资源地址得到页面数据 Document document = Jsoup.parse(HttpUtil.get("https://pic.sogou.com/pic/searchList.jsp?from=homeHotSearch&rcer=&spver=0&tagQSign=%E9%AB%98%E6%B8%85,3636d5ad&showMode=0&routeName=searchlist&keyword=美女", 15000)); String variableName = "window.__INITIAL_STATE__"; // 解析得到所有的