【前言】
你是否也曾羨慕過有些 phython 大神有著如下的神操作:

他們就輕輕的執(zhí)行一串代碼,就能循環(huán)的抓取很多自己想要的數(shù)據(jù)。
其實不用太羨慕他們,因為不光 phython 能實現(xiàn),我們用 JAVA 同樣也能夠輕松實現(xiàn)。
閑話不多說,下面我們直接開始實戰(zhàn):
【1】創(chuàng)建項目
(1.1)我們用 IDEA(Eclipse同理) 創(chuàng)建一個全新的maven工程,我這里取名工程名 zyqok,各位隨意。

(1.2)在 pom.xml 里面加上 <dependencies>

(1.3)創(chuàng)建 Test 類,好了工程就已經(jīng)搭好了。

【2】Httpclient 實現(xiàn)網(wǎng)絡(luò)請求
(2.1)什么是 httpclient ?
Httpclient 是 Apache 的一個子項目,它是一個為 Java 可以實現(xiàn)網(wǎng)絡(luò)請求的客戶端工具包。
簡單的說,他是一個 Jar 包,有了他,我們通過 Java 程序就可以實現(xiàn)網(wǎng)絡(luò)請求。
(2.2) 復(fù)制下面的 httpclient 依賴,加入到 pom.xml 文件中。
<!-- httpclient 核心包 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>

(2.3)創(chuàng)建一個 HttpTool 的類,這個類我們專門用來實現(xiàn)網(wǎng)絡(luò)請求相關(guān)方法。

(2.4) 為了避免其他網(wǎng)站侵權(quán)問題,下面以我個人網(wǎng)站一個頁面為例(http://www.zyqok.cn/material/index),我們來抓取這個頁面上的所有圖片。

(2.5) 可以看得出,這是一個 get 請求,并且返回的是一個 html 頁面。所以我們在 HttpTool 類中加入一個如下方法體:
/**
* 實現(xiàn)Get請求
* @param url 請求地址
* @return 頁面內(nèi)容
*/
public static String doGet(String url) {
return null;
}

(2.6)復(fù)制代碼,添加 get 實現(xiàn)方法:
// 構(gòu)建get請求
HttpGet get = new HttpGet(url);
// 創(chuàng)建客戶端
CloseableHttpClient client = HttpClients.createDefault();
try {
// 客戶端執(zhí)行請求,獲取響應(yīng)
HttpResponse response = client.execute(get);
// 獲取響應(yīng)的頁面內(nèi)容
InputStream in = response.getEntity().getContent();
StringBuilder sb = new StringBuilder();
byte[]b = new byte[102400];
int length;
while ((length = in.read(b)) != -1) {
sb.Append(new String(b, 0, length, "utf-8"));
}
// 返回頁面內(nèi)容
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}

(2.7)OK,網(wǎng)絡(luò)請求相關(guān)實現(xiàn)類我們已經(jīng)寫好了,我們接下來測試下,我們在 Test 類的 main 方法里加入如下代碼:
String html = HttpTool.doGet("http://www.zyqok.cn/material/index");
System.out.println(html);

(2.8)執(zhí)行程序,查看結(jié)果。可以看到我們確實已經(jīng)通過請求,獲取到網(wǎng)頁的返回內(nèi)容了。

【3】Jsoup 解析網(wǎng)頁
在整個【2】的實現(xiàn)過程中,我們已經(jīng)拿到網(wǎng)頁返回的數(shù)據(jù),但我們要的是整個網(wǎng)頁中的圖片,并不是這種雜亂無章的網(wǎng)頁頁面數(shù)據(jù),那么我們該怎么辦呢?簡單,接下來我們需要用到另外一種技術(shù)了 ---- Jsoup。
(3.1)什么是 Jsoup 技術(shù)?
下面是度娘給出的一個官方解釋:Jsoup 是一款Java 的HTML解析器,可直接解析某個URL地址、HTML文本內(nèi)容。它提供了一套非常省力的API,可通過DOM,css以及類似于jQuery的操作方法來取出和操作數(shù)據(jù)(摘自百度)。
下面再用我個人語言簡單的總結(jié)下:Jsoup 技術(shù)就是用來處理各種 html 頁面 和 xml 數(shù)據(jù)。我們這里可以通過 Jsoup 來處理【2】中返回的 html 頁面。
(3.2)加入 Jsoup 依賴
我們在 pom.xml 加入如下依賴:
<!-- Jsoup 核心包 -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>

(3.3)當(dāng)然,使用 Jsoup 之前,我們需要對響應(yīng)的 HTML 頁面進行分析,分析主要作用是:如何定位篩選出我們需要的數(shù)據(jù)?
我們把【2】中獲取到的頁面響應(yīng)拷貝到 txt 文本中,然后可以發(fā)現(xiàn):每個圖片它都包含在一個 div 中,且該div 有一個名為 material-div 的 class。

(3.4)按照上面分析:首先我們要獲取到包含圖片的所有 div,于是我們修改main方法中代碼為如下:
String html = HttpTool.doGet("http://www.zyqok.cn/material/index");
// 將 html 頁面解析為 Document 對象
Document doc = Jsoup.parse(html);
// 獲取所有包含 class = material-div 的 div 元素
Elements elements = doc.select("div.material-div");
for(Element div: elements){
System.out.println(div.toString());
}
注意:doc.select() 括號中的參數(shù)為過濾條件,基本等同于 Jquery 的過濾條件,所以會Jquery的同學(xué),如何篩選條件基本就得心應(yīng)手的,當(dāng)然不會寫篩選條件的也不要怕,這里有一份 Jsoup 使用指南,閣下不妨收下(傳送門:Jsoup 官方使用指南)。

(3.5)我們執(zhí)行代碼,將輸出結(jié)果繼續(xù)拷貝到文本中。
可以看到,本次確實只有圖片相關(guān)的div元素了,但這并不是我們想要的最終結(jié)果,我們最終的結(jié)果是獲取到所有圖片。
所以我們還需要繼續(xù)分析:如何獲取所有圖片的鏈接和名字。

(3.6)由于每個圖片所在的div元素結(jié)構(gòu)都一樣,所以我們可以取隨機取一個div元素進行分析,于是我們可以取第一個div來進行分析,結(jié)構(gòu)如下:
<div align="center" style="padding: 10px;" class="material-div">
<div style="width: 80px; height: 80px; margin-bottom: 3px; display: flex; align-items: center; justify-content: center">
<img class="fangda image" src="https://zyqok.oss-cn-chengdu.aliyuncs.com/20200414220946131_大樹夕陽.jpg">
<input type="hidden" class="materialId" value="121">
</div>
<font style="font-size: 5px">大樹夕陽.jpg</font><br>
<font style="font-size: 5px">2020-04-14 22:09:46</font>
</div>
3.7)我們可以看到,整個結(jié)構(gòu)內(nèi),就一個 img 元素標(biāo)簽,于是我們可以取第1個img標(biāo)簽的 src 屬性為圖片鏈接;同理,我們?nèi)〉?個 font 元素的文本內(nèi)容為圖片名稱。

