日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

带你入门Java网络爬虫

發布時間:2023/12/20 java 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 带你入门Java网络爬虫 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 爬蟲初識
  • 選Java還是選Python
  • Java網絡爬蟲來了
    • 網絡爬蟲流程
    • 需要掌握的Java基礎知識
    • HTTP協議基礎與網絡抓包
  • 小工具實現數據采集
    • 文本類數據采集
    • 圖片數據的采集
    • 大文件內容獲取問題
  • 其他知識點

爬蟲初識

記得,在本科時,因為畢業論文需要不少網絡上用戶的問答數據。最開始,我并沒有搞過網絡爬蟲,只能利用關鍵詞搜索的方式,找到相關的數據,然后一條一條復制。你可能覺得這樣很傻,但不得不承認這確實我最初的操作方式,很艱難,累的手疼。

后來,讀研究生時,既要開展實際的項目,同時也要做科研。項目和科研,都需要采集大量的網絡數據。領頭做項目的師兄,指定了一系列國內外網站,并把采集任務分配給我。額,當時,對于啥都不咋會的我,只能說“這該咋弄啊?這咋弄啊?。。”。沒辦法,硬著頭皮也要上。

后來,經師兄指點,讓我去學習網路爬蟲,說網路爬蟲可以搞定“我想要的數據”。聽師兄的,不會錯,那就學吧。

選Java還是選Python

決定要用網絡爬蟲去采集數據了,但面臨一個選擇就是:是用Java還是Python寫網絡爬蟲呢?對于一個新手,我看了一些網上的各種對比帖子,各有各的觀點,其中不少說Python上手容易,寫起來方便。但最終我還是選擇了Java,有以下幾點原因:
(1) Java火了很多年,而且依舊很火,其生態也比較完善。目前,很多大公司的系統皆采用Java設計,足以說明其強大之處。把Java學好了,足夠讓我找一份不錯的工作。
(2) Java是復雜一些難一些,但嚴謹規范,對于大型工程,對于大型程序,如果不規范不嚴謹維護豈不容易出問題。
(3) 對網絡爬蟲而言,JAVA中也有很多簡單易用的類庫(如Jsoup、Httpclient等),同時還存在不少易于二次開發的網絡爬蟲框架(Crawler4J、WebMagic等)。
(4) 曾在一個帖子中看到,“世界上99%的人都會選擇一條容易走的大路,因為人都喜歡安逸。這也是人的大腦的思維方式決定的,因為大腦的使命是為了讓你生存,而不是求知。但成功是總是屬于那1%的人,這類人是堅持讓大腦做不愿意做的事的人——求知”。哎,這在我看來,還真有一定的道理。如果勵志想成為一名真正的程序員,建議先學習Java。在此基礎上,如果你對Python感興趣,也是可以快速上手的。

Java網絡爬蟲來了

網絡爬蟲流程

學習網絡爬蟲之前,先看了普通網絡爬蟲大致流程,如下圖所示:

