摘要:系列教程手把手教你寫電商爬蟲第一課找個軟柿子捏捏手把手教你寫電商爬蟲第二課實戰(zhàn)尚妝網(wǎng)分頁商品采集爬蟲看完兩篇,相信大家已經(jīng)從開始的小菜鳥晉升為中級菜鳥了,好了,那我們就繼續(xù)我們的爬蟲課程。
系列教程:
手把手教你寫電商爬蟲-第一課 找個軟柿子捏捏
手把手教你寫電商爬蟲-第二課 實戰(zhàn)尚妝網(wǎng)分頁商品采集爬蟲
看完兩篇,相信大家已經(jīng)從開始的小菜鳥晉升為中級菜鳥了,好了,那我們就繼續(xù)我們的爬蟲課程。
上一課呢一定是因為對手太強,導致我們并沒有完整的完成尚妝網(wǎng)的爬蟲。
吭吭~,我們這一課繼續(xù),爭取徹底搞定尚妝網(wǎng),不留任何遺憾。
我們先回顧一下,上一課主要遺留了兩個問題,兩個問題都和ajax有關。
1、由于是ajax加載下一頁,導致下一頁url并不會被系統(tǒng)自動發(fā)現(xiàn)。
2、商品頁面的價格是通過ajax加載的,我們直接從網(wǎng)頁中獲取不到信息本身。
好了,我們先解決第一個問題:
第一個問題實際上是一個爬蟲中比較常見的問題,即url的發(fā)現(xiàn),默認情況下,URL的發(fā)現(xiàn)是神箭手云爬蟲框架自動處理的,但是如果在ajax的情況下,框架則無從發(fā)現(xiàn)url,這個時候就需要我們自己手動處理url的發(fā)現(xiàn),這里,神箭手給我們提供了一個很方便的回調(diào)函數(shù)讓我們來自己處理url的發(fā)現(xiàn):
onProcessHelperUrl(url, content, site)
這個回調(diào)函數(shù)有兩個參數(shù),分別是當前處理的頁面對象和整個爬取站的對象,我們可以通過獲取頁面對象的內(nèi)容來分析是否有我們需要的新一頁的url,通過site.addUrl()方法加入到url隊列中既可。這里我們可以看到,當超出頁數(shù)的時候,尚妝網(wǎng)會給我們返回一個這樣的頁面,我們就知道頁數(shù)超過了,不需要在加入新的頁url:
這個頁面我們很好判斷,只需要看內(nèi)容中是否有"無匹配商品"關鍵字既可。
這里我們需要一些基礎的js能力,代碼如下:
configs.onProcessHelperUrl = function(url, content, site){ if(!content.indexOf("無匹配商品")){ //如果沒有到最后一頁,則將頁數(shù)加1 var currentPage = parseInt(url.substring(url.indexOf("&page=") + 6)); var page = currentPage + 1; var nextUrl = url.replace("&page=" + currentPage, "&page=" + page); site.addUrl(nextUrl); } }
原理很簡單,如果內(nèi)容中沒有無匹配商品這個關鍵詞的時候,則把當前頁面的下一頁加入的待爬隊列中。
好了,ajax分頁問題徹底解決,下面來看這個最棘手的ajax內(nèi)容加載的問題,也就是如何獲取到商品頁面中的價格信息
首先,遇到這類問題,我們通常有兩個思路:
1、通過js引擎將整個頁面渲染出來之后,在去做內(nèi)容抽取,這個方案對于一些復雜js頁面是唯一解決方案,用神箭手來處理也很簡單,不過由于需要執(zhí)行js,導致抓取速度很慢,不到不得已情況,我們先不使用這個核武器
2、通過剛剛處理分頁的經(jīng)驗,我們可以預先分析ajax請求,然后將這一步多出來的請求和原來的頁面請求做一個關聯(lián)。這種方案適合比較簡單的js頁面中。
OK,介紹完思路,根據(jù)經(jīng)驗,我們感覺尚妝網(wǎng)的ajax加載并沒有十分復雜,所以我們選擇方案二來處理這種ajax頁面加載。
同樣的,首頁我們通過chrome開發(fā)者工具,抓取到這個ajax請求,這里教大家一個小竅門,開發(fā)者工具中,可以篩選請求對象未xhr,這種就是異步請求,我們就很容易發(fā)現(xiàn)我們的嫌疑url:
http://item.showjoy.com/product/getPrice?skuId=22912
我們在頁面中找一下這個22912怎么提取最方便,我們很快就發(fā)現(xiàn)了一個標簽:
這個標簽很干凈,獲取的xpath也很簡單:
//input[@id="J_UItemId"]/@value
這樣就好辦了,我們再看下這個頁面請求的結(jié)果是什么:
{"count":0,"data": {"discount":"6.2","discountMoney":"43.00","originalPrice":112,"price":"69.00","showjoyPrice":"69.00"},"isRedirect":0,"isSuccess":0,"login":0}
可以看出來,是一個典型的json對象,這個就好辦了,神箭手中給我們提供了通過jsonpath提取內(nèi)容的方式,可以很簡單的提取到價格對象,即price對應的值。
那最后我們怎么才能關聯(lián)這個請求呢?這里也是框架中提供的一個方案,叫做attachedUrl,專門用來解決關聯(lián)請求的請求的問題,也就是某一個字段的值可以通過一個關聯(lián)請求的內(nèi)容中抽取出來。語法我就不介紹了,直接上代碼吧:
{ name: "skuid", selector: "http://input[@id="J_UItemId"]/@value", }, { name: "price", sourceType: SourceType.AttachedUrl, attachedUrl: "http://item.showjoy.com/product/getPrice?skuId={skuid}", selectorType: SelectorType.JsonPath, selector: "$.data.price", }
簡單介紹一下attachedUrl的用法,首先我們要設置sourceType為attachedUrl,同時我們要設置一個attachedUrl,即為關聯(lián)請求的地址,其中由于有一個值是動態(tài)的,所以我們需要在這個抽取項之前先抽取一下這個動態(tài)的值,所以我們增加了一個抽取項的名字叫做skuid,在attachedUrl中的調(diào)用方法為{skuid},真實請求時,該項就會被自動替換成我們上一個skuid抽取項抽取到的值。接著,由于我們獲取到的是json返回,因此我們抽取的方式應該是通過jsonpath,最后,寫一個抽取規(guī)則既可,jsonpath比xpath更加簡單,相信大家一看就懂了。
好了,弄了這么多,完整的代碼如下:
var configs = { domains: ["www.showjoy.com","list.showjoy.com","item.showjoy.com"], scanUrls: ["http://list.showjoy.com/search/?q=cateIds%3A1,cateName%3A%E9%9D%A2%E8%86%9C"], contentUrlRegexes: ["http://item.showjoy.com/sku/d+.html"], helperUrlRegexes: ["http://list.showjoy.com/search/?q=cateIds%3A1,cateName%3A%E9%9D%A2%E8%86%9C(&page=d+)?"],//可留空 fields: [ { // 第一個抽取項 name: "title", selector: "http://h3[contains(@class,"choose-hd")]",//默認使用XPath required: true //是否不能為空 }, { // 第二個抽取項 name: "comment", selector: "http://div[contains(@class,"dtabs-hd")]/ul/li[2]",//使用正則的抽取規(guī)則 required: false //是否不能為空 }, { // 第三個抽取項 name: "sales", selector: "http://div[contains(@class,"dtabs-hd")]/ul/li[3]",//使用正則的抽取規(guī)則 required: false //是否不能為空 }, { name: "skuid", selector: "http://input[@id="J_UItemId"]/@value", }, { name: "price", sourceType: SourceType.AttachedUrl, attachedUrl: "http://item.showjoy.com/product/getPrice?skuId={skuid}", selectorType: SelectorType.JsonPath, selector: "$.data.price", } ] }; configs.onProcessHelperUrl = function(url, content, site){ if(!content.indexOf("無匹配商品")){ //如果沒有到最后一頁,則將頁數(shù)加1 var currentPage = parseInt(url.substring(url.indexOf("&page=") + 6)); var page = currentPage + 1; var nextUrl = url.replace("&page=" + currentPage, "&page=" + page); site.addUrl(nextUrl); } return true; } var crawler = new Crawler(configs); crawler.start();
終于搞定了,我們趕緊測試一下爬取的結(jié)果吧:
欣賞自己艱苦的勞動成果是不是很有成就感,不過現(xiàn)在的爬取結(jié)果依然有些美中不足,評論數(shù)和銷售額拿到的都是一個完整的句子,而我們希望得到的是具體的數(shù)字,這個怎么操作呢?這個其實就是一個字段抽取到之后的進一步處理,框架中給我們提供了一個回調(diào)函數(shù)為:
afterExtractField(fieldName, data)
函數(shù)會將抽取名和抽取到的數(shù)據(jù)傳進來,我們只需要通過js的字符串處理函數(shù)對數(shù)據(jù)進行進一步加工既可,直接上完整的修改過的代碼:
var configs = { domains: ["www.showjoy.com","list.showjoy.com","item.showjoy.com"], scanUrls: ["http://list.showjoy.com/search/?q=cateIds%3A1,cateName%3A%E9%9D%A2%E8%86%9C"], contentUrlRegexes: ["http://item.showjoy.com/sku/d+.html"], helperUrlRegexes: ["http://list.showjoy.com/search/?q=cateIds%3A1,cateName%3A%E9%9D%A2%E8%86%9C(&page=d+)?"],//可留空 fields: [ { // 第一個抽取項 name: "title", selector: "http://h3[contains(@class,"choose-hd")]",//默認使用XPath required: true //是否不能為空 }, { // 第二個抽取項 name: "comment", selector: "http://div[contains(@class,"dtabs-hd")]/ul/li[2]",//使用正則的抽取規(guī)則 required: false //是否不能為空 }, { // 第三個抽取項 name: "sales", selector: "http://div[contains(@class,"dtabs-hd")]/ul/li[3]",//使用正則的抽取規(guī)則 required: false //是否不能為空 }, { name: "skuid", selector: "http://input[@id="J_UItemId"]/@value", }, { name: "price", sourceType: SourceType.AttachedUrl, attachedUrl: "http://item.showjoy.com/product/getPrice?skuId={skuid}", selectorType: SelectorType.JsonPath, selector: "$.data.price", } ] }; configs.onProcessHelperUrl = function(url, content, site){ if(!content.indexOf("無匹配商品")){ //如果沒有到最后一頁,則將頁數(shù)加1 var currentPage = parseInt(url.substring(url.indexOf("&page=") + 6)); var page = currentPage + 1; var nextUrl = url.replace("&page=" + currentPage, "&page=" + page); site.addUrl(nextUrl); } return true; } configs.afterExtractField = function(fieldName, data){ if(fieldName == "comment" || fieldName == "sales"){ var regex = /.*((d+)).*/; return (data.match(regex))[1]; } return data; } var crawler = new Crawler(configs); crawler.start();
我們判斷了如果是comment和sales抽取項時,通過正則直接匹配到括號里的數(shù)字,這里注意,網(wǎng)頁上的括號本來是全角的括號,所以千萬不要寫錯了。
這次終于可以開心的看著自己的爬蟲數(shù)據(jù)結(jié)果了:
對爬蟲感興趣的童鞋可以加qq群討論:342953471。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/79453.html
摘要:系列教程手把手教你寫電商爬蟲第一課找個軟柿子捏捏手把手教你寫電商爬蟲第二課實戰(zhàn)尚妝網(wǎng)分頁商品采集爬蟲看完兩篇,相信大家已經(jīng)從開始的小菜鳥晉升為中級菜鳥了,好了,那我們就繼續(xù)我們的爬蟲課程。 系列教程: 手把手教你寫電商爬蟲-第一課 找個軟柿子捏捏手把手教你寫電商爬蟲-第二課 實戰(zhàn)尚妝網(wǎng)分頁商品采集爬蟲 看完兩篇,相信大家已經(jīng)從開始的小菜鳥晉升為中級菜鳥了,好了,那我們就繼續(xù)我們的爬蟲課...
摘要:剩下的同學,我們繼續(xù)了可以看出,作為一個完善的電商網(wǎng)站,尚妝網(wǎng)有著普通電商網(wǎng)站所擁有的主要的元素,包括分類,分頁,主題等等。 系列教程 手把手教你寫電商爬蟲-第一課 找個軟柿子捏捏 如果沒有看過第一課的朋友,請先移步第一課,第一課講了一些基礎性的東西,通過軟柿子切糕王子這個電商網(wǎng)站好好的練了一次手,相信大家都應該對寫爬蟲的流程有了一個大概的了解,那么這課咱們就話不多說,正式上戰(zhàn)場,對壘...
摘要:剩下的同學,我們繼續(xù)了可以看出,作為一個完善的電商網(wǎng)站,尚妝網(wǎng)有著普通電商網(wǎng)站所擁有的主要的元素,包括分類,分頁,主題等等。 系列教程 手把手教你寫電商爬蟲-第一課 找個軟柿子捏捏 如果沒有看過第一課的朋友,請先移步第一課,第一課講了一些基礎性的東西,通過軟柿子切糕王子這個電商網(wǎng)站好好的練了一次手,相信大家都應該對寫爬蟲的流程有了一個大概的了解,那么這課咱們就話不多說,正式上戰(zhàn)場,對壘...
摘要:老規(guī)矩,爬之前首先感謝淘寶公布出這么多有價值的數(shù)據(jù),才讓我們這些爬蟲們有東西可以搜集啊,不過淘寶就不用我來安利了廣大剁手黨相信睡覺的時候都能把網(wǎng)址打出來吧。 系列教程: 手把手教你寫電商爬蟲-第一課 找個軟柿子捏捏 手把手教你寫電商爬蟲-第二課 實戰(zhàn)尚妝網(wǎng)分頁商品采集爬蟲 手把手教你寫電商爬蟲-第三課 實戰(zhàn)尚妝網(wǎng)AJAX請求處理和內(nèi)容提取 都已經(jīng)三節(jié)課了,大家活動活動手腳,咱們開始一場...
摘要:老規(guī)矩,爬之前首先感謝淘寶公布出這么多有價值的數(shù)據(jù),才讓我們這些爬蟲們有東西可以搜集啊,不過淘寶就不用我來安利了廣大剁手黨相信睡覺的時候都能把網(wǎng)址打出來吧。 系列教程: 手把手教你寫電商爬蟲-第一課 找個軟柿子捏捏 手把手教你寫電商爬蟲-第二課 實戰(zhàn)尚妝網(wǎng)分頁商品采集爬蟲 手把手教你寫電商爬蟲-第三課 實戰(zhàn)尚妝網(wǎng)AJAX請求處理和內(nèi)容提取 都已經(jīng)三節(jié)課了,大家活動活動手腳,咱們開始一場...
閱讀 3623·2021-11-24 09:39
閱讀 2557·2021-11-15 11:37
閱讀 2216·2021-11-11 16:55
閱讀 5209·2021-10-14 09:43
閱讀 3711·2021-10-08 10:05
閱讀 3012·2021-09-13 10:26
閱讀 2333·2021-09-08 09:35
閱讀 3541·2019-08-30 15:55