隨著互聯網+時代的來臨,越來越多的互聯網企業層出不窮,涉及游戲、視頻、新聞、社交、電商、房產、旅游等眾多行業。如今互聯網成為大量信息的載體,如何有效地從中提取有價值的信息并利用這些信息成為一個巨大的挑戰
爬蟲,一個可怕的怪物,從百度、Google等搜索引擎公司誕生開始便有了它的身影,如今移動互聯網時代爬蟲更是猖狂,每個網站似乎都被它光顧過,只是你看不到,不過你放心它不干壞事,你能在網上迅速搜索到你到的信息應該都是它的功勞,它每天會默默無聞的采集互聯網上的豐富信息供大家查詢共享。Java作為互聯網開發的主流語言,廣泛應用于互聯網領域,本課程使用java技術為大家講解如何編寫爬蟲程序爬取網絡上有價值的數據信息。
知識點
- 爬蟲的架構解析
- 爬蟲基本原理分析
- 編寫爬蟲程序
- 爬蟲在電商中的應用
1. 爬蟲簡介
我們訪問某一個網頁的時候,在地址欄輸入網址,按回車,該網站的服務器就會返回一個HTML文件給我們,瀏覽器解析返回的數據,展示在UI上。同樣爬蟲程序也是模仿人的操作,給網站發送一個請求,網站會給爬蟲程序返回一個HTML文件,爬蟲程序再根據返回的數據進行抓取分析
1.1 爬蟲概論
網絡爬蟲(Web crawler)也叫網絡蜘蛛(Web spide)自動檢索工具(automatic indexer),是一種”自動化瀏覽網絡“的程序,或者說是一種網絡機器人。
爬蟲被廣泛用于互聯網搜索引擎或其他類似網站,以獲取或更新這些網站的內容和檢索方式。它們可以自動采集所有其能夠訪問到的頁面內容,以供搜索引擎做進一步處理(分檢整理下載的頁面),而使得用戶能更快的檢索到他們需要的信息。
通俗的講,就是把你手動打開窗口,輸入數據等等操作用程序代替。用程序替你獲取你想要的信息,這就是網絡爬蟲
1.2 爬蟲應用
1.2.1 搜索引擎
爬蟲程序可以為搜索引擎系統爬取網絡資源,用戶可以通過搜索引擎搜索網絡上一切所需要的資源。搜索引擎是一套非常龐大且精密的算法系統,搜索的準確性,高效性等都對搜索系統有很高的要求。
1.2.2 數據挖掘
爬蟲除了用來做搜索外,還可以做非常多的工作,可以說爬蟲現在在互聯網項目中應用的非常廣泛。
互聯網項目通過爬取相關數據主要進行數據分析,獲取價值數據。那么爬蟲具體可以做那么分析,下面可以簡單做一個簡單了解:
- 股票分析---預測股市
- 社會學方面統計預測
- 情緒地圖
- 飲食分布圖
- 票房分析預測
- 機場實時流量
- 公交系統實時線路
- 火車票實時銷售統計
- App下載量分析
1.3 爬蟲原理
1.3.1 爬蟲目的
一般來講對我們而言需要抓取的是某個網站或者某個應用的內容,提取有用的價值,進行數據分析。
1.3.2 爬蟲框架設計
為了開發的方便,也可以使用爬蟲框架來開發項目中的爬蟲;一個通用的網絡爬蟲的框架如圖所示:
網絡爬蟲的基本工作流程如下:
- 首先選取一部分精心挑選的種子URL
- 將這些URL放入待抓取URL隊列
- 從待抓取URL隊列中取出待抓取在URL,解析DNS,并且得到主機的ip,并將URL對應的網頁下載下來,存儲進已下載網頁庫中。此外,將這些URL放進已抓取URL隊列
- 分析已抓取URL隊列中的URL,分析其中的其他URL,并且將URL放入待抓取URL隊列,從而進入下一個循環
2. Java爬蟲框架
2.1 Nutch
Nutch屬于分布式爬蟲,爬蟲使用分布式,主要是解決兩個問題:1)海量URL管理;2)網速。如果要做搜索引擎,Nutch1.x是一個非常好的選擇。Nutch1.x和solr或者es配合,就可以構成一套非常強大的搜索引擎,否則盡量不要選擇Nutch作為爬蟲。用Nutch進行爬蟲的二次開發,爬蟲的編寫和調試所需的時間,往往是單機爬蟲所需的十倍時間不止。
2.2 Heritrix
Heritrix 是個“Archival Crawler”——來獲取完整的、精確的、站點內容的深度復制。包括獲取圖像以及其他非文本內容。抓取并存儲相關的內容。對內容來者不拒,不對頁面進行內容上的修改。重新爬行對相同的URL不針對先前的進行替換。爬蟲主要通過Web用戶界面啟動、監控和調整,允許彈性的定義要獲取的url。
2.3 crawler4j
crawler4j是Java實現的開源網絡爬蟲。提供了簡單易用的接口,可以在幾分鐘內創建一個多線程網絡爬蟲。
2.4 WebCollector
WebCollector使用了Nutch的爬取邏輯(分層廣度遍歷),Crawler4j的的用戶接口(覆蓋visit方法,定義用戶操作),以及一套自己的插件機制,設計了一套爬蟲內核。
2.5 WebMagic
WebMagic項目代碼分為核心和擴展兩部分。核心部分(webmagic-core)是一個精簡的、模塊化的爬蟲實現,而擴展部分則包括一些便利的、實用性的功能。WebMagic的架構設計參照了Scrapy,目標是盡量的模塊化,并體現爬蟲的功能特點。
3. HttpClient&Jsoup
爬蟲實現的技術有很多,對于java語言來說,有很多的選擇,可以是很多開源的爬蟲框架,也可以使用基本httpClient,Jsoup來爬取網頁
3.1 HttpClient簡介
HttpClient 是 apache 組織下面的一個用于處理 HTTP 請求和響應的開源工具。它不是一個瀏覽器,也不處理客戶端緩存等瀏覽器的功能。它只是一個類庫!它在 JDK 的基本類庫基礎上做了更好的封裝。
HttpClient 項目依賴于 HttpCore(處理核心的 HTTP 協議)、commons-codec(處理與編碼有關的問題的項目)和 commons-logging(處理與日志記錄有關問題的項目)。如果你希望能夠通過 HttpClient 向服務器上傳文件等與 multipart 編碼類型有關的請求,以及其它復雜的MIME 類型,那么,你需要另外一個依賴包:HttpMime(它是專門處理與 MIME 類型有關問題的項目),在下載的 HttpClient 包中(下載地址)已經包含了 HttpMime
項目中使用的 HttpClient 版本為:4.0.1GA,httpClient需要有以下依賴包:
- httpclient-4.0.1.jar
- httpcore-4.0.1.jar
- httpmime-4.0.1.jar
又依賴于 mime4j(apache-mime4j-0.6.jar)
- commons-codec-1.4.jar
- commons-logging-1.1.1.jar
- commons-io-1.4.jar – 為了更方便處理與 IO 有關的需求
3.2 HttpClient抓取網頁流程
使用HttpClient發送請求、接收響應很簡單,一般需要如下幾步:
- 創建HttpClient對象。
- 創建請求方法的實例,并指定請求URL。如果需要發送GET請求,創建HttpGet對象;如果需要發送POST請求,創建HttpPost對象。
- 如果需要發送請求參數,可調用HttpGet、HttpPost共同的setParams(HetpParams params)方法來添加請求參數;對于HttpPost對象而言,也可調用setEntity(HttpEntity entity)方法來設置請求參數。
- 調用HttpClient對象的execute(HttpUriRequest request)發送請求,該方法返回一個HttpResponse。
- 調用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可獲取服務器的響應頭;調用HttpResponse的getEntity()方法可獲取HttpEntity對象,該對象包裝了服務器的響應內容。程序可通過該對象獲取服務器的響應內容。
- 釋放連接。無論執行方法是否成功,都必須釋放連接。
3.3 簡單抓取代碼
用HttpClient發送請求,請求頭不帶cookie,用EntityUtils解析響應結果
public class MyHttpClient {
/***
* 需求:使用httpClient爬取傳智播客官方網站數據
*
* @param args
* @throws Exception
* @throws ClientProtocolException
*/
public static void main(String[] args) throws Exception {
// 創建HttpClient對象
HttpClient hClient = new DefaultHttpClient();
// 設置響應時間,設置傳智源碼時間,設置代理服務器(不使用本機的IP爬取,以防止被服務器識別從而IP加入黑名單)
hClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000)
.setParameter(CoreConnectionPNames.SO_TIMEOUT, 10000)
.setParameter(ConnRouteParams.DEFAULT_PROXY, new HttpHost("111.155.124.67", 8123));
// 爬蟲URL大部分都是get請求,創建get請求對象
HttpGet hget = new HttpGet("http://www.itcast.cn/");
// 向傳智播客官方網站發送請求,獲取網頁源碼
HttpResponse response = hClient.execute(hget);
// EntityUtils工具類把網頁實體轉換成字符串
String content = EntityUtils.toString(response.getEntity(), "utf-8");
System.out.println(content);
}
}
解析結果
用HttpClient發送請求,請求頭帶cookie,用EntityUtils解析響應結果
//使用httpClient發送請求,使用Jsoup分析網頁
public static void main(String[] args) throws Exception {
//創建httpClient客戶端
HttpClient hClient = new DefaultHttpClient();
//創建http發送請求對象,Httpget
HttpGet hget = new HttpGet("http://www.itcast.cn");
//設置請求頭
hget.setHeader("Cookie", "login_sid_t=f39c57f474a4fbffeeac8b0d727c7310; " +
"YF-Ugrow-G0=169004153682ef91866609488943c77f; " +
"YF-V5-G0=cd5d86283b86b0d506628aedd6f8896e; WBStorage=7754ff192036c629|undefined;" +
" _s_tentry=-; YF-Page-G0=074bd03ae4e08433ef66c71c2777fd84; " +
"Apache=1025338456965.9829.1478277156276; " +
"SINAGLOBAL=1025338456965.9829.1478277156276; " +
"ULV=1478277156293:1:1:1:1025338456965.9829.1478277156276:; " +
"SUB=_2AkMvQDcef8NhqwJRmP4Uzm7mbYxwzA_EieLBAH7sJRMxHRl" +
"-yj9jqmwNtRBn0SIxPIgzk6P4Umq_twX_A70bVg..; " +
"SUBP=0033WrSXqPxfM72-Ws9jqgMF55529P9D9W5J2ZDKK_Q-h8ni.aX3E1Ci");
hget.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 " +
"(KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36");
//設置連接超時,傳遞響應超時
hClient.getParams()
.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000)
.setParameter(CoreConnectionPNames.SO_TIMEOUT, 10000)
.setParameter(ConnRouteParams.DEFAULT_PROXY, new HttpHost("121.31.71.63", 80));
//發送請求
HttpResponse response = hClient.execute(hget);
//獲取網頁內容
String content = EntityUtils.toString(response.getEntity(), "utf-8");
System.out.println(content);
}
4. Jsoup簡介
jsoup 是一款Java 的HTML解析器,可直接解析某個URL地址、HTML文本內容。它提供了一套非常省力的API,可通過DOM,CSS以及類似于jQuery的操作方法來取出和操作數據
通常在寫爬蟲程序時,httpClient結合Jsoup共同使用即可實現完美的爬蟲系統。httpClient負責模擬瀏覽器發送請求,Jsoup負責解析httpClient請求返回的HTML頁面,解析獲取需要的數據
4.1 Jsoup獲取網頁流程
- 從一個 URL,文件或字符串中解析 HTML
- 使用 DOM 或 CSS 選擇器來查找、取出數據
- 可操作 HTML 元素、屬性、文本
4.2 Jsoup獲取網頁代碼
用Jsoup抓取傳智播客官網左側的數據,如圖所示
用谷歌瀏覽器開發者工具(F12)打開查看源碼如下圖,從中可以看到ul標簽的class選擇器為nav_txt
public class HttpClientJsoup {
/***
* 需求:使用httpClient爬取傳智播客官方網站數據
*
* @param args
* @throws Exception
* @throws ClientProtocolException
*/
public static void main(String[] args) throws Exception {
// 創建HttpClient對象
HttpClient hClient = new DefaultHttpClient();
// 設置響應時間,設置傳智源碼時間,設置代理服務器
/*hClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000)
.setParameter(CoreConnectionPNames.SO_TIMEOUT, 10000)
.setParameter(ConnRouteParams.DEFAULT_PROXY, new HttpHost("111.155.124.67", 8123));*/
// 爬蟲URL大部分都是get請求,創建get請求對象
HttpGet hget = new HttpGet("http://www.itcast.cn/");
hget.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 " +
"(KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36");
// 向傳智播客官方網站發送請求,獲取網頁源碼
HttpResponse response = hClient.execute(hget);
// EntityUtils工具類把網頁實體轉換成字符串
String content = EntityUtils.toString(response.getEntity(), "utf-8");
// 使用Jsoup解析網頁內容
Document document = Jsoup.parse(content);
// 獲取文檔標題
String title = document.title();
System.out.println(title);
Elements elements = document.select("ul.nav_txt a");
System.out.println(elements);
for(Element element : elements){
System.out.println(element.text() + ":" + element.attr("href"));
}
}
}
解析結果
使用jsoup向服務器發送請求
public class MyJsoup {
/*
* 需求:使用Jsoup解析網頁源碼
*/
public static void main(String[] args) throws Exception {
// 使用jsoup向服務器發送請求
Document doc = Jsoup.connect("http://www.itcast.cn").get();
// Jsoup使用類型css,Jquery選擇器方式獲取元素節點
// Elements elements = doc.getElementsByTag("a");
// System.out.println(elements.text());
Elements elements = doc.select("ul.nav_txt a");
// 循環元素
for (Element element : elements) {
System.out.println(element.text() + ":" + element.attr("href"));
}
}
}
解析結果
5. 綜合應用
解析下圖中紅色框的內容,HttpClient發送請求,Jsoup解析結果
點擊開發者工具的第一個圖標,移動鼠標到網頁的目標位置,即可定位到該目標的網頁源碼位置
package com.github.webcrawder;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
public class CrawderDemo {
public static void main(String[] args) throws ClientProtocolException, IOException {
// 創建httpClient客戶端
HttpClient hClient = new DefaultHttpClient();
// 創建http發送請求對象,Httpget
HttpGet hget = new HttpGet("http://www.itcast.cn");
// 發送請求
HttpResponse response = hClient.execute(hget);
// 獲取網頁內容
String content = EntityUtils.toString(response.getEntity(), "utf-8");
// 使用Jsoup解析網頁內容
Document document = Jsoup.parse(content);
// 使用元素選擇器選擇網頁的內容
Elements elements = document.select("ul.nav_li a");
System.out.println(elements.text());
System.out.println(elements);
}
}
解析結果
//使用jsoup加載遠程連接數據
@Test
public void myJsouptest() throws Exception {
String userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like " +
"Gecko) Chrome/44.0.2403.157 Safari/537.36";
//準備cookie信息
Map<String, String> maps = new HashMap<String, String>();
maps.put("TC-Ugrow-G0", "968b70b7bcdc28ac97c8130dd353b55e");
maps.put("SUB", "2AkMvfeeDf8NhqwJRmP0dzGvhZY5yywvEieLBAH7sJRMxHRl-yT9jqmAHtRAgR4BQZgBIE" +
"-Xz-jsqjVftcUdtrA..");
maps.put("SUBP", "0033WrSXqPxfM72-Ws9jqgMF55529P9D9WhBu3bohh6dYkXbY_GUs5d8");
//獲取網頁dom對象
Document doc = Jsoup.connect("http://www.itcast.cn/")
.userAgent(userAgent)
.cookies(maps).get();
//獲取文檔標簽
String title = doc.title();
System.out.println(title);
//獲取網頁元素
Elements elements = doc.select("div.qrcode-text");
System.out.println(elements.text());
}