90行程式碼爬取我的微博

fairjm發表於2017-07-03

本文來自 fairjm@圖靈社群 轉截請註明出處


這90行程式碼寫了大半年,本來年初就能寫好的,結果懶癌發作一病不起,昨天突然驚醒,已經過了半年了,這半年來也沒業餘好好寫程式碼,發的文章也是划水性質,不能再這麼下去了.

初衷其實挺簡單的,看自己發了1w+的微博,想著哪天不見了青春的記憶就蕩然無存,實在太可惜了,儲存到本地方便追溯.
目標是 http://weibo.com/xxx/profile所有頁碼的內容.
那要怎麼幹呢,我們知道微博的非同步頁面渲染用的是介面返回html資料拼接的方式,一般需要構造請求然後自行拼接html,但一頁就要請求兩次,而且如何拼接要看js是怎麼處理的...
enter image description here

實在是過於麻煩了有點勸退了,還不如自己登上去然後儲存一下頁面呢.於是就會有這樣的操作:

    1.登陸http://weibo.com  
    2.進入profile頁面  
    3.鍵盤輸入End一次,載入頁面  
    4.再輸入End一次,載入頁面到這頁底部.  
    5.儲存   
    6.點下一頁,回到步驟3.沒有下一頁就結束  

但這裡有350多頁,自己操作一定會手痠,何不讓程式幫我們完成?

查閱了一下找到了個工具canopy,基於Selenium的F# web UI測試框架.
因為不知道微博做了什麼限制,我需要偶爾看一下程式的進度,所以我還是需要介面的,選擇了chrome的webdriver(注意需要使用最新版,不然測試外掛會無法工作).

接下來我們就只需要略生硬地翻譯一下上面的步驟就可以啦.

chromeDir <- @"D:\webdriver\chrome"  

首先設定一下webdriver所在的目錄.

start chrome
url "https://weibo.com"
waitFor (fun () -> 
        let now = currentUrl()
        now.Contains("/profile"))

啟動chrome,跳轉到weibo.com 登陸自己完成,然後點選自己的微博跳轉到profile頁,上面程式碼如果不在profile頁會進行等待.

press Keys.End  

按下end 這邊可能需要等待一下載入完畢再按下一個End,要按兩次拿取一頁完整的頁面.
然後得到頁面文字~

let getHtml () =
    let ele = element "html"
    ele.GetAttribute("outerHTML")

接下去我要獲得下一頁的地址,檢視了下html得到css選擇器的寫法:

let getNextPageElement () =
    try
        Some(element "a.page.next")
    with
        _ -> None

... ...(省略檔案儲存 等等操作)

滿心歡喜,寫好了,開始執行,看著資料夾下html慢慢增加,還是挺開心的.
突然程式停了,看了下瀏覽器在載入的時候卡住了(應該是請求過多觸發了限制....),重新整理了下頁面才繼續載入.
因為程式判斷了End兩次只要要能獲取到下一頁才會繼續,網頁卡在載入根本沒把下一頁的按鈕渲染出來,自然就不行了.
想了想還是應該降低速度,增大End的等待時間以及加上錯誤重試的功能才比較科學,再完善了一下滾到頁底的方式:

let pressToProfileEnd () =
    let pressIt() =
        pressEnd()
        sleep 4
        pressEnd()
        sleep 4
        pressEnd() //保險起見 再來一次
        sleep 4
    pressIt()
    // try it again
    let notHasNext = getNextPageElement().IsNone
    if notHasNext then
        reload()
        pressIt()  

接下去就看著瀏覽器慢慢滾動,網頁一頁頁被儲存到目標檔案了,這年末年初的坑終於也是給填上了,不免鬆了一口氣.

(完整程式碼見:https://github.com/fairjm/fsharpSnippet/blob/master/WeiboProfileCrawler.fs)

Ps:這90行可是包含了空行和註釋~爬點東西工具對了程式碼也可以像python那麼少啊(逃

相關文章