[Java]教你網路爬蟲基本觀念及實作

開了一篇新教學,使用新的 IDE 及 方便的套件

[Java]手把手帶你實作PTT爬蟲(1)-文章列表










簡單來說網路爬蟲就是自動去蒐集網站內容

進而從網站的內容中,截取關鍵字進行建檔

再截取其中的網址繼續爬下去

所以今天我們就拿一個網站來試驗

看看爬蟲是怎麼抓資料的

今天選的網站是鼎鼎大名的SOGO論壇

什麼??你說你不知道??嗯...不要問很可怕

我們先來講解一下最基本的觀念

你丟出去,對方丟回來

所有的網站皆是如此!!很單純

複雜的是有些網站的驗證機制不好過

這次我們使用Chrome的F12來分析網站

Step 1

開啟網站點下F12,切到Network,勾選Preserve log



Step 2

我們先從登入開始

點一下上方的登入,觀察一下右邊出現的Log

可以發現點下去的第一時間,向一個網址發送了GET請求



點進去可以看到請求的詳細內容



往下拉到底可以到看Query String Parameters

這是GET送出去的參數



之後切換到 Reponse

這是對方主機回傳回來的資料,可以看到內容是登入框的HTML碼



OK!!到這邊我們總結一下,按下登入後發生了什麼事情

  • 會觸發GET要求
  • 要求的網址是: http://oursogo.com/member.php
  • 傳送的參數有
    • mod=logging
    • action=login
    • referer=
    • infloat=yes
    • handlekey=login
    • inajax=1
    • ajaxtarget=fwin_content_login
  • 對方丟回來一段登入框的HTML碼

看了一下參數,應該是沒有動態(每次發出去的內容都會換)的部分

如果不確定有沒有,重新整理網站後,再按一次登入

如果參數都一樣的話,代表我們只要寫死就可以了

Step 3

輸入帳號密碼後,點下登入

可以看到又對同一隻檔案發送了請求,這次的是POST



一樣點開來看一下內容





這次參數的部分多了一個 Form Data

這是使用 POST 傳送的參數,Query String是 GET 傳送的參數,兩者可以共存

這次切到 Reponse 看不到東西,因為被重新導向過

但之後我們可以用程式看,不用擔心

OK!!到這邊我們第二次總結一下,進行登入後發生了什麼事情

  • 會觸發POST要求
  • 要求的網址是: http://oursogo.com/member.php
  • Query傳送的參數有
    • mod=logging
    • action=login
    • loginsubmit=yes
    • handlekey=login
    • loginhash=L3Y53
    • inajax=1
  • Form傳送的參數有
    • formhash=e0290946
    • referer=http://oursogo.com
    • username=
    • password=
    • questionid=0
    • answer=
    • loginsubmit=true

這次參數中混入了奇怪的東西 loginhash 和 formhash

這兩個很明顯的是動態產生的,這兩樣資料要怎麼來呢??

還記得上一步驟我們點下登入後有回傳了一段HTML碼嗎??

這兩樣資料就在那裡面,我們只要截取出來就好

或許會有人問:如果不在要怎麼辦!

你們只要記住

資料一定會有!!但可能在任何地方

這時候更要針對這個網頁上的所有動作進行分析

比如有沒有發送其他的要求,或是東西藏在JS當中...etc

到這邊我們已經分析完了"登入"到底做了些什麼事

Step 3

再來我們就先寫一段程式碼吧,開啟IDE後新增一個Java專案

設定一些package



article = 文章部分 http=通訊部分 login=登入部分 start=程式起點

新增一隻 Class 用來向主機發出 HTTP 要求

這隻是我之前寫好的,後面附上專案檔案

