爬蟲學習日記(六)完成第一個爬蟲任務

KIM曉峰發表於2019-01-10

距離上一篇學習日記已經過去了兩個星期,簡單講一下這兩個星期都幹了些什麼吧。

任務回顧:

  1. 測試SUDU是否可以用selenium的方式來獲取網頁資訊。
  2. 用selenium的方式實現SUDURoute的功能。
  3. 完成SITC Crawler。

因為capture SUDU 的爬蟲出了問題,估計是頻繁爬對面資料,被對面給block掉了,而Cindy就想讓我試試用selenium+phantomJS的方式,看看行的通嗎,之前用的是httpclient的方式。然後我就參照之前自己自學的方式,還有百度,用selenium獲取了對面的首頁,證明這種方式是可以的。所以我們Team決定改用selenium來實現SUDU,而且要我來寫。剛開始我是一位不難的,但是真正寫起來才發現真的很複雜,各種xpath獲取element,而且有很多業務的知識,那些要記錄,那些不用記錄,有進行很多的判斷,寫了兩天發現進度緩慢,而且Cindy也在催,感覺自己做不完了,就讓東哥去做了。後面一個星期,被安排了另外一個task,也是要寫一個crawler,用httpclient的方式,網站結構比SUDU簡單很多,完成較快,已經初步寫完,能實現功能,自己測試也沒什麼問題。

總結

  1. 用selenium來獲取SUDU首頁

因為只是獲取首頁,所以並沒有什麼難度。
首先在本地配置了一個driver。

//本地測試driver路徑
    private static WebDriver getWebDriver() {
        ChromeOptions options = new ChromeOptions();
        Map<String, Object> contentSettings = new HashMap<>();
        contentSettings.put("images", 2);

        Map<String, Object> preferences = new HashMap<>();
        preferences.put("profile.default_content_settings", contentSettings);

        DesiredCapabilities caps = DesiredCapabilities.chrome();
        caps.setCapability("chrome.prefs", preferences);
        caps.setCapability(ChromeOptions.CAPABILITY, options);

//		options.addArguments("headless");// headless mode
//		options.addArguments("disable-gpu");
        options.setBinary("C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe");
        System.setProperty("webdriver.chrome.driver", "D:\\phantomjs-2.0.0-windows\\chromedriver.exe");
//		ChromeDriver driver = new ChromeDriver(caps);


        System.setProperty("phantomjs.binary.path", "D:\\phantomjs-2.0.0-windows\\bin\\phantomjs.exe");
        ArrayList<String> args = new ArrayList<>();
        args.add("--ignore-ssl-errors=true");
        args.add("--ssl-protocol=any");
        DesiredCapabilities capabilities = DesiredCapabilities.phantomjs();
        capabilities.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, args);
        PhantomJSDriver driver = new PhantomJSDriver(capabilities);

        return driver;
    }
複製程式碼
caps.setCapability(ChromeOptions.CAPABILITY, options);
複製程式碼

這一句配置是用模擬手機登入,我之前也有點不明白為什麼要設定成這樣,後來在別人的blog中發現這樣子設定不容易被對面反爬蟲。

配置好Chrome和ChromeDriver的路徑,要注意版本號要對應。 配置好phantomjs的路徑。

String url = "https://www.hamburgsud-line.com/linerportal/pages/hsdg/p2p.xhtml?lang=en";
			driver.get(url);
			String html = driver.getPageSource();
複製程式碼

呼叫driver的get方法,他就回去開啟這個url,用getPageSource就能獲取這個網頁的原始碼,輸出這個html,發現裡面是有內容的,用selenium方式可行 。

  1. 用selenium的方式實現SUDURoute的功能。

才發現自己之前寫的沒有儲存,上傳git被還原回去了。

就只能簡單講一下現在還記得的幾個有印象的點。

