天天看點

Selenium 抓取淘寶商品

我們可以嘗試分析Ajax來抓取了相關資料,但是并不是所有的頁面都是可以分析Ajax來就可以完成抓取的,比如淘寶。它的整個頁面資料确實也是通過Ajax擷取的,但是這些Ajax接口參數比較複雜,可能會包含加密密鑰等參數,是以我們如果想自己構造Ajax參數是比較困難的,對于這種頁面我們最友善快捷的抓取方法就是通過Selenium,本節我們就來用Selenium來模拟浏覽器操作,抓取淘寶的商品資訊,并将結果儲存到MongoDB。

首先我們來看下淘寶的接口,看看它的接口相比一般Ajax多了怎樣的内容。

打開淘寶頁面,搜尋一個商品,比如iPad,此時打開開發者工具,截獲Ajax請求,我們可以發現會擷取商品清單的接口。

Selenium 抓取淘寶商品

它的連結包含了幾個GET參數,如果我們要想構造Ajax連結直接請求再好不過了,它的傳回内容是Json格式。

Selenium 抓取淘寶商品

但是這個Ajax接口包含了幾個參數,其中_ksTS、rn參數不能直接發現其規律,如果我們要去探尋它的生成規律也不是做不到,但這樣相對會比較繁瑣,是以如果我們直接用Selenium來模拟浏覽器的話就不需要再關注這些接口參數了,隻要在浏覽器裡面可以看到的我們都可以爬取。這也是為什麼我們選用Selenium爬取淘寶的原因。

我們本節的目标是爬取商品資訊,例如:

Selenium 抓取淘寶商品

這樣的一個結果就包含了一個商品的基本資訊,包括商品圖檔、名稱、價格、購買人數、店鋪名稱、店鋪所在地,我們要做的就是将這些資訊都抓取下來。

抓取入口就是淘寶的搜尋頁面,這個連結是可以直接構造參數通路的,例如如果搜尋iPad,就可以直接通路https://s.taobao.com/search?q=iPad,呈現的就是第一頁的搜尋結果,如圖所示:

Selenium 抓取淘寶商品

如果想要分頁的話,我們注意到在頁面下方有一個分頁導航,包括前5頁的連結,也包括下一頁的連結,同時還有一個輸入任意頁碼跳轉的連結,如圖所示:

Selenium 抓取淘寶商品

在這裡商品搜尋結果一般最大都為100頁,我們要擷取的每一頁的内容,隻需要将頁碼從1到100順次周遊即可,頁碼數是确定的。是以在這裡我們可以直接在頁面跳轉文本框中輸入要跳轉的頁碼,然後點選确定按鈕跳轉即可到達頁碼頁碼對應的頁面。

在這裡我們不直接點選下一頁的原因是,一旦爬取過程中出現異常退出,比如到了50頁退出了,我們如果點選下一頁就無法快速切換到對應的後續頁面,而且爬取過程中我們也需要記錄目前的頁碼數,而且一旦點選下一頁之後頁面加載失敗,我們還需要做異常檢測檢測目前頁面是加載到了第幾頁,是以整個流程相對複雜,是以在這裡我們直接選用跳頁的方式來爬取頁面。

當我們成功加載出某一頁商品清單時,利用Selenium即可擷取頁面源代碼,然後我們再用相應的解析庫解析即可,在這裡我們選用PyQuery進行解析。

下面我們用代碼來實作一下整個抓取過程。

首先我們需要構造一個抓取的URL,https://s.taobao.com/search?q=iPad,URL非常簡潔,參數q就是要搜尋的關鍵字,我們隻需要改變連結的參數q即可擷取不同商品的清單,在這裡我們将商品的關鍵字定義成一個變量,然後構造出這樣的一個URL。

構造出URL之後我們就需要用Selenium進行抓取了,我們實作如下抓取清單頁的方法:

在這裡我們首先構造了一個WebDriver對象,使用的浏覽器是Chrome,然後指定一個關鍵詞,如iPad,然後我們定義了一個get_index()方法,用于抓取商品清單頁。

在該方法裡我們首先通路了這個連結,然後判斷了目前的頁碼,如果大于1,那就進行跳頁操作,否則等待頁面加載完成。

等待加載我們使用了WebDriverWait對象,它可以指定等待條件,同時指定一個最長等待時間,在這裡指定為最長10秒。如果在這個時間内成功比對了等待條件,也就是說頁面元素成功加載出來了,那就立即傳回相應結果并繼續向下執行,否則到了最大等待時間還沒有加載出來就直接抛出逾時異常。

比如我們最終要等待商品資訊加載出來,在這裡就指定了presence_of_element_located這個條件,然後傳入了 .m-itemlist .items .item 這個選擇器,而這個選擇器對應的頁面内容就是每個商品的資訊塊,可以到網頁裡面檢視一下。如果加載成功,就會執行後續的get_products()方法,提取商品資訊。

