基于Jsoup的Java爬虫-爬取必应壁纸网站的壁纸(Java静态壁纸爬虫实例)

news/2024/11/22 9:26:43/

准备阶段
1、必应壁纸网站:https://bing.ioliu.cn(爬取对象网站)

2、Jsoup包下载地址:https://jsoup.org/download(以下代码需要用到该包,记得导入包)

编写工具类

为什么要编写工具类?

答:我之后可能还要写其他类型网站的爬虫,在这里编写个工具类方便以后的开发进行,以及实现代码复用,提高编程效率。

工具类代码如下:

(工具类中有些方法这个爬虫实例可以不会用到,以后可能有机会用到,工具类方法暂且这些,以后我还会继续写上一些使用的方法)

package com.yf.utils;import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;public class SpiderUtil {private static String UserAgent = "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)";private static int TIMEOUT = 30000;//设置访问超时时间(ms)/*** 在桌面创建一个名为directoryName的文件夹** @param directoryName*/public static File createDirectoryOnDesktop(String directoryName) {javax.swing.filechooser.FileSystemView fsv = javax.swing.filechooser.FileSystemView.getFileSystemView();File home = fsv.getHomeDirectory();File file = new File(home + "/" + directoryName);if (!file.exists())file.mkdir();//创建文件夹return file;}/*** 创建文件夹** @param path* @return*/public static File createDirectory(String path) {File file = new File(path);if (!file.exists()) {file.mkdirs();}return file;}/*** 在指定路径下创建一个名为directoryName的文件夹** @param path* @param directoryName* @return*/public static File createDirectory(String path, String directoryName) {File file = new File(path, directoryName);if (!file.exists()) {file.mkdirs();}return file;}/*** 在指定路径下创建一个名为directoryName的文件夹** @param path* @param directoryName* @return*/public static File createDirectory(File path, String directoryName) {File file = new File(path, directoryName);if (!file.exists()) {file.mkdirs();}return file;}/*** 根据url以及xpath获取页面的Elements并将其返回** @param url* @param xpath* @return*/public static Elements getElementsbyURL(String url, String xpath) {try {Document document = Jsoup.parse(new URL(url), TIMEOUT);Elements elements = document.select(xpath);return elements;} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();System.out.println("访问" + url.toString() + "超时");}return null;}/*** 获取URL的输入流** @param url* @return*/public static InputStream getInpuStream(String url) {URL imgurl = null;try {imgurl = new URL(url);//通过URL获取URLConnection对象URLConnection imgconnect = imgurl.openConnection();//然后添加请求头信息(模糊网站对爬虫的识别,将爬虫看作浏览器访问处理)imgconnect.setRequestProperty("User-Agent", UserAgent);//返回URLConnection输入流return imgconnect.getInputStream();} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}/*** 下载文件** @param is* @param os* @return true下载成功 false下载失败*/public static boolean downloadFile(InputStream is, OutputStream os) {try {byte[] b = new byte[2048];int len = 0;while ((len = is.read(b)) != -1) {//写入os.write(b, 0, len);}return true;} catch (IOException e) {e.printStackTrace();} finally {//关闭流if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}}return false;}
}

介绍Jsoup包的方法

Jsoup.parse(URL url,int timeout)(该实例主要用到该方法)

该方法通过访问url返回Document对象,访问超时会抛出异常,timeout为毫秒级的。

其他有趣的方法请自行百度

爬虫分析

1、观察必应壁纸网站的地址栏,第一页壁纸的url为https://bing.ioliu.cn/ranking?p=1,第二页壁纸的url为https://bing.ioliu.cn/ranking?p=2,必应壁纸网站的每一页的url都是规律的(一般大多数静态网站页面都会有个规律,除非是动态页面用JavaScript实现就需要通过另外一种手段爬取)

2、每一页网站下的壁纸标签以及内容都装在类名为item的div下。

打开类名为item的div的标签

 

获取图中a标签链接,得到图片次页面链接

进一步爬取

例如:https://bing.ioliu.cn/photo/ChefchaouenMorocco_ZH-CN6127993429?force=ranking_1

