網絡爬蟲,即網絡機器人或網頁spider。通常用來爬取網頁資料與資訊。随着蜘蛛自主爬行得越來越遠,其挖掘的資料也便越來越多。
在現今計算機界通常的認識是python實作網絡爬蟲有着得天獨厚的優勢,實作容易快捷,且挖掘效率高。然而随着Java語言的發展與完善,一批又一批Java開發者為Java實作網絡爬蟲構造了諸多架構與jar包。這其中就包括heritrix,crawler4j等。
Java實作網絡爬蟲,說大不大,說小不小。小到隻需要使用Java SE中的net包即可實作,大到需要使用樸素貝葉斯等機器學習算法實作。
學習使用Java開發網絡爬蟲的筒子們通常學到的第一課就是使用一個java.net.URL去下載下傳網頁源代碼,然後再用輸入流将爬取到的資訊寫入檔案中。然而盡管java.net包提供了通過HTTP通路資源的基本功能,但它沒有提供全面的靈活性和套接字、連接配接池等開發爬蟲需要的功能。
是以在實際開發中通常使用HttpClient下載下傳網頁,用Jsoup解析網頁。
HttpClient擷取網頁内容的過程:
1. 建立一個CloseableHttpClient類的執行個體
2. 使用這個執行個體執行HTTP請求,得到一個HttpResponse的執行個體
3. 通過HttpResponse的執行個體得到傳回的二進制流,二進制流封裝在HttpEntity中
4. 根據指定的字元集把二進制流轉成字元串,完成下載下傳
public static String downloadPage(String url) throws IOException{
String content = null;
//建立一個用戶端,類似于打開一個浏覽器
//CloseableHttpClient httpclient = HttpClientBuilder.create().builder();
DefaultHttpClient httpclient = new DefaultHttpClient();
//建立一個GET方法,類似于在浏覽器位址欄中輸入一個位址
HttpGet httpget = new HttpGet(url);
//類似于在浏覽器位址欄中輸入回車,獲得網頁内容
HttpResponse response = httpclient.execute(httpget);
//檢視傳回的内容,類似于在浏覽器檢視源代碼
HttpEntity entity = response.getEntity();
if(entity != null){
//讀入内容流,并以字元串形式傳回,這裡指定網頁編碼是UTF-8
content = EntityUtils.toString(entity,"utf-8");
EntityUtils.consume(entity); //關閉内容流
}
//釋放連接配接
httpclient.getConnectionManager().shutdown();
return content;
}
Jsoup是一個功能十分強大的Java的HTML解析器,它支援使用DOM來查找、取出資料,也可以使用CSS選擇器來查找、取出資料,還提供了類似于JQuery的操作方法來取出和操作資料。隻需要一個jsoup.jar包即可。
String url = "http://www.baidu.com";
Document doc = Jsoup.connect(url).get(); //解析的結果就是一個文檔對象
Elements links = doc.select("a[href]"); //帶有href屬性的a标簽
for(Element link: links){ //周遊每個連結
String linkHref = link.attr("href"); //得到href屬性中的值,也就是URL位址
String linkText = link.text(); //得到錨點上的文字說明
System.out.println(linkHref+" "+linkText); //輸出URL位址和錨點上的文字說明
}
當然,在Jsoup進行URL連接配接時可以進行連接配接參數的設定
Document doc = Jsoup.connect("http://www.lietu.com/")
.data("query","Java") //請求參數
.userAgent("jsoup") //設定User-Agent
.Cookie("auth","token") //設定Cookie
.timeout(3000) //設定連接配接逾時時間
.post(); //使用POST方法通路URL
如果遇到超連結中還有超連結,需要依次爬取的情況,隻需封裝後遞歸調用即可
public static void extractList(String url) throws IOException{
Document doc = Jsoup.connect(url).get(); //解析的結果就是一個文檔對象
Elements links = doc.select("a[href]"); //帶有href屬性的a标簽
for(Element link: links){ //周遊每個連結
String linkHref = link.attr("href"); //得到href屬性中的值,也就是URL位址
if(linkHref.startsWith("http://list.xiu.com/") || linkHref.startsWith("http://brand.xiu.com/")){
if(urlSeen.contains(linkHref))
continue;
extractList(linkHref); //遞歸調用
}else if(linkHref.startsWith("http://item.xiu.com/product/")){
if(urlSeen.contains(linkHref))
continue;
getProduct(linkHref); //提取詳細頁中的商品資訊
}
}
}
Jsoup.connect下載下傳網頁非常友善簡潔,但是沒有多次重試的功能,是以可以使用HttpClient下載下傳網頁後把字元串傳給Jsoup解析。
模式:HttpClient實作下載下傳網頁,用Jsoup解析網頁。
String url = "http://www.baidu.com";
String content = HttpUtil.getContent(url);
Document doc = Jsoup.parse(content);
一般來說,還是建議先将網頁中下載下傳的資料存儲入資料庫中,再從資料庫中提取資料。
按照上述流程,即可構造出一個簡易的網絡爬蟲。