Selenium實戰——天貓淘寶京東買家秀
源碼地址:https://github.com/edisonleolhl/BuyersShow
1、起因
作為一個關注什么值得買已久的人,作為一個微博都關注了好幾個白菜君的人,在各大電商網站上薅羊毛那是再平常不過了。作為一個從來沒看過商品的買家,商品評論里的買家秀自然是重點關注。
然而有的商品,只鐘意其中一種顏色,或者款式,也許這個款式很特別,買的人很少,即使在評論區選擇“帶圖”評價,可能好幾頁才有一個買家秀,這無疑是非常耗時又耗力的。
而且,商家有時候為了評價數量更多、更好看,新款的商品會和老款商品放在一起賣,選擇款式的時候區分開,但是評價里卻還有很多老款的,新款的寥寥無幾,不禁想到:如果能一次性只看一種款式的買家秀就好了。
作為一個Python爬蟲的實踐者,就琢磨著能不能寫個自動化工具,告訴程序商品的url地址,然后在本地就會有所有的買家秀圖片,并且是按款式區分的,于是,說干就干,總共用時一天,反正坑挺多的。。
2、步驟
首先,訪問這些評論,是不需要登錄的,所以最開始我搞了挺久的cookies,后來發現根本不需要。。
selenium作為一個強大的自動化工具,幾乎可以完全模擬瀏覽器的所有行為,抓取買家秀自然不在話下,如果你對selenium還不太了解,請看這篇文章:http://www.lxweimin.com/p/c8ed978dd0ab
-
先抓淘寶吧,進入商品頁面后,先要跳轉到評論部分,點擊“累計評論”這個按鈕就好了。注意了,先得把窗口最大化哦,
driver.maximize_window()
2018111-taobao -
用xpath語法來選擇這個按鈕吧,如何快速知道這個元素的xpath路徑呢,推薦chrome瀏覽器安裝xpath helper這個插件,打開插件,按住shift,把鼠標移動到元素上,框里自動出來xpath路徑了。
driver.find_element_by_xpath(".//*/a[@id='J_ReviewTabTrigger']").click() # 累計評論
2018111-taobaoxpath -
點擊“有圖”
driver.find_element_by_xpath(".//*/label/input[@id='reviews-t-val3']").send_keys(Keys.SPACE) # 有圖
-
接下來是得到所有圖片,這個比較簡單,因為所有買家秀圖片都是在li這個標簽里面,而且這個li標簽的class='photo-item',所以xpath語法這樣寫就好了,最后會得到一個關于img_ele_list的列表:
img_ele_list = driver.find_elements_by_xpath(".//*/li[@class='photo-item']/img")
-
得到img_ele,調用img_ele_list[i].get_attribute('src'),即可得到圖片的url,但是注意,這個時候圖片只有40x40!因為這是小圖,那大圖怎么辦,點開一個買家秀,查看大圖,發現它們的url有個規律:
-
40x40:
2018111-40x40 -
400x400:
2018111-400x400 -
url那里除了40x40、400x400,其他完全一樣,那其他圖片是不是這樣的呢?經過實踐發現,把這里改成500x500,一樣可以顯示圖片,圖片大一號而已。通過總結得到,一般人都是用手機拍的照片,一般像素值肯定會大于400x400,于是這里直接替換成400x400即可,阿里已經存儲了同一張圖片的不同格式(雖然我覺得挺浪費空間的)。
url = img_ele_list[i].get_attribute('src').replace('40x40', '400x400')
-
-
好,圖片下載完了,如果直接下載到本地,文件名肯定是亂七八糟的,這與我們“想要按款式分開買家秀”的初衷不符了,在存儲圖片的時候,應該知道這個圖片是哪個款式,于是,我們需要找到這個圖片元素所在的那個評論用戶所買的款式。
2018111-yuanma -
根據xpath語法,我們得到了img_ele,需要往上找3級父節點,再找弟弟,再找class='tb-r-info'的div,
p = img_ele_list[i].find_element_by_xpath("./../../../following-sibling::div[1]/div[@class='tb-r-info']")
-
但是得到的輸出是這樣的:
p = '2017年11月27日 10:06顏色分類:紅色 參考身高:130cm'
-
這里用正則表達式,把日期和款式分開:
d = re.findall (r'^20[0-9][0-9].[0-1][0-9].[0-3][0-9].', p.text)[0] p = re.findall (r'(?<=[0-9][0-9]:[0-9][0-9]).+$', p.text)[0].replace ('/', '-').replace ('\\', '--') # 款式要作為文件名的,所以不要/和\\
-
從上圖可以看到,同時也可以找到買家秀對應的用戶評論,這里直接給出xpath語法:
c = img_ele.find_element_by_xpath(".//../../../preceding-sibling::div[1]").text.replace ('/', '-').replace ('\\', '--')
好的,一個完整的圖片以及信息找到了,要遍歷這一頁的所有買家秀,怎么做呢?
前文我們得到了img_ele_list,我們可以對其遍歷,對每個img_ele,找到其對應的評論、日期、款式,各自加入到一個新的列表中,最后4個列表長度相等,代碼如下:
# 得到把該頁的所有買家秀,存入列表中,并且創建另外三個列表,長度一樣,
# 分別存儲每個買家秀的property和對應的用戶發表的評論時間及內容
# 我認為帶買家秀的評論比較重要,最后在圖片文件名中給出
img_ele_list = driver.find_elements_by_xpath(".//*/li[@class='photo-item']/img")
property_list = []
datetime_list = []
comment_list = []
p, d, c = '', '', ''
for img_ele in img_ele_list:
try:
p = img_ele.find_element_by_xpath("./../../../following-sibling::div[1]/div[@class='tb-r-info']") # p = '2017年11月27日 10:06顏色分類:紅色 參考身高:130cm'
d = re.findall (r'^20[0-9][0-9].[0-1][0-9].[0-3][0-9].', p.text)
if len(d) > 0:
d = d[0] # 得到日期時間
else:
d = ''
p = re.findall (r'(?<=[0-9][0-9]:[0-9][0-9]).+$', p.text)
if len(p) > 0:
p = p[0].replace ('/', '-').replace ('\\', '--') # 刪掉日期時間,得到款式等信息
else:
p = ''
c = img_ele.find_element_by_xpath(".//../../../preceding-sibling::div[1]").text.replace ('/', '-').replace ('\\', '--')
except Exception as e:
print("ERROR happens when getting corresponding property of img :::", e)
datetime_list.append (d)
property_list.append (p)
comment_list.append (c)
# 四個列表長度一致,所以可以用同一個指針i來對四個列表同步遍歷
for i in range(len(img_ele_list)):
url = img_ele_list[i].get_attribute('src').replace('40x40', '400x400')
with open (path + '/' + property_list[i] + '-' + datetime_list[i] + '-' + str(time.time()) + '.jpg', 'wb+') as f_img:
try:
f_img.write (urllib.request.urlopen (url).read ())
except:
print("Img url illegal: " + url)
else:
print ("A new img!!! PROPERTY = %s, DATETIME = %s\n, COMMENT = %s\n, DOWALOADING url = %s"
%(property_list[i], datetime_list[i], comment_list[i], url))
-
可以看到,完成了4個列表后,就開始下載這些圖片了,圖片名字舉例如:
顏色:卡其色 尺碼:170-92A-M-2017年10月04日-1515648926.131808.jpg
翻頁
-
翻頁從來都是一個重難點,但是掌握規律,是有跡可循的。看截圖,評論有兩頁,第一頁是這樣的:
2018111-next2018111-nextlast -
這里給出我的辦法:找到pg-current的li,查它的弟弟元素,得到其文本值,如果是數字,則還沒有到最后一頁,如果不是數字,則到最后一頁(即“下一頁”),于是在這里用try...except捕捉一下,再所有代碼之上套一個while循環,于是,代碼如下:
while True: # 得到把該頁的所有買家秀,存入列表中,并且創建另外三個列表,長度一樣, # 分別存儲每個買家秀的property和對應的用戶發表的評論時間及內容 # 我認為帶買家秀的評論比較重要,最后在圖片文件名中給出 img_ele_list = driver.find_elements_by_xpath(".//*/li[@class='photo-item']/img") property_list = [] datetime_list = [] comment_list = [] p, d, c = '', '', '' for img_ele in img_ele_list: try: p = img_ele.find_element_by_xpath("./../../../following-sibling::div[1]/div[@class='tb-r-info']") # p = '2017年11月27日 10:06顏色分類:紅色 參考身高:130cm' d = re.findall (r'^20[0-9][0-9].[0-1][0-9].[0-3][0-9].', p.text) if len(d) > 0: d = d[0] # 得到日期時間 else: d = '' p = re.findall (r'(?<=[0-9][0-9]:[0-9][0-9]).+$', p.text) if len(p) > 0: p = p[0].replace ('/', '-').replace ('\\', '--') # 刪掉日期時間,得到款式等信息 else: p = '' c = img_ele.find_element_by_xpath(".//../../../preceding-sibling::div[1]").text.replace ('/', '-').replace ('\\', '--') except Exception as e: print("ERROR happens when getting corresponding property of img :::", e) datetime_list.append (d) property_list.append (p) comment_list.append (c) # 四個列表長度一致,所以可以用同一個指針i來對四個列表同步遍歷 for i in range(len(img_ele_list)): url = img_ele_list[i].get_attribute('src').replace('40x40', '400x400') with open (path + '/' + property_list[i] + '-' + datetime_list[i] + '-' + str(time.time()) + '.jpg', 'wb+') as f_img: try: f_img.write (urllib.request.urlopen (url).read ()) except: print("Img url illegal: " + url) else: print ("A new img!!! PROPERTY = %s, DATETIME = %s\n, COMMENT = %s\n, DOWALOADING url = %s" %(property_list[i], datetime_list[i], comment_list[i], url)) # ---------------翻頁--------------- driver.execute_script ("window.scrollBy(0,-100)") time.sleep(1) try: next = driver.find_element_by_xpath(".//*/ul/li[@class='pg-current']/./following-sibling::li[1]") # 淘寶的評論頁碼工具條,每個都是li標簽 if next.text.isdigit(): ActionChains(driver).click(next).perform() time.sleep(1) else: exit() except: print('only one page with img') exit()
3、結果
-
在項目文件夾下,運行items.py,提示輸入url,復制你在瀏覽器地址欄中的url,粘貼到命令行上(我用的是Pycharm IDE,最后要加個空格,防止IDE自動打開url),按下回車即可,這里找個圖片比較多的商品吧。
2018111-pycharmrun -
單個輸出是這樣的:
A new img!!! PROPERTY = 顏色分類:米灰色厚絨 尺碼:38, DATETIME = 2017年12月27日 , COMMENT = 包裝特別好,大盒子套小盒子,高大上,鞋特別暖和,毛毛特別多特別軟,鞋底也厚,走路軟軟的,哈哈非常喜歡,都說好看,尺碼也特準,超級喜歡 , DOWALOADING url = https://img.alicdn.com/imgextra/i2/0/TB2wrG1klTH8KJjy0FiXXcRsXXa_!!0-rate.jpg_400x400.jpg
因為一個買家可能有多個買家秀圖片,還記得上文說的4個列表長度一致嗎?好幾個圖片對應的款式、日期、評論,都是一樣的,所以看起來命令行中會有重復的,但是url絕對是不一樣的(即都是不同的買家秀,除非買家發表評論的時候手抖發了兩張一樣的)
在本地文件夾中可以輕松查看:
- 因為圖片文件名開頭是按款式區分的,所以文件夾中“按名稱排序”即可把同款商品放在一起瀏覽,簡單方便。
4、其他電商
天貓
-
注意天貓和淘寶是兩套不同的網頁模版,所以還得重新設計xpath語法,主要有這幾點需要更改的:
各種xpath
翻頁操作(詳情參考github上源碼的注釋)
京東
-
京東的帶圖評價其實挺方便的,但是還是不能按款式瀏覽。
2018111-jd 對于jd而言,得到圖片后,查詢對應評價、日期、款式其實挺簡單的,因為像上圖一樣,一個頁面只有一個評論、日期、款式,很好處理,具體看源碼即可。
翻頁操作,也是直接點下一個,就不詳細敘述了。
5、后記
-
小工具真的特別特別實用,才寫了每兩天,就用了好幾次了(雖然都是些白菜),但是真的特別方便,買家秀才是反映商品的有效途徑。
2018111-dikan2018111-hat