使用的是 apache http(https://hc.apache.org/)



再來在 login 中新增一個 Class Login,並規劃一些方法



之後按照上面分析好的步驟,撰寫程式

註解寫了很清楚,就不多做解釋了





Step 4

實際開一個討論區看看吧,這次的目標是爬取文章標題

奇怪!!居然出現了一個年齡限制



不用怕,一樣照上面的步驟解決這個頁面



分析完這個頁面資訊後我們一併分析文章頁面

進到文章後...拿一下衛生紙隨便先選一篇文章後,右鍵>檢查



之後我們就可以看到文章標題寫在 title 標籤中

上層是一個 li 標籤,由此看來,每一個文章簡介都是一個 li



Step 5

再來我們就繼續程式碼吧,在 article 中新增一個 Class ArticleList,並規劃一些方法









Step 6

到這邊我們已經把 登入 年齡驗證 抓取標題 實作完畢了

再來就是在 start 中新增一個 Class Start 來測試結果



大成功



總結

我們學到了如何使用 Chrome F12 工具來幫助我們分析 HTTP

也學習到了平常瀏覽網站時,瀏覽器到底幫我們做了什麼事情

爬蟲就是另一種瀏覽器,但爬回來的就是冷冰冰的程式碼

但在這邊呼籲,沒事不要去亂爬別人的東西,會讓對方的主機增加負擔

Read more

[LeetCode] #12 Integer to Roman 解題

題目連結 題型解說 這是一題難度為普通的題目 需要設計一個方法,此方法會傳入一個整數 num 要求是把整數轉換成羅馬字母,轉換清單如下 I => 1 V => 5 X => 10 L => 50 C => 100 D => 500 M => 1000 但羅馬字母有一些特殊規則 4 並非 IIII 而是 IV,9 並非 VIIII 而是 IX 這規則同樣可以套用到 40 90 400 900 解題思路 既然知道特殊規則是一樣的,變得是使用的符號,那麼先從 num 取個位數開始 轉換完成後,把 num 除上 10,消除個位數,

By Michael

[LeetCode] #11 Container With Most Water 解題

題目連結 題型解說 這是一題難度為中等的題目 需要設計一個方法,此方法會傳入一個數字陣列 height 陣列中的元素代表每一個柱子的高度 現在需要計算出,該陣列中以某兩隻柱子為邊界,最多可以裝多少水 以範例來說 height = [1,8,6,2,5,4,8,3,7] 最多可以裝 7 * 7 = 49 單位的水 解題思路 計算面積就是底乘上高 底的計算方式為 「右邊柱子的 index」 減去 「左邊柱子的 index」 高就取最短的那一根柱子高度 拿題目給的例子來當範例 建立三個變數 result、left、right left、right 代表左右兩邊的 index result 代表目前最大容量,初始值 0 第一步,找出最短的柱子高度,

By Michael

[LeetCode] #941 Valid Mountain Array 解題

題目連結 題型解說 這是一題難度為簡單的題目 需要設計一個方法,此方法會傳入一個數字陣列 arr 判斷陣列中的元素是不是由低到高再從高到低(山形)的排序,且不連續一個以上數字 比如說 [1,2,3,2] 就是一個山形陣列,但 [1,2,2,3,2] 不是,因為有兩個 2 [1,2,3,4,5] 和 [5,4,3,2,1] 也不算是山形陣列,前者只有往上沒有往下,後者相反 解題思路 準備一個數字變數(temp)和布林變數(asc),跑一次迴圈,有可能遇到如下狀況 1. 某個數字與前一個數字相同,這時候直接回傳 false

By Michael

[LeetCode] #944 Delete Columns to Make Sorted 解題

題目連結 題型解說 這是一題難度為簡單的題目 需要設計一個方法,此方法會傳入一個字串陣列 strs 這個陣列中每個字串的長度都相同,字串內容都是小寫英文 需要檢查每個元素的第 N 個字元是不是由小至大排列,並回傳有幾個錯誤排列 比如傳入的陣列長這樣 ["cba","daf","ghi"] 取第一個字元 = cdg 取第二個字元 = bah 取第三個字元 = afi 其中第二組的結果(bah)並不是由小至大排列,故回傳 1 解題思路 這一題就用兩個迴圈各別把字元取出來,並比較是否比上一個字元大(Java 中的字元可以直接比較),如果不是就將結果+1 程式碼 Java class Solution { public int minDeletionSize(String[] strs) { int result = 0; for (int i = 0,

By Michael