關于翻頁的操作,我們在這裡是首先擷取了頁碼輸入框,指派為input,然後擷取了送出按鈕,指派為submit,分别是下圖中的兩個元素:

Selenium 抓取淘寶商品

首先我們清空了輸入框,調用clear()方法即可,随後調用send_keys()方法将頁碼填充到輸入框中,然後點選确定按鈕即可。

那麼怎樣知道有沒有跳轉到對應的頁碼呢?我們可以注意到成功跳轉某一頁後頁碼都會高亮顯示:

Selenium 抓取淘寶商品

我們隻需要判斷目前高亮的頁碼數是目前的頁碼數即可,是以在這裡使用了另一個等待條件 text_to_be_present_in_element,它會等待某一文本出現在某一個節點裡面即傳回成功,在這裡我們将高亮的頁碼節點對應的CSS選擇器和目前要跳轉的頁碼通過參數傳遞給這個等待條件,這樣它就會檢測目前高亮的頁碼節點裡是不是我們傳過來的頁碼數,如果是,那就證明頁面成功跳轉到了這一頁,頁面跳轉成功。

那麼這樣,剛才我們所實作的get_index()方法就可以做到傳入對應的頁碼,然後加載出對應頁碼的商品清單後,再去調用get_products()方法進行頁面解析。

接下來我們就可以實作get_products()方法來解析商品清單了,在這裡我們直接擷取頁面源代碼,然後用PyQuery進行解析,實作如下:

首先我們調用了page_source屬性擷取了頁碼的源代碼,然後構造了PyQuery解析對象,首先我們提取了商品清單,使用的CSS選擇器是 #mainsrp-itemlist .items .item,它會比對到整個頁面的每個商品,是以它的比對結果是多個,是以在這裡我們又對它進行了一次周遊,用for循環将每個結果分别進行解析,在這裡每個結果我們用for循環把它指派為item變量,每個item變量都是一個PyQuery對象,然後我們再調用它的find()方法,傳入CSS選擇器,就可以擷取單個商品的特定内容了。

比如在這裡我們檢視一下商品資訊源碼,如圖所示:

Selenium 抓取淘寶商品

在這裡我們觀察一下商品圖檔的源碼,它是一個 img 節點,包含了id、class、data-src、alt、src等屬性,在這裡我們之是以可以看到這張圖檔是因為它的src屬性被指派為圖檔的URL,在這裡我們就把它的src屬性提取出來就可以擷取商品的圖檔了,不過這裡我們還注意到有一個data-src屬性,它的内容也是圖檔的URL,觀察後發現此URL是圖檔的完整大圖,而src是壓縮後的小圖,是以這裡我們抓取data-src屬性來作為商品的圖檔。

是以我們需要先利用find()方法先找到圖檔的這個節點,然後再調用attr()方法擷取商品的data-src屬性即可,這樣就成功提取了商品圖檔連結。然後我們用同樣的方法提取商品的價格、成交量、名稱、店鋪、店鋪所在地等資訊,然後将所有提取結果指派為一個字典,叫做product,随後調用save_to_mongo()将其儲存到MongoDB即可。

接下來我們再将商品資訊儲存到MongoDB,實作如下:

我們首先建立了一個MongoDB的連接配接對象,然後指定了資料庫,在方法裡随後指定了Collection的名稱,然後直接調用insert()方法即可将資料插入到MongoDB,此處的result變量就是在get_products()方法裡傳來的product,包含了單個商品的資訊,這樣我們就成功實作了資料的插入。

剛才我們所定義的get_index()方法需要接收一個參數page,page即代表頁碼數,是以在這裡我們再實作頁碼周遊即可,代碼如下:

實作非常簡單,隻需要調用一個for循環即可,在這裡定義最大的頁碼數100,range()方法的傳回結果就是1到100的清單,順次周遊調用index_page()方法即可。

這樣我們的淘寶商品爬蟲就完成了,最後調用main()方法即可運作。

我們将代碼運作起來,可以發現首先會彈出一個Chrome浏覽器,然後順次通路淘寶頁面,然後控制台便會輸出相應的提取結果,這些商品資訊結果都是一個字典形式,然後被存儲到了MongoDB裡面。

但是此次爬取有個不太友好的地方就是Chrome浏覽器,爬取過程必須要開啟一個Chrome浏覽器确實不太友善,是以在這裡我們還可以對接PhantomJS,隻需要将WebDriver的聲明修改一下即可,但是注意這裡必須要安裝好PhantomJS,如果沒有安裝可以參考第一章裡的安裝方法說明。

将WebDriver聲明修改如下:

這樣在抓取過程中就不會有浏覽器彈出了。

另外我們還可以設定緩存和禁用圖檔加載的功能,進一步提高爬取效率,修改如下:

這樣我們就可以禁用PhantomJS的圖檔加載同時開啟緩存,可以發現頁面爬取速度進一步提升。

本節代碼位址為:https://github.com/Python3WebSpider/TaobaoProduct。