public static void main(String[] args) throws IOException {URL url=new URL("https://bing.ioliu.cn/photo/ChefchaouenMorocco_ZH-CN6127993429?force=ranking_1");Document document = Jsoup.parse(url, 30000);//System.out.println(document.toString());Element element = document.select(".progressive--not-loaded").get(0);System.out.println(document);}

用Java代码测试输出静态html代码可以看到图片真实url路径在下面的

.progressive--not-loaded类的img标签下

<body class="detail" oncontextmenu="self.event.returnValue=false"><div class="preview"><div class="progressive"><img class="target progressive__img progressive--not-loaded" src="http://h1.ioliu.cn/bing/LuciolaCruciata_ZH-CN9063767400_800x480.jpg?imageslim" data-progressive="http://h1.ioliu.cn/bing/LuciolaCruciata_ZH-CN9063767400_1920x1080.jpg?imageslim"></div><div class="mark"></div><div class="options">

图片路径为:

http://h1.ioliu.cn/bing/LuciolaCruciata_ZH-CN9063767400_1920x1080.jpg

这样就可以设置爬取的规则

主页(.item 一页一共12个item)->获取图片次页面链接

图片次页面(.progressive--not-loaded)获取图片的真实url路径

 

3、可以看到壁纸图片的源地址(主要爬取对象),图片的描述(爬取用来当文件名),图片拍摄日期,图片浏览量。这些都是可以爬取的内容,用Java写一个嵌套的循环就能够将整个网站的壁纸都爬取下来。

4、怎么获取必应壁纸网站的总页数?

代码实现

package com.yf.spider;import com.yf.utils.SpiderUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
/***必应壁纸爬虫*/
public class Reptile {public static void main(String[] args){//调用工具类在桌面创建一个文件夹String directoryName="photo";File photo=SpiderUtil.createDirectoryOnDesktop(directoryName);//必应壁纸网站String url="https://bing.ioliu.cn/ranking?p=1";//获取装在页数内容的页面标签Elements span=SpiderUtil.getElementsbyURL(url,"span");//通过字符串操作得到总页数//装在页数内容的页面标签在最后一个span标签中(观察可知)String p=span.get(span.size()-1).text();int intp=Integer.parseInt(p.substring(p.lastIndexOf("/")+2));//总页数System.out.println("图片总页数为:"+intp);for(int i=1;i<=intp;i++){URL tempurl= null;try {//通过for循环将页面tempurl = new URL("https://bing.ioliu.cn/ranking?p="+i);Document tempdocument=Jsoup.parse(tempurl,Integer.MAX_VALUE);//获取html//获取当前页面装有图片类名为card的div容器Elements cards = tempdocument.select("body > div.container > div > div.card");System.out.println("---------------第"+i+"页开始下载---------------");System.out.println("------------当前页共有:"+cards.size()+"张图片------------");for(Element e:cards){//获取图片链接地址//获取类名为card的div容器下的第一个a标签的属性href值String img_href=e.selectFirst("a").attr("href");// photo/LuciolaCruciata_ZH-CN9063767400?force=ranking_1// 获取img_href页面中的.progressive--not-loaded标签Elements elements = SpiderUtil.getElementsbyURL("https://bing.ioliu.cn/"+img_href,".progressive--not-loaded");//http://h1.ioliu.cn/bing/ChefchaouenMorocco_ZH-CN6127993429_1920x1080.jpg?imageslimString temp = elements.get(0).attr("data-progressive");//处理后 http://h1.ioliu.cn/bing/ChefchaouenMorocco_ZH-CN6127993429_1920x1080.jpgString imgsrc = temp.substring(0,temp.lastIndexOf("?"));System.out.println(imgsrc);//获取图片名称//例如:舍夫沙万的蓝色墙壁,摩洛哥 (© Tatsuya Ohinata/Getty Images)//字符串操作String str=e.selectFirst("div.description>h3").text().split(" ")[0];//舍夫沙万的蓝色墙壁,摩洛哥//将字符串中的,和,全部换成---舍夫沙万的蓝色墙壁,摩洛哥  -->  舍夫沙万的蓝色墙壁---摩洛哥String imgname=str.replaceAll(",","---").replaceAll(",","---");//字符串操作,获取图片链接文件的后缀名(jpg);String fileType=imgsrc.substring(imgsrc.lastIndexOf("."));//通过图片链接获取输入流InputStream is=SpiderUtil.getInpuStream(imgsrc);OutputStream os=new FileOutputStream(new File(photo,imgname+fileType));//PATH为存储路径//下载文件boolean b=SpiderUtil.downloadFile(is,os);if(b){System.out.println(imgname+" 下载完成");}else{System.out.println(imgname+" 下载失败");}// 休眠3秒 防反爬Thread.sleep(3000);}System.out.println("--------------第"+i+"页已下载完成--------------");} catch (MalformedURLException e) {e.printStackTrace();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}}
}

介绍一下谷歌浏览器中的开发者工具中的一个好用的功能,可以用来方便找页面标签

copy的选择器路径是这样的:body > div.page > span,实现代码中有些也是这么做的,不过也不要太过依赖工具。

运行结果

图片总页数为:108
---------------第1页开始下载---------------
------------当前页共有:12张图片------------
舍夫沙万的蓝色墙壁---摩洛哥 下载完成
淡水和盐水在埃斯塔蒂特附近的三河河口交汇---西班牙 下载完成
黄山---中国安徽省 下载完成
哈尔施塔特---奥地利 下载完成
巴扎鲁托群岛---莫桑比克 下载完成
从太空中拍摄到的地球 下载完成
埃特勒塔小镇---法国诺曼底 下载完成
雷尼尔山上空的璀璨银河--- 下载完成
新西兰南岛的塔斯曼湖 下载完成
被萤火虫照亮的小树林---日本四国岛 下载完成
基约夫附近的南摩拉维亚风景---捷克共和国 下载完成
马他奴思卡冰川里的冰隧道---阿拉斯加州 下载完成
--------------第1页已下载完成--------------
---------------第2页开始下载---------------
------------当前页共有:12张图片------------
金塔马尼小镇---巴厘岛---印度尼西亚 下载完成
希腊扎金索斯的沉船湾 下载完成
阿德温山谷的Hallwylfjellet山峰---挪威 下载完成
锡内莫雷茨村上空的英仙座流星雨---保加利亚 下载完成

爬取得到的图片:

补充:休眠时间间隔一定要设置,并且设置长一些,不要给人家服务器带来压力!!!

 

 

 

 

 

 

 

 

 

 


http://www.ppmy.cn/news/472410.html

相关文章

某农业大学数据结构A-第15-16周作业

1.希尔排序 【问题描述】给出一组数据&#xff0c;请用希尔排序将其按照从小到大的顺序排列好。 【输入形式】原始数据&#xff0c;以0作为输入的结束&#xff1b;第二行是增量的值&#xff0c;都只有3个。 【输出形式】每一趟增量排序后的结果 【样例输入】 8 3 6 1 68 12 19…

[第一章 web入门]afr

afr_1 题目开头已经提示说是任意文件读取漏洞 所以这里还需要复习一下php伪协议php://filter 的作用 读取源代码并进行base64编码输出&#xff0c;不然传入的参数会直接当做php代码执行就看不到源代码内容了。php://filter即使在allow_url_fopen和allow_url_include双off情况下…

微信小程序开发21__Echarts的应用

Echarts 是一个使用JS实现的开源可视化库&#xff0c; 其官网是 https://echarts.apache.org . 它提供了常规的折线图、柱状图、散点图、饼图、K线图等&#xff0c; 还支持图与图之间的混搭。 Echarts 的微信小程序版本的Github为 https://github.com/ecomfe/echarts-for-…

ESP32驱动-MAX98357-I2S数字功放驱动

MAX98357-I2S数字功放驱动 文章目录 MAX98357-I2S数字功放驱动1、MAX98357介绍2、硬件准备3、软件准备4、驱动实现4.1 DTMF音频生成4.2 从SD卡播放音频4.3 播放网络音频1、MAX98357介绍 MAX98357和MAX98358数字输入D类音频功率放大器,帮助设计者以高性价比实现紧凑、高效、即…

【SpringCloud-5】gateway网关

网关是干啥用的就不用再说了。 sringcloud中的网关&#xff0c;第一代是zuul&#xff0c;但是性能比较差&#xff08;1.x是阻塞式的&#xff0c;2.x是基于Netty的&#xff09;&#xff0c;然后有了第二代GateWay&#xff0c;基于Reactor模型 异步非阻塞。 springcloud网关就是一…

机械革命Z2 键盘失灵

机械革命Z2 键盘特效配置完之后不要点存储&#xff0c;可能引起系统bug&#xff0c;导致键盘失灵。如果失灵&#xff0c;可以重新插一下电源排线&#xff0c;重启。 后记&#xff1a; 坚持了几天之后&#xff0c;还是没用的&#xff0c;售后换了键盘的排线问题消失。

怎么解决机械革命笔记本蓝屏问题

1、重启电脑&#xff0c;出现logo界面后连续按F2键直到打开bios&#xff0c;接着切换至“Advanced”&#xff0c;将光标移至“OS Support”选项&#xff0c;并将后面数值调成“Others”。 2、接下来将光标移至“SATA Device”选项&#xff0c;将硬盘模式调成“AHCI”。 3、最后…

机械革命 Code10参数配置 机械革命 Code10怎么样

恰逢 10 月 24 日程序员节&#xff0c;机械革命今日宣布&#xff0c;机械革命 Code10 将于 10 月 26 日正式到来。 机械革命 Code10 全新登场&#xff0c;1024 程序员节快乐&#xff01;我们 10 月 26 日见&#xff01;机械革命 Code10怎么样这些点很重要http://www.adiannao.c…