Java爬蟲實現(xiàn)爬取京東上的手機搜索頁面 HttpCliient+Jsoup
1、需求及配置
需求:爬取京東手機搜索頁面的信息,記錄各手機的名稱,價格,評論數(shù)等,形成一個可用于實際分析的數(shù)據(jù)表格。

使用Maven項目,log4j記錄日志,日志僅導(dǎo)出到控制臺。
Maven依賴如下(pom.xml)
<dependencies> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency> <dependency> <!-- jsoup HTML parser library @ https://jsoup.org/ --> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.11.2</version> </dependency> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>
log4j配置(log4j.properties),將INFO及以上等級信息輸出到控制臺,不單獨設(shè)置輸出文檔。
log4j.rootLogger=INFO, Console #Console log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
2、需求分析與代碼
2.1需求分析
第一步,建立客戶端與服務(wù)端的連接,并通過URL獲得網(wǎng)頁上的HTML內(nèi)容。
第二步,解析HTML內(nèi)容,獲取需要的元素。
第三步,將HTML內(nèi)容輸出到本地的文本文檔中,可直接通過其他數(shù)據(jù)分析軟件進行分析。
根據(jù)以上分析,建立4個類,GetHTML(用于獲取網(wǎng)站HTML), ParseHTML(用于解析HTML), WriteTo(用于輸出文檔), Maincontrol(主控).下面分別對四個類進行說明。為使代碼盡量簡潔,所有的異常均從方法上直接拋出,不catch。
2.2代碼
2.2.1GetHTML類
該類包含兩個方法:getH(String url), urlControl(String baseurl, int page),分別用于獲取網(wǎng)頁HTML及控制URL。由于此次爬取的網(wǎng)頁內(nèi)容只是京東上某一類商品的搜索結(jié)果,所以不需要對頁面上所有的URL進行遍歷,只需要觀察翻頁時URL的變化,推出規(guī)律即可。只向外暴露urlControl方法,類中設(shè)置一個private的log屬性:private static Logger log = Logger.getLogger(getHTML.class); 用于記錄日志。
getH(String url),對單個URL的HTML內(nèi)容進行獲取。
urlControl(String baseurl, int page),設(shè)置循環(huán),訪問多個頁面的數(shù)據(jù)。通過審查元素可以看到京東上搜索頁page的變化實際是奇數(shù)順序的變化。

再看一下點擊后網(wǎng)址的變化,可以發(fā)現(xiàn)實際變化的是page屬性的值。通過拼接的方式就可以很的容易的獲得下一個網(wǎng)頁的地址。
https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&cid2=653&cid3=655&page=3&s=47&click=0
https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&cid2=653&cid3=655&page=5&s=111&click=0
https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&cid2=653&cid3=655&page=7&s=162&click=0
整體代碼:
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
public class getHTML {
//建立日志
private static Logger log = Logger.getLogger(getHTML.class);
private static String getH(String url) throws ClientProtocolException, IOException {
//控制臺輸出日志,這樣每條訪問的URL都可以在控制臺上看到訪問情況
log.info("正在解析" + url);
/*
* 以下內(nèi)容為HttpClient建立連接的一般用法
* 使用HttpClient建立客戶端
* 使用get方法訪問指定URL
* 獲得應(yīng)答
* */
CloseableHttpClient client = HttpClients.createDefault();
HttpGet get = new HttpGet(url);
CloseableHttpResponse response = client.execute(get);
/*
* 以下內(nèi)容為將HTML內(nèi)容轉(zhuǎn)化為String
* 獲得應(yīng)答體
* 將應(yīng)答體轉(zhuǎn)為String格式,此處使用了EntityUtils中的toString方法,編碼格式設(shè)置為"utf-8"
* 完成后關(guān)閉客戶端與應(yīng)答
* */
HttpEntity entity = response.getEntity();
String content;
if (entity != null) {
content = EntityUtils.toString(entity, "utf-8");
client.close();
response.close();
return content;
} else
return null;
}
public static void urlControl(String baseurl, int page) throws ClientProtocolException, IOException {
//設(shè)置當(dāng)前頁count
int count = 1;
//如果當(dāng)前頁小于想要爬取的頁數(shù)則執(zhí)行
while (count < page) {
//實際訪問的URL為不變的URL值拼接上URL變化的值
String u = baseurl + (2 * count - 1) + "&click=0";
//此處調(diào)用ParseHTML類中的方法對URL中的HTML頁面進行處理,后面詳細(xì)介紹該類
String content = ParseHTML.parse(getH(u)).toString();
//此處調(diào)用WriteTo類中的方法對解析出來的內(nèi)容寫入到本地,后面詳細(xì)介紹該類
WriteTo.writeto(content);
count++;
}
}
}
2.2.2ParseHTML類
該步驟需要通過審查元素對需要爬取內(nèi)容的標(biāo)簽進行確定,再通過Jsoup中的CSS選擇器進行獲取。
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class ParseHTML {
public static StringBuilder parse(String content)
{
//使用Jsoup中的parse方法對已經(jīng)轉(zhuǎn)換為String的HTML內(nèi)容進行分析,返回值為Document類
Document doc = Jsoup.parse(content);
//使用選擇器select對需要找的元素進行抓取,例如第一個select中選擇的是ul標(biāo)簽中class屬性等于gl-warp clearfix的內(nèi)容
Elements ele = doc.select("ul[class = gl-warp clearfix]").select("li[class=gl-item]");
//設(shè)置一個容器,用于裝各個屬性
StringBuilder sb = new StringBuilder();
//通過上一個選擇器可以獲得整個頁面中所有符合要求的元素,也即各款手機,下面則需要對每款手機進行遍歷,獲取其屬性
for (Element e : ele) {
//此處對各個屬性的獲取參考了網(wǎng)上一篇爬取京東上內(nèi)容的文章,應(yīng)該有其他不同的寫法
String id = e.attr("data-pid");
String mingzi = e.select("div[class = p-name p-name-type-2]").select("a").select("em").text();
String jiage = e.select("div[class=p-price]").select("strong").select("i").text();
String pinglun = e.select("div[class=p-commit]").select("strong").select("a").text();
//向容器中添加屬性
sb.append(id+"\t");
sb.append(mingzi+"\t");
sb.append(jiage+"\t");
sb.append(pinglun+"\t");
sb.append("\r\n");
}
return sb;
}
}
2.2.3WriteTo類
此類中的方法將解析完成的內(nèi)容寫入到一個本地文件中。只是簡單的IO。
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class WriteTo {
// 設(shè)置文件存放的位置
private static File f = new File("C:\\jingdong.txt");
public static void writeto(String content) throws IOException {
//使用續(xù)寫的方式,以免覆蓋前面寫入的內(nèi)容
BufferedWriter bw = new BufferedWriter(new FileWriter(f, true));
bw.append(content);
bw.flush();
bw.close();
}
}
2.2.4MainControl類
主控程序,寫入基地址與想要獲取的頁面數(shù)。調(diào)用getHTML類中的urlControl方法對頁面進行抓取。
import java.io.IOException;
import org.apache.http.client.ClientProtocolException;
public class MainControl {
public static void main(String[] args) throws ClientProtocolException, IOException {
// TODO Auto-generated method stub
String baseurl = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc="
+ "utf-8&qrst=1&rt=1&stop=1&vt=2&cid2=653&cid3=655&page=";
int page = 5;//設(shè)置爬取頁數(shù)
getHTML.urlControl(baseurl, page);
}
}
3、爬取結(jié)果
爬取20頁。
3.1控制臺輸出

3.2文檔輸出
可以直接使用Excel打開,分隔符為制表符。列分別為商品編號,名稱,價格與評論數(shù)。

4、小結(jié)
此次爬取使用了HttpClient與Jsoup,可以看到對于簡單的需求,這些工具還是非常高效的。實際上也可以把所有類寫到一個類當(dāng)中,寫多個類的方式思路比較清晰。
以上這篇Java爬蟲實現(xiàn)爬取京東上的手機搜索頁面 HttpCliient+Jsoup就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring WebFlux使用函數(shù)式編程模型構(gòu)建異步非阻塞服務(wù)
這篇文章主要介紹了Spring WebFlux使用函數(shù)式編程模型構(gòu)建異步非阻塞服務(wù),重點介紹如何使用函數(shù)式編程模型創(chuàng)建響應(yīng)式 RESTful 服務(wù),這種編程模型與傳統(tǒng)的基于 Spring MVC 構(gòu)建 RESTful 服務(wù)的方法有較大差別,感興趣的朋友跟隨小編一起看看吧2023-08-08
SpringBoot使用Logback進行日志記錄的代碼示例
在開發(fā)Web應(yīng)用程序時,日志記錄是非常重要的一部分,在SpringBoot中,我們可以使用Logback進行日志記錄,Logback是一款高性能、靈活的日志框架,它可以滿足各種不同的日志需求,在本文中,我們介紹了如何在SpringBoot中使用Logback進行日志記錄2023-06-06
基于MockMvc進行springboot調(diào)試(SpringbootTest)
這篇文章主要介紹了基于MockMvc進行springboot調(diào)試(SpringbootTest),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10
Java調(diào)度線程池ScheduledThreadPoolExecutor不執(zhí)行問題分析
最近項目上反饋某個重要的定時任務(wù)突然不執(zhí)行了,很頭疼,開發(fā)環(huán)境和測試環(huán)境都沒有出現(xiàn)過這個問題。定時任務(wù)采用的是ScheduledThreadPoolExecutor,后來一看代碼發(fā)現(xiàn)踩了一個大坑。本文就來和大家聊聊這次的踩坑記錄與解決方法,需要的可以參考一下2023-03-03
關(guān)于SpringBoot配置項的優(yōu)先級,不再有配置不生效的問題
這篇文章主要介紹了關(guān)于SpringBoot配置項的優(yōu)先級,不再有配置不生效的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04
Spring實戰(zhàn)之使用@Resource配置依賴操作示例
這篇文章主要介紹了Spring實戰(zhàn)之使用@Resource配置依賴操作,結(jié)合實例形式分析了Spring使用@Resource配置依賴具體步驟、實現(xiàn)及測試案例,需要的朋友可以參考下2019-12-12
Springboot整合企業(yè)微信機器人助手推送消息的實現(xiàn)
本文主要介紹了Springboot整合企業(yè)微信機器人助手推送消息的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
java?poi之XWPFDocument如何讀取word內(nèi)容并創(chuàng)建新的word
這篇文章主要介紹了java?poi之XWPFDocument如何讀取word內(nèi)容并創(chuàng)建新的word問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04
java迭代器移除元素出現(xiàn)并發(fā)修改異常的原因及解決
這篇文章主要介紹了java迭代器移除元素出現(xiàn)并發(fā)修改異常的原因及解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12

