Java爬蟲: 爬取京東上的手機搜索頁面 HttpClient+Jsoup

 1.需求及配置

需求:爬取京東手機搜索頁面的信息,記錄各手機的名稱,價格,評論數等,造成一個可用於實際分析的數據表格。java

使用Maven項目,log4j記錄日誌,日誌僅導出到控制檯。node

Maven依賴以下(pom.xml)apache

 1   <dependencies>
 2         <dependency>
 3             <groupId>org.apache.httpcomponents</groupId>
 4             <artifactId>httpclient</artifactId>
 5             <version>4.5.3</version>
 6         </dependency>
 7 
 8         <dependency>
 9           <!-- jsoup HTML parser library @ https://jsoup.org/ -->
10           <groupId>org.jsoup</groupId>
11           <artifactId>jsoup</artifactId>
12           <version>1.11.2</version>
13         </dependency>
14 
15           <!-- https://mvnrepository.com/artifact/log4j/log4j -->
16         <dependency>
17             <groupId>log4j</groupId>
18             <artifactId>log4j</artifactId>
19             <version>1.2.17</version>
20         </dependency>
21   </dependencies>

 

log4j配置(log4j.properties),將INFO及以上等級信息輸出到控制檯,不單獨設置輸出文檔。app

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需求分析

第一步,創建客戶端與服務端的鏈接,並經過URL得到網頁上的HTML內容。工具

第二步,解析HTML內容,獲取須要的元素。網站

第三步,將HTML內容輸出到本地的文本文檔中,可直接經過其餘數據分析軟件進行分析。ui

根據以上分析,創建4個類,GetHTML(用於獲取網站HTML), ParseHTML(用於解析HTML), WriteTo(用於輸出文檔), Maincontrol(主控).下面分別對四個類進行說明。爲使代碼儘可能簡潔,全部的異常均從方法上直接拋出,不catch。編碼

2.2代碼

2.2.1GetHTML類

該類包含兩個方法:getH(String url), urlControl(String baseurl, int page),分別用於獲取網頁HTML及控制URL。因爲這次爬取的網頁內容只是京東上某一類商品的搜索結果,因此不須要對頁面上全部的URL進行遍歷,只須要觀察翻頁時URL的變化,推出規律便可。只向外暴露urlControl方法,類中設置一個private的log屬性:private static Logger log = Logger.getLogger(getHTML.class); 用於記錄日誌。url

getH(String url),對單個URL的HTML內容進行獲取。spa

urlControl(String baseurl, int page),設置循環,訪問多個頁面的數據。經過審查元素能夠看到京東上搜索頁page的變化實際是奇數順序的變化。

再看一下點擊後網址的變化,能夠發現實際變化的是page屬性的值。經過拼接的方式就能夠很的容易的得到下一個網頁的地址。

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

總體代碼:

 1 import java.io.IOException;  2 import org.apache.http.HttpEntity;  3 import org.apache.http.client.ClientProtocolException;  4 import org.apache.http.client.methods.CloseableHttpResponse;  5 import org.apache.http.client.methods.HttpGet;  6 import org.apache.http.impl.client.CloseableHttpClient;  7 import org.apache.http.impl.client.HttpClients;  8 import org.apache.http.util.EntityUtils;  9 import org.apache.log4j.Logger; 10 
11 public class getHTML { 12     //創建日誌
13     private static Logger log = Logger.getLogger(getHTML.class); 14     private static String getH(String url) throws ClientProtocolException, IOException { 15         //控制檯輸出日誌,這樣每條訪問的URL均可以在控制檯上看到訪問狀況
16         log.info("正在解析" + url); 17         
18         /* 
19  * 如下內容爲HttpClient創建鏈接的通常用法 20  * 使用HttpClient創建客戶端 21  * 使用get方法訪問指定URL 22  * 得到應答 23  * */
24         
25         CloseableHttpClient client = HttpClients.createDefault(); 26         HttpGet get = new HttpGet(url); 27         CloseableHttpResponse response = client.execute(get); 28         
29         /*
30  * 如下內容爲將HTML內容轉化爲String 31  * 得到應答體 32  * 將應答體轉爲String格式,此處使用了EntityUtils中的toString方法,編碼格式設置爲"utf-8" 33  * 完成後關閉客戶端與應答 34  * */
35         HttpEntity entity = response.getEntity(); 36  String content; 37         if (entity != null) { 38             content = EntityUtils.toString(entity, "utf-8"); 39  client.close(); 40  response.close(); 41             return content; 42         } else
43             return null; 44  } 45     public static void urlControl(String baseurl, int page) throws ClientProtocolException, IOException { 46         //設置當前頁count
47         int count = 1; 48         //若是當前頁小於想要爬取的頁數則執行
49         while (count < page) { 50             //實際訪問的URL爲不變的URL值拼接上URL變化的值
51             String u = baseurl + (2 * count - 1) + "&click=0"; 52             //此處調用ParseHTML類中的方法對URL中的HTML頁面進行處理,後面詳細介紹該類
53             String content = ParseHTML.parse(getH(u)).toString(); 54             //此處調用WriteTo類中的方法對解析出來的內容寫入到本地,後面詳細介紹該類
55  WriteTo.writeto(content); 56             count++; 57  } 58  } 59 }

 

 2.2.2ParseHTML類