(3.8)于是我們可以修改循環(huán)中的代碼內(nèi)容如下:
// 獲取第1個 img 元素Element img = div.selectFirst("img");// 獲取第1個 font 元素Element font = div.selectFirst("font");// 獲取img元素src屬性,即為圖片鏈接String url = img.attr("src");// 獲取name元素文本,即為圖片名稱String name = font.text();System.out.println(name + ": " + url);

(3.9)我們執(zhí)行上面代碼,可以得出如下結(jié)果。

可以看到,這個頁面上的所有圖片地址和名稱已經(jīng)被我們成功抓下來了。
【4】獲取圖片到本地
在第【3】步中,我們獲取到的只是所有圖片的鏈接,并沒有將所有圖片下載到我們本地,那么接下來,我們要將這個圖片下載到我們本地才算完成。
(4.1)既然要下載到本地,我們首先在本地找個地方,用于存放這些圖片。
比如:我將這圖片全部下載到 D:imgs(D 盤的 imgs 文件夾)中。

(4.2)我們在 HttpTool 類中增加保存圖片到本地的方法,代碼如下:
/**
* 保存圖片到本地
* @param src 圖片地址
* @param name 圖片名稱
*/
public static void saveImg(String src, String name) {
// 構(gòu)建get請求
HttpGet get = new HttpGet(src);
// 創(chuàng)建客戶端
CloseableHttpClient client = HttpClients.createDefault();
try {
// 客戶端執(zhí)行請求,獲取響應(yīng)
HttpResponse response = client.execute(get);
// 獲取響應(yīng)的頁面內(nèi)容
InputStream in = response.getEntity().getContent();
int length;
byte[] bytes = new byte[1024];
FileOutputStream fos = new FileOutputStream("D:\imgs\" + name);
while ((length = in.read(bytes)) != -1) {
fos.write(bytes, 0, length);
fos.flush();
}
in.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}

(4.3)修改 Test 類 main 方法最終代碼如下:
public static void main(String args[]) throws Exception {
String html = HttpTool.doGet("http://www.zyqok.cn/material/index");
// 將 html 頁面解析為 Document 對象
Document doc = Jsoup.parse(html);
// 獲取所有包含 class = material-div 的 div 元素
Elements elements = doc.select("div.material-div");
for (int i = 0; i<elements.size(); i++) {
Element div = elements.get(i);
// 獲取第1個 img 元素
Element img = div.selectFirst("img");
// 獲取第1個 font 元素
Element font = div.selectFirst("font");
// 獲取img元素src屬性,即為圖片鏈接
String src = img.attr("src");
// 獲取name元素文本,即為圖片名稱
String name = font.text();
if (!name.contains(".")) {
name += ".jpg";
}
HttpTool.saveImg(src, i + name);
System.out.println("抓取第 " + i + " 張圖片成功! 圖片名稱 : " + name);
}
System.out.println("所有圖片抓取完成 !!");
}

(4.4)執(zhí)行代碼,打印如下圖,看到這個結(jié)果,是不是感覺有點文章開頭的展示味道了。
最后,我們只需要去本地文件夾下看看,所有圖片是否成功保存到了本地?如果有圖片,則我們就成功了。

(4.5)我們打開D盤imgs文件夾,可以看到網(wǎng)站上的圖片確實已經(jīng)全部保存到本地了。

【5】結(jié)尾語
通過我們 [批量抓取網(wǎng)絡(luò)圖片] 這一實戰(zhàn)案例,我們可以感受到:通過 Httopclient 和 Jsoup 這兩種技術(shù),不僅僅可以批量抓取數(shù)據(jù),其實還可以實現(xiàn)很多功能。
比如:網(wǎng)站登錄,分布式服務(wù)器之間的數(shù)據(jù)傳遞,三方平臺的API對接,有效數(shù)據(jù)的篩選和保存,數(shù)據(jù)的二次加工等等。