爬取天貓國際、京東全球購、淘寶全球購的商品資料
公司內部mini專案–智慧選品
“智慧選品”專案主要是方便採購人員瞭解其他競品平臺的商品資料,將其他平臺上賣的特別好的商品資料展示給採購人員,方便他們去採購商品,擴大公司自己的商品,所以就需要爬取其他平臺的資料,本著需求出發,這裡主要爬取天貓國際、京東全球購、淘寶全球購的商品屬性資料,包括標題、品牌、價格、銷量、評論數、收藏數、好評數等等,再利用推薦演算法對資料排序。
需要解決的問題
- 商品資料獲取
- 新品識別
- 推薦演算法
備註說明:
1、首先商品資料獲取,其實京東全球購的資料獲取不到銷量,而且評論數也不是準確數字,這裡只盡可能的採集資料,實在沒有的商品屬性也沒辦法。
2、新品識別其實是一個重點,因為你需要把其他平臺中不存在我們商品資料的商品找出來,而且要精細到規格,這裡就比較難受,因為像口紅這樣的商品,可能顏色就有10多個,要找出不存在我們商品資料中但在其他平臺上的商品,難度較大,這裡有很多問題,目前討論出來的方法是,利用商品標題和商品一些屬性做相似度匹配,這準確率實際效果不高。
3、推薦演算法這裡比較簡單,後面單獨開一篇部落格講解。
資料獲取
這裡使用的技術都是一樣的,我先講解利用什麼技術手段來獲取資料,其實目前獲取資料手段也較多:
方法已將講解OK了,我的目的是儘快爬取到資料,所以我選擇了第二種方法,後面也覺得這種方法是真的簡單,所以接下來就會講解此方法如何獲取到三個電商平臺的資料。
pom引用
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-server</artifactId>
<version>2.53.0</version>
</dependency>
京東資料
1、採集首頁
這個採集首頁的意思就是開始採集的第一個頁面,這個頁面作為我們的初始頁面,方便我們通過該頁面獲取到其他連結,然後不斷的採集下去,由於電商的特殊性,電商的商品資料都是有商品列表頁的,所以我們可以將商品列表頁作為採集的入口,如圖所示:
我們可以看到,如上圖所示,這是京東-美妝個護-香水彩妝-口紅 相關的商品資料,口紅是三級類目,其中圖中標1的是口紅類目資訊,2表明這個商品的分頁數,一共有157頁,其中紅色 3部分表明 商品 主要區域中,一行是4個商品,但其實這一頁有12行,也就說一頁有4*12=48個商品,這是關於口紅的所有商品,這個url=京東-口紅類目商品列表頁;大家可以訪問來了解,這樣,我們可以通過該頁面來獲取商品詳情頁連結和標題、價格等等,當然通過再訪問詳情頁,可以瞭解更多商品詳情資料,這裡我們決定了這個頁面是初始頁,那我們如何利用selenium工具來實現模擬人的行為來登入這個頁面呢,程式碼如下:
System.setProperty("webdriver.chrome.driver", "D:\\SoftBuild\\chromedriver_win32\\chromedriver.exe");
// driver即為瀏覽器物件
WebDriver driver = new ChromeDriver();
String url="https://search.jd.hk/Search?keyword=口紅&enc=utf-8";
driver.get(url);
try {
TimeUnit.SECONDS.sleep(10); // 10s的sleep,這樣你就可以看到很多商品資料
} catch (InterruptedException e) {
System.out.println("Sleep方法出錯");
}
driver.close(); //此方法是關閉視窗
driver.quit(); // 此方法是關閉瀏覽器,整個瀏覽器程序也被關閉
備註:其中chromedriver.exe的下載地址:chrome瀏覽器驅動下載連結,這裡也會涉及到跟你自己電腦上谷歌瀏覽器的版本問題,大家可以看看這個網站的瀏覽器版本和驅動版本對應關係,網站:selenium(三)之webDriver與瀏覽器版本問題
那我們再來下一個步驟。
2、獲取商品詳情頁連結
首先要分析一下此頁面的頁面原始碼:
<li class="gl-item">
<div class="p-tab">
<ul>
</ul>
</div>
<div class="p-cnt">
<div class="item hasComment" skuid="J_1994030801">
<div class="p-img">
<a href="//item.jd.hk/1994030801.html" target="_blank">
<img src="//img11.360buyimg.com/cms/jfs/t2296/67/2540291745/1095/28285fbe/570e2074Nf22696dd.gif" data-original="//img10.360buyimg.com/n7/jfs/t18805/53/812555036/78482/c5235542/5aaa2226N3eac3269.jpg" class="lazy"></a>
<div class="other">
<div class="cj-concern">
<i>
</i>
<em>關注</em>
</div>
<div class="p-operate">
<a href="javascript:;" skuid="1994030801" class="p-o-btn contrast J_contrast">
<i>
</i>對比</a>
</div>
</div>
</div>
<div class="price-icons">
<div class="price">
<span>
<b>
</b>
</span>
<div class="sam">
</div>
</div>
</div>
<div class="p-name">
<a href="//item.jd.hk/1994030801.html" target="_blank">
<em>魅可(M.A.C) 【滿199減100】 MAC魅可
<font class="skcolor_ljg">口紅</font>顯色豐潤脣膏
<font class="skcolor_ljg">口紅</font>3g Chili鐵鏽紅/小辣椒色</em></a>
</div>
<div class="p-conduct">
<em></em>
</div>
<div class="p-buy">
<div class="assess">
<a href="//item.jd.hk/1994030801.html#comments-list" target="_blank" class="comment">
<i>
</i>
<em>9164</em></a>
</div>
</div>
<div class="p-icons" style="max-width: 200px">
</div>
</div>
</div>
</li>
這是一個商品模組的程式碼,其中我們可以瞭解一下內容:
其他也有相應的價格和銷量的div標籤,這裡可以明顯瞭解到這些內容。上一節我們知道如何訪問這些內容,接下來我們可以來了解一下,怎麼獲取網頁內容。
程式碼:
System.setProperty("webdriver.chrome.driver", "D:\\SoftBuild\\chromedriver_win32\\chromedriver.exe");
// driver即為瀏覽器物件
WebDriver driver = new ChromeDriver();
String url="https://search.jd.hk/Search?keyword=口紅&enc=utf-8";
driver.get(url);
try {
TimeUnit.SECONDS.sleep(10); // 10s的sleep,這樣你就可以看到很多商品資料
} catch (InterruptedException e) {
System.out.println("Sleep方法出錯");
}
WebElement divmain=driver.findElement(By.id("plist")); // 這個plist是頁面所有商品所在div的id
List<WebElement> divGoodlist=divmain.findElements(By.className("gl-item")); // 這個是<li class="gl-item">的標籤,通過className來獲取所有匹配到的頁面元素。正常這個大小應該是48。
for(WebElement goodEle:divGoodlist){
// 這裡我們獲取標題,通過這個來了解一下。
WebElement nameEle=goodEle.findElement(By.className("p-name"));
WebElement aele=nameEle.findElement(By.tagName("a"));
System.out.println("標題:"+aele.getText();
System.out.println("連結:"+aele.getAttribute("href"));
}
driver.close(); //此方法是關閉視窗
driver.quit(); // 此方法是關閉瀏覽器,整個瀏覽器程序也被關閉
這樣我們就獲取到了商品詳情頁和標題。如果你要獲取其他內容也都可以,但是要注意,你是通過class 屬性來獲取還是通過id 一以及其他 tag來獲取,匹配該屬性的元素是唯一的還是多個。不然容易報錯。
備註:
京東的網頁原始碼裡class 屬性比較少空格,天貓網頁原始碼裡面很多class都是空格,這裡其實有區別,大家繼續往下看天貓的資料獲取。
3、下一頁
這個很關鍵,因為這一頁商品資料獲取完了,就必須獲取下一頁的資料,這裡我們看下網頁中原始碼的下一頁。
<div id="J_bottomPage" class="p-wrap">
<span class="p-num">
<a href="/search?keyword=%E5%8F%A3%E7%BA%A2&enc=utf-8" class="curr">1</a>
<a href="/search?keyword=%E5%8F%A3%E7%BA%A2&enc=utf-8&page=2" class="">2</a>
<a href="/search?keyword=%E5%8F%A3%E7%BA%A2&enc=utf-8&page=3" class="">3</a>
<a href="javascript:;" class="pn-break">...</a> <a href="/search?keyword=%E5%8F%A3%E7%BA%A2&enc=utf-8&page=157" class="">157</a>
<a href="/search?keyword=%E5%8F%A3%E7%BA%A2&enc=utf-8&page=2" class="pn-next">下一頁<i>></i></a>
</span>
<span class="p-skip"> <em>共<b>157</b>頁 到第</em>
</span>
</div>
其中a標籤中有一個class=”pn-next”的,這個是點選下一頁的操作,於是我們可以用來模擬滑鼠點選。
具體程式碼如下:
/**
* 京東的下一頁操作
* @param driver
* @return
*/
public boolean getNextPage(WebDriver driver){
boolean falg=false;
if(!driver.getPageSource().contains("下一頁")){ // 判斷頁面中是否有下一頁,因為有的入口只有一頁資料,沒有下一頁的按鈕
return falg;
}
WebElement divElement= driver.findElement(By.className("pn-next")); // 獲取這個元素
divElement.click(); // 滑鼠點選下一頁
System.out.println("----點選跳轉到下一頁----");
return falg;
}
這段程式碼就成功跳轉到下一頁,這樣就可以再獲取下一頁的商品資料。所以你需要自己組合這兩個功能,先獲取當前頁面的商品資料,再判斷有沒有下一頁,有下一頁,就開始點選跳轉到下一頁,再獲取下一頁的商品資料。
天貓資料獲取
1、採集首頁
這裡天貓的資料是一行5個,一頁是12行,那麼基本一頁就是60個商品,天貓只顯示100頁,如果你的關鍵詞太少了,只顯示前6000個商品,所以,你看到的100頁並不代表只有100頁,其實天貓商品的資料規模是遠超京東的,所以碰到這個情況就必須細分採集入口,比如:從三級類目中再根據品牌來篩選,具體到三級類目下的某個品牌,這樣條件多了,具體到品牌的商品數量就相對少了,舉例就是:三級類目下有100個品牌,每個品牌有100頁資料,那麼就可以採集100*100*60=600000個商品了,這樣可以爬取更多的商品連結。當然,你可以自己定義自己的採集策略。
2、獲取商品屬性
檢視頁面原始碼:
<div class="product " data-id="544794131401" data-atp="a!,,50010808,,,,,,,,">
<div class="product-iWrap">
<div class="productImg-wrap">
<a href="//detail.tmall.hk/item.htm?id=544794131401&skuId=3414795933847&areaId=330108&standard=1&user_id=1954290542&cat_id=55950003&is_b=1&rn=a48427a02adeec0fd36ebb3a42aef0d8" class="productImg" target="_blank" data-p="1-10">
<img src="" "//img.alicdn.com/bao/uploaded/i5/tb1inzzpxxxxxbsapxxcwky_xxx_053854.jpg_b.jpg"/>
</a>
</div>
<p class="productPrice">
<em title="255.00"><b>¥</b>255.00</em>
<i class="national-flag tm-unit-FR"></i>
</p>
<div class="productTitle productTitle-spu">
<!--product.spuTitleShow:true ,product.itemTitleShow:$product.itemTitleShow-->
<a href="//detail.tmall.hk/item.htm?id=544794131401&skuId=3414795933847&areaId=330108&standard=1&user_id=1954290542&cat_id=55950003&is_b=1&rn=a48427a02adeec0fd36ebb3a42aef0d8" target="_blank" title="滋潤 保溼 防水" data-p="1-11">Dior/迪奧 烈豔藍金脣膏</a>
<a class="lightspot" href="//detail.tmall.hk/item.htm?id=544794131401&skuId=3414795933847&areaId=330108&standard=1&user_id=1954290542&cat_id=55950003&is_b=1&rn=a48427a02adeec0fd36ebb3a42aef0d8" target="_blank" title="滋潤 保溼 防水" data-p="1-11">滋潤 保溼 防水</a>
</div>
<div class="productShop" data-atp="b!1-3,{user_id},,,,,,">
<a class="productShop-name" href="//store.taobao.com/search.htm?user_number_id=1954290542&rn=a48427a02adeec0fd36ebb3a42aef0d8" target="_blank">
駿然海外專營店
</a>
</div>
<p class="productStatus">
<span>該款月成交 <em>4.2萬筆</em></span>
<span data-icon="small" class="ww-light ww-small m_wangwang J_WangWang" data-item="544794131401" data-nick="駿然海外專營店" data-tnick="駿然海外專營店" data-display="inline" data-atp="a!1-2,,,,,,,1954290542"></span>
</p>
</div>
</div>
這是天貓的商品模組html程式碼,基本我也就不講了,重點還是你自己通過元素定位,定位到相應的標籤上,標籤上有id那就根據id定位,沒有id,那就根據class來定位。
程式碼:
System.setProperty("webdriver.chrome.driver", "D:\\SoftBuild\\chromedriver_win32\\chromedriver.exe");
// driver即為瀏覽器物件
WebDriver driver = new ChromeDriver();
String tmdUrl="https://list.tmall.hk/search_product.htm?spm=a2231.7718719.2014120102.33.4a5c12feFloXgU&cat=55950003&sort=s&acm=lb-zebra-34359-425776.1003.8.519261&_ksTS=1429862287170_954&from=sn_1_rightnav&_input_charset=utf-8&style=g&s=0&search_condition=7&industryCatId=52830004&callback=__jsonp_cb&active=1&abtest=null&scm=1003.8.lb-zebra-34359-425776.ITEM_14455541646861_519261";
driver.get(tmdUrl);
WebElement goodmain=driver.findElement(By.id("J_ItemList")); // 商品模組的div區域
List<WebElement> goodelement=driver.findElements(By.className("product-iWrap"));
String falg="productTitle productTitle-spu";
for(WebElement goodele :goodelement){
WebElement div= goodele .findElement(By.cssSelector(falg));
List<WebElement> acl=div.findElements(By.tagName("a")); // 將特定div下的所有a標籤都獲取到了。
// 後續自己處理
}
2、下一頁
天貓的下一頁資料也很容易獲取,可以自己去參考京東的那個自己做一個,嘗試測試一下;
爬蟲過程中碰到的問題
在爬取商品資料的過程中碰到了很多問題,這些問題也是其他爬蟲工作者碰到的問題,這裡寫出來,其實我覺得所有的爬蟲的重點就是解決這些問題,其他都是小問題,這些問題解決了,爬蟲就很順利。
1、驗證碼
驗證碼就是為了為了反爬,不讓你爬取,但是如今,驗證碼的問題也基本都沒有太多問題,許多打碼平臺可以幫助我們解決這個問題,當然自己去用機器學習或者深度學習來訓練模型,然後來實現一個識別驗證碼。
2、登入
天貓和淘寶資料都會出現這個問題,當你頻繁的訪問網站的時候,會跳轉到登入介面,要求使用者登入,這個問題的解決是用大量的手機來申請淘寶賬號,然後利用這些賬號獲取cookie ,然後攜帶cookie去訪問這些頁面,也可以當出現驗證碼的時候實現一個賬號登入的功能。
3、限制訪問次數,載入不了頁面內容
這個問題也會出現,但是如果有賬號的話,這個問題相對不會那麼激進,不會那麼容易被觸發,所以這裡利用動態IP技術來說相對可以解決,不過不推薦使用免費的ip,免費的ip容易獲取,但是也容易被反爬衝的網站拿來更好的限制這些ip的訪問,所以花錢購買有用的ip吧,這個沒得辦法,這些IP最好也是全國各地的IP,這樣就不會被反爬。
4、攜帶cookie
電商平臺利用cookie做了很多事情,他們利用cookie來表明使用者身份,和伺服器的session一起工作,其中我瞭解到的比較少,但感覺cookie可以有效的針對直接的http請求,其實selenium工具是不需要自己在程式碼裡設定cookie的,因為selenium工具是啟動一個瀏覽器,瀏覽器訪問網站是自己生成一些cookie的,這個可以自己嘗試一下,檢視selenium工具啟動的瀏覽器的後臺cookie。
selenium 總結
這個工具是在有介面的情況下,比如Windows和帶介面的Linux環境下,如果要部署到生產環境中就會有一個問題,一般的生產環境都是Linux無介面版本,所以採取的方案就是:
1、部署沙盒,xvfb軟體就是一個部署在伺服器的沙盒軟體,這樣,selenium工具啟動一個瀏覽器可以直接執行在xvfb中。
2、使用phantomjs工具,此工具也是一個瀏覽器工具,可以當做瀏覽器使用,有了這個工具就可以不使用谷歌瀏覽器等等。
總結
京東資料的反爬機制相對薄弱,可能京東還沒開始注重這一塊,淘寶和天貓相對較為成熟,這裡的反爬都是針對這兩者的,希望這些問題可以幫助大家,特別是有興趣的同學,可以手動的去了解一下。