該步驟須要經過審查元素對須要爬取內容的標籤進行肯定,再經過Jsoup中的CSS選擇器進行獲取。

 1 import org.jsoup.Jsoup;  2 import org.jsoup.nodes.Document;  3 import org.jsoup.nodes.Element;  4 import org.jsoup.select.Elements;  5 
 6 public class ParseHTML {  7     
 8     public static StringBuilder parse(String content)  9  { 10         //使用Jsoup中的parse方法對已經轉換爲String的HTML內容進行分析,返回值爲Document類
11         Document doc = Jsoup.parse(content); 12         //使用選擇器select對須要找的元素進行抓取,例如第一個select中選擇的是ul標籤中class屬性等於gl-warp clearfix的內容
13         Elements ele = doc.select("ul[class = gl-warp clearfix]").select("li[class=gl-item]"); 14         //設置一個容器,用於裝各個屬性
15         StringBuilder sb = new StringBuilder(); 16         //經過上一個選擇器能夠得到整個頁面中全部符合要求的元素,也即各款手機,下面則須要對每款手機進行遍歷,獲取其屬性
17         for (Element e : ele) { 18             //此處對各個屬性的獲取參考了網上一篇爬取京東上內容的文章,應該有其餘不一樣的寫法
19             String id = e.attr("data-pid"); 20             String mingzi = e.select("div[class = p-name p-name-type-2]").select("a").select("em").text(); 21             String jiage = e.select("div[class=p-price]").select("strong").select("i").text(); 22             String pinglun  = e.select("div[class=p-commit]").select("strong").select("a").text(); 23             //向容器中添加屬性
24             sb.append(id+"\t"); 25             sb.append(mingzi+"\t"); 26             sb.append(jiage+"\t"); 27             sb.append(pinglun+"\t"); 28             sb.append("\r\n"); 29  } 30         return sb; 31  } 32 }

 

2.2.3WriteTo類

此類中的方法將解析完成的內容寫入到一個本地文件中。只是簡單的IO。

 1 import java.io.BufferedWriter;  2 import java.io.File;  3 import java.io.FileWriter;  4 import java.io.IOException;  5 
 6 public class WriteTo {  7     // 設置文件存放的位置
 8     private static File f = new File("C:\\jingdong.txt");  9     public static void writeto(String content) throws IOException { 10         //使用續寫的方式,以避免覆蓋前面寫入的內容
11         BufferedWriter bw = new BufferedWriter(new FileWriter(f, true)); 12  bw.append(content); 13  bw.flush(); 14  bw.close(); 15  } 16 }

 

2.2.4MainControl類

主控程序,寫入基地址與想要獲取的頁面數。調用getHTML類中的urlControl方法對頁面進行抓取。

 1 import java.io.IOException;  2 import org.apache.http.client.ClientProtocolException;  3 
 4 public class MainControl {  5     public static void main(String[] args) throws ClientProtocolException, IOException {  6         // TODO Auto-generated method stub
 7         String baseurl = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc="
 8                 + "utf-8&qrst=1&rt=1&stop=1&vt=2&cid2=653&cid3=655&page=";  9         int page = 5;//設置爬取頁數 10  getHTML.urlControl(baseurl, page); 11  } 12 }

 

3爬取結果

爬取20頁。

3.1控制檯輸出

3.2文檔輸出

能夠直接使用Excel打開,分隔符爲製表符。列分別爲商品編號,名稱,價格與評論數。

 

4小結

這次爬取使用了HttpClient與Jsoup,能夠看到對於簡單的需求,這些工具仍是很是高效的。實際上也能夠把全部類寫到一個類當中,寫多個類的方式思路比較清晰。

相關文章
相關標籤/搜索