首先因為是用的phantomjs,而且它設定成手機模式,在原先的crawler中,不能沿用他之前用的ChromeDriver的方式,因為兩種開啟方式,頁面裡面各種element的ID是有一些是不一樣的。
如,當時我在debug的時候,發現按鈕事件一直無效,回去頁面裡面看,發現按鈕的ID已經變了。其實發現按鈕ID變了這個也有點曲折,因為那時候我不知道瀏覽器已經被設定成了手機瀏覽的方式,所以我還是回去原先他的網站上看的,用的是pc端瀏覽器開啟的頁面裡面的按鈕的ID,但是就是一直跑不通,後來才想到應該去看我獲取的html裡面的,才發現按鈕的ID換了的,把按鈕的ID換回來就可以實現點選事件了。

實現點選事件後,他會執行一個判斷,判斷網頁是否出現了某些元素,這裡指的就是搜尋結果,出現了搜尋結果他就會停止等待。

停止等待以後,他會將獲取的html用jsoup轉換成document物件,就可以用DOM通過id或者其他東西來查詢節點來轉換成element,這裡是找到routeList。

做到routeList都一直聽順利,後來要對routeList做解析的時候,就一直遇到問題。
首先我第一個問題是對業務的不理解,在程式碼裡面有transhipment進行判斷的,0或者1有不一樣的解析方式,如果是0的話,是可以成功執行的,點開裡面巢狀的內容都是可以獲取到,但是在1的時候,就一直獲取不到,就一直卡在這裡。

對SUDU的開發就停留在這裡了。

  1. 完成SITC Crawler。

先講講需求,獲取route然後記錄。

爬蟲學習日記(六)完成第一個爬蟲任務

因為用的是httpclient,所以並不像之前用selenium一樣擔心ID的問題。

通過這個爬蟲的開發,也逐漸瞭解到用selenium和用httpclient的區別:
1.selenium其實就是模仿使用者操作,來實現各種點選操作,然後獲取執行後的頁面,對頁面進行解析獲取,通過jsoup轉成ducument,用DOM獲取各個element中我想要的元素。

2.httpclient則是模擬放鬆post和get請求,不管執行什麼操作,歸根結底都是往requestURL傳送請求去後臺。通過httpclient就可以拼接傳送請求的頭部還有body,然後解析它返回來的response。

兩者各有各的好處,selenium對於一些獲取動態頁面的比較適合,httpclient則比較適合獲取靜態頁面的。

現在來講講我做SITC的一些心得:

首先覺得要做一個爬蟲,就要先從瞭解他的各個請求開始。
之前我一直用的是selenium的思維去做httpclient,想要說實現點選查詢這個方法,然後獲取整個頁面,然而顯示資訊那裡都是動態生成的,用httpclient是獲取不到顯示的資訊的,返回回來的都是空的。
這裡我用的是Chrome除錯介面裡面的network,發現當我點選查詢的時候,會有一個請求傳送到後臺:

爬蟲學習日記(六)完成第一個爬蟲任務

而這個請求返回來的是一個json:

爬蟲學習日記(六)完成第一個爬蟲任務

這就是最主要的一個request了,我只要模擬這個POST請求,把我想搜尋的引數設定進去,就能返回我所要的資訊,然後對這些資訊進行解析就行了。

爬蟲學習日記(六)完成第一個爬蟲任務

成功獲取到我想要的資訊以後,剩下的就是解析。
因為返回來的是一個String,我要把它轉成能操作的list,就必須先把String轉成list。
我的做法是:
把string轉成jsonobject

JSONObject Json = JSONObject.fromObject(response);

複製程式碼

在Json裡面通過get到list:

JSONArray routeArray = (JSONArray) Json.get("list");
複製程式碼

這樣就能對list進行操作了。

SITC大致的心得就是這樣,第一次做考慮的情況還不是很多,估計後續會有一些bug。

                                                                        和狗子一起成為更好的人。
複製程式碼

相關文章