主要包括5個步驟:

  • 選取部分種子URL(或初始URL),將其放入待采集的隊列中。如在Java中,可以放入List、LinkedList以及Queue中。
  • 判斷URL隊列是否為空,如果為空則結束程序的執行,否則執行步驟3。
  • 從待采集的URL隊列中取出一個URL,獲取URL對應的網頁內容。在此步驟需要使用HTTP響應狀態碼(如200和403等)判斷是否成功獲取到了數據,如響應成功則執行解析操作;如響應不成功,則將其重新放入待采集URL隊列(注意這里需要過濾掉無效URL)。
  • 針對響應成功后獲取到的數據,執行頁面解析操作。此步驟根據用戶需求獲取網頁內容中的部分字段,如汽車論壇帖子的id、標題和發表時間等。
  • 針對步驟4解析的數據,執行數據存儲操作。
  • 需要掌握的Java基礎知識

    在使用Java構建網絡爬蟲時,需要掌握很多Java方面的基礎知識。例如,Java中基本的數據類型、Java中的數組操作、判斷語句的使用、集合操作、對象和類的使用、String類的使用、日期和時間的處理、正則表達式的使用、Maven工程的創建、多線程操作、日志的使用等。

    看著知識點很多,但如果將其放入到具體的網絡爬蟲實戰項目中去學習,會發現很簡單。下面,我舉兩個例子。
    在網絡爬蟲中,我們經常需要將待采集的URL放到集合中,然后循環遍歷集合中的每個URL去采集數據。比如,我們使用Queue集合操作:

    Queue<String> urlQueue = new LinkedList<String>();//添加要采集的URLurlQueue.offer("https://ccm.net/download/?page=1");urlQueue.offer("https://ccm.net/download/?page=2");urlQueue.offer("https://ccm.net/download/?page=3");boolean t = true;while (t) {//如果隊列為空,循環結束if( urlQueue.isEmpty() ){t = false;}else {//取出每個URLString url = urlQueue.poll();//獲取HTMLString getHtml = ...;//判斷是否成功請求到HTMLif (成功請求到HTML) {//解析數據...;}else { //如果網頁存在但沒有請求到數據,重新添加到隊列中urlQueue.offer(url); }}}

    另外,在采集數據時,不同網站的時間使用格式可能不同。而不同的時間格式,會為數據存儲以及數據處理帶來一定的困難。例如,下圖為某汽車論壇中時間使用的格式,即“yyyy-MM-dd”和“yyyy-MM-dd HH:mm”兩種類型。

    下圖為某新聞網站中的時間使用格式“yyyy-MM-dd HH:mm:ss”。

    再如,藝術品網站deviantart(https://www.deviantart.com/enterthespectrum/modals/memberlist/)的時間使用的是UNIX時間戳的形式。

    針對汽車論壇中的“yyyy-MM-dd”和“yyyy-MM-dd HH:mm”格式,可以統一轉化成“yyyy-MM-dd HH:mm:ss”格式,以方便數據存儲以及后期數據處理。此時,可以寫個方法將將字符串類型的時間標準化成指定格式的時間。如下程序:

    import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class TimeTest {public static void main(String[] args) {System.out.println(parseStringTime("2016-05-19 19:17","yyyy-MM-dd HH:mm","yyyy-MM-dd HH:mm:ss"));System.out.println(parseStringTime("2018-06-19","yyyy-MM-dd","yyyy-MM-dd HH:mm:ss"));}/*** 字符型時間格式標準化方法* @param inputTime(輸入的字符串時間),inputTimeFormat(輸入的格式),outTimeFormat(輸出的格式).* @return 轉化后的時間(字符串)*/public static String parseStringTime(String inputTime,String inputTimeFormat,String outTimeFormat){String outputDate = null;try {//日期格式化及解析時間Date inputDate = new SimpleDateFormat(inputTimeFormat).parse(inputTime); //轉化成新的形式的字符串outputDate = new SimpleDateFormat(outTimeFormat).format(inputDate); } catch (ParseException e) {e.printStackTrace();}return outputDate;} }

    針對UNIX時間戳,可以通過如下方法處理:

    //將unix時間戳轉化成指定形式的時間public static String TimeStampToDate(String timestampString, String formats) {Long timestamp = Long.parseLong(timestampString) * 1000;String date = new SimpleDateFormat(formats, Locale.CHINA).format(new Date(timestamp));return date;}

    HTTP協議基礎與網絡抓包

    做網絡爬蟲,還需要了解HTTP協議相關的內容,即要清楚數據是怎么在服務器和客戶端傳輸的。

    具體需要了解的內容包括:

  • URL的組成:如協議、域名、端口、路徑、參數等。
  • 報文:分為請求報文和響應報文。其中,請求報文包括請求方法、請求的URL、版本協議以及請求頭信息。響應報文包括請求協議、響應狀態碼、響應頭信息和響應內容。響應報文包括請求協議、響應狀態碼、響應頭信息和響應內容。
  • HTTP請求方法:在客戶端向服務器發送請求時,需要確定使用的請求方法(也稱為動作)。請求方法表明了對URL指定資源的操作方式,服務器會根據不同的請求方法做不同的響應。網絡爬蟲中常用的兩種請求方法為GET和POST。
  • HTTP狀態碼:HTTP狀態碼由3位數字組成,描述了客戶端向服務器請求過程中發生的狀況。常使用200判斷網絡是否請求成功。
  • HTTP信息頭:HTTP信息頭,也稱頭字段或首部,是構成HTTP報文的要素之一,起到傳遞額外重要信息的作用。在網絡爬蟲中,我們常使用多個User-Agent和多個referer等請求頭來模擬人的行為,進而繞過一些網站的防爬措施。
  • HTTP響應正文:HTTP響應正文(或HTTP響應實體主體),指服務器返回的一定格式的數據。網絡爬蟲中常遇到需要解析的幾種數據包括:HTML/XML/JSON。


  • 在開發網絡爬蟲時,給定 URL,開發者必須清楚客戶端是怎么向服務器發送請求的,以及客戶端請求后服務器返回的數據是什么。只有了解這些內容,開發者才能在程序中拼接URL,針對服務返回的數據類型設計具體的解析策略。因此,網絡抓包是實現網絡爬蟲必不可少的技能之一,也是網絡爬蟲開發的起點。例如,給定下面的URL:

    https://tianchi.aliyun.com/dataset/?spm=5176.12282016.0.0.7bba15a2ZOO4VC

    即我想要獲取阿里天池上的數據集介紹的信息:

    從上圖中,可以看到共有107頁,點擊第二頁,會發現瀏覽器中的URL變為發生變化。但通過谷歌瀏覽器抓包的方式,會發現數據真實請求的URL。另外從下圖可以看到請求的方式使用的是POST的形式,并且POST提交的參數是以JSON的形式呈現,同時在請求頭中包含x-csrf-token。


    另外,通過Preview可以看到網頁數據返回的形式為JSON:

    小工具實現數據采集

    網絡爬蟲主要涉及的是網頁請求,網頁解析和內容存儲。下面,使用一塊簡單易用的Jsoup工具實現幾個案例數據的采集。

    Jsoup是一款基于Java語言的開源項目,主要用于請求URL獲取網頁內容、解析HTML和XML文件。使用Jsoup可以非常輕松的構建一些輕量級網絡爬蟲。

    文本類數據采集

    要采集的網站地址為:https://www.pythonforbeginners.com/。網站內容如下圖所示:

    其中,我們要采集的字段包括:帖子的標題和帖子的簡介

    我們利用網絡抓包的形式發現該網頁返回的數據為HTML格式,如下圖所示。從中可以看到,我們想要的數據都在標簽“li class=‘hentry’”中。

    之后,我們需要使用的jar包,即Jsoup。在Eclipse中創建Maven工程,并在工程的pom.xml文件中添加Jsoup對應的dependency:

    <!-- https://mvnrepository.com/artifact/org.jsoup/jsoup --><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.11.3</version></dependency>

    基于此jar包,可以編寫一個請求該網站數據,解析該網站數據的程序,如下:

    package com.qian.test;import java.io.IOException; import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements;public class Test {public static void main(String[] args) throws IOException {//創建連接---注意這里是HTTPS協議Connection connect = Jsoup.connect("https://www.pythonforbeginners.com/").validateTLSCertificates(false);//請求網頁Document document = connect.get();//解析數據--CSS選擇器Elements elements = document.select("li[class=hentry]");for (Element ele : elements) {String title = ele.select("h2").text();String url = ele.select("h2>a").attr("href");//控制臺輸出的形式---也可以文件流輸出或導入數據庫System.out.println(title + "\t" + url); }} }

    執行該程序會在控制臺輸出以下內容:

    這里需要注意的是,該網站使用的是HTTPS協議,因此需要調用validateTLSCertificates()方法。否則,如果只使用下面的方式請求頁面,則會報錯。

    //創建連接Connection connect = Jsoup.connect("https://www.pythonforbeginners.com/");//請求網頁Document document = connect.get();

    圖片數據的采集

    圖片數據是非常常見的一種數據形式。很多做圖片處理的研究者,經常需要采集一些網站上的圖片,下面以Jsoup工具演示如下采集圖片。給定圖片地址:

    https://www.makro.co.za/sys-master/images/h98/h64/9152530710558/06cf39e4-7e43-42d4-ab30-72c81ab0e941-qpn13_medium

    對應的圖片為:

    如下為操作程序:

    package com.qian.jsoupconnect;import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.Connection.Method; import org.jsoup.Connection.Response; //實現圖片的下載 public class JsoupConnectInputstream {public static void main(String[] args) throws IOException {String imageUrl = "https://www.makro.co.za/sys-master/images/h98/h64/9152530710558/06cf39e4-7e43-42d4-ab30-72c81ab0e941-qpn13_medium";Connection connect = Jsoup.connect(imageUrl);Response response = connect.method(Method.GET).ignoreContentType(true).execute(); System.out.println("文件類型為:" + response.contentType());//如果響應成功,則執行下面的操作if (response.statusCode() ==200) {//響應轉化成輸出流BufferedInputStream bufferedInputStream = response.bodyStream();//保存圖片saveImage(bufferedInputStream,"image/1.jpg");}}/*** 保存圖片操作* @param 輸入流* @param 保存的文件目錄* @throws IOException*/static void saveImage(BufferedInputStream inputStream, String savePath) throws IOException {byte[] buffer = new byte[1024];int len = 0;//創建緩沖流FileOutputStream fileOutStream = new FileOutputStream(new File(savePath));BufferedOutputStream bufferedOut = new BufferedOutputStream(fileOutStream);//圖片寫入while ((len = inputStream.read(buffer, 0, 1024)) != -1) {bufferedOut.write(buffer, 0, len);}//緩沖流釋放與關閉bufferedOut.flush();bufferedOut.close();} }

    在上述程序中,使用了ignoreContentType()方法,即忽略請求的數據類型。如果狀態碼為200,即響應成功,接著對數據流進行操作,將圖片下載到指定目錄下。執行該程序,可以發現工程的“image/”目錄下成功多了,一張圖片。

    大文件內容獲取問題

    在采集數據時,經常遇到一些較大的文件,如包含大量文本信息的HTML文件、超過10M的圖片、PDF和ZIP等文件。Jsoup默認情況下最大只能獲取1M的文件。因此,直接使用Jsoup請求包含大量文本信息的HTML文件,將導致獲取的內容不全;請求下載超過1M的圖片和ZIP等文件,將導致文件無法查看或解壓。但在Jsoup中,可以使用maxBodySize(int bytes)設置請求文件大小限制,來避免這種問題的出現。如下網站:

    http://poi.mapbar.com/shanghai/F10


    該網站中按照A-B-C-D…一直排下去,導致HTML過大。因此需要使用maxBodySize()方法。程序如下所示:

    package com.qian.jsoupconnect;import java.io.IOException; import org.jsoup.Jsoup; import org.jsoup.Connection.Method; import org.jsoup.Connection.Response;public class JsoupConnectBodySize2 {public static void main(String[] args) throws IOException {//如果不設置maxBodySize,會導致網頁不全String url = "http://poi.mapbar.com/shanghai/F10";Response response = Jsoup.connect(url).timeout(10*10*1000).maxBodySize(Integer.MAX_VALUE).method(Method.GET).ignoreContentType(true).execute();System.out.println(response.parse());} }

    再如,我要請求一個壓縮文件,URL地址為:

    https://www-us.apache.org/dist//httpd/httpd-2.4.37.tar.gz

    Jsoup下載httpd-2.4.37.tar.gz文件(8.75M)時,也需要使用maxBodySize()方法,同時用Integer.MAX_VALUE設置的請求文件大小。另外,在請求大文件時,超時時間也需設置的盡量長些。程序如下:

    package com.qian.jsoupconnect;import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import org.jsoup.Jsoup; import org.jsoup.Connection.Method; import org.jsoup.Connection.Response; public class JsoupConnectBodySize1 {public static void main(String[] args) throws IOException {String url = "https://www-us.apache.org/dist//httpd/httpd-2.4.37.tar.gz";//超時時間設置長一些,下載大文件Response response = Jsoup.connect(url).timeout(10*60*1000).maxBodySize(Integer.MAX_VALUE).method(Method.GET).ignoreContentType(true).execute();//如果響應成功,則執行下面的操作if (response.statusCode() ==200) {//響應轉化成輸出流BufferedInputStream bufferedInputStream = response.bodyStream();//保存圖片saveFile(bufferedInputStream,"image/httpd-2.4.37.tar.gz");}}/*** 保存文件* @param 輸入流* @param 保存的文件目錄* @throws IOException*/static void saveFile(BufferedInputStream inputStream, String savePath) throws IOException {byte[] buffer = new byte[1024];int len = 0;//創建緩沖流FileOutputStream fileOutStream = new FileOutputStream(new File(savePath));BufferedOutputStream bufferedOut = new BufferedOutputStream(fileOutStream);//圖片寫入while ((len = inputStream.read(buffer, 0, 1024)) != -1) {bufferedOut.write(buffer, 0, len);}//緩沖流釋放與關閉bufferedOut.flush();bufferedOut.close();} }

    執行該程序,可以發現“image/”目錄下成功下了httpd-2.4.37.tar.gz。

    其他知識點

    上面,只介紹了Jsoup的一些簡單用法。更多的知識點將涉及到連接超時問題、請求頭添加問題、POST請求問題、代理問題、詳細的HTML/XML數據解析問題。

    另外,在Java網絡爬蟲中,還涉及其他網頁請求工具,例如:HttpClient/URLConnection/OkHttp等。

    在數據解析方面,還涉及CSS選擇器的使用、Xpath語法的使用、HtmlCleaner和Htmlparser如何解析HTML;XML數據如何解析;JSON校正、GSON和Fastjson的使用等。

    在數據存儲方面,還涉及輸入流和輸出流的操作、EXCEL的操作、數據庫的操作等。

    另外,在Java中還存在很多優秀的開源的網絡爬蟲框架,如Crawler4J、Webcollector、WebMagic等。

    為幫助想要入門Java網絡爬蟲的讀者,這里特意推薦一本書《網絡數據采集技術 Java網絡爬蟲實戰》。

    該書的特色包括:

  • 注重基礎:即梳理了Java網絡爬蟲涉及的Java基礎知識,如Maven的操作、Java基于語法、字符串操作、集合操作、日期格式化、正則表達式、輸入輸出流操作、數據庫操作等一系列知識點;
  • **注重系統性:**即系統梳理網絡爬蟲開發的邏輯、HTTP協議的內容、網頁數據請求、網頁數據解析、網絡數據存儲等;
  • **詳細的案例講解:**為便于讀者實際操作,本書以典型網站為例,講解Java網絡爬蟲涉及知識點,如HTTPS 請求認證問題、文本/圖片/PDF/壓縮包下載存儲問題、大文件內容獲取不全問題、模擬登陸問題、Javascript動態加載問題、定時數據采集問題等;
  • **開源框架的使用:**介紹了三種簡單易用的Java網絡爬蟲框架,即Crawler4j、WebCollector和WebMagic,通過這三種框架的學習,讀者可以輕輕松松開發符合自身需求的網絡爬蟲項目;
  • 為便于讀者學習,每個數據采集項目,都提供了完整的代碼(github可下載),并且代碼給出了清晰的注釋
  • 另外,本書適合的讀者包括:

  • 想要以項目的方式學習Java的人員;
  • Java網絡爬蟲開發的初學者和進階者;
  • 科研人員,尤其是從事網絡大數據驅動的碩士生和博士生;
  • 開設相關課程的高等院校師生。
  • 總結

    以上是生活随笔為你收集整理的带你入门Java网络爬虫的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。