前言
大家都喜歡買東西,而現代人購物很大一部份會從線上的購物平台來尋找,像是台灣前幾大的 PChome24h購物、momo購物網、蝦皮購物、露天拍賣等等。
這次的Python網路爬蟲實例系列要來挖掘"蝦皮購物",試著說明如何抓取各項商品資訊、評價資料,跟著文章體驗爬蟲的樂趣吧~
備註:此文僅教育學習,切勿用作商業用途,個人實作皆屬個人行為,本作者不負任何法律責任
套件
此次 Python 爬蟲主要使用到的套件:
安裝
|
|
尋找抓取資料的方法
我們想要爬取"搜尋商品結果"頁面的商品資訊,以下以搜尋"手機保護殼"來示範。
前往蝦皮購物網站,一開始當然是打開我們熟悉的 開發人員工具 (F12 或 Ctrl + Shift + i),切換到"Network" > "XHR",並在網頁上方搜尋欄打入關鍵字、點擊搜尋。
接著在開發人員工具頁面中,它會記錄著每個請求,從中尋找蝦皮購物是否採用動態載入的方式載入資料,可以一個一個查看,或使用搜尋(Ctrl+f)來找商品名稱。
在其中一條 ?by=relevancy&keyword=...
開頭的請求中發現了搜尋結果商品資訊。
開發人員工具切換到"Headers"頁面查看請求的網址與方法。
請求網址:https://shopee.tw/api/v2/search_items/?by=relevancy&keyword=手機保護殼&limit=50&newest=0&order=desc&page_type=search&version=2
請求方法:GET
但如果你直接拿此網址去用 Python requests.get(url)
,會發現回傳資料會不完整、裡面的多項數據也是錯誤的,只在 Headers 加上 user-agent
顯然是不夠的。
經過我的測試,將 referer
加入 Headers 後資料就完整了。
(放到 referer
前記得要將 url 編碼才不會噴錯)
但又遇到一個問題,仔細看會發現,怎麼取得的資料和網頁上看到的順序不一樣?!
首先猜測 Headers 是否還缺少哪個參數導致,經過多次嘗試後,發覺是 x-api-source 與 cookie。
x-api-source 帶入 pc
即可,很簡單。
但 cookie 則需要當中的 SPC_SI 值,這個值該從何而來。
我將 SPC_SI 的值貼到搜尋(Ctrl+f),來找找這個值是從哪邊來的。
發現其中一個是在請求 https://shopee.tw/api/v4/search/product_labels
後,返回的結果 set-cookie 中有設定 SPC_SI。
因此這部分我就先嘗試使用 requests 的 Session,他會把每次請求都算在同一個 session 裡,像是 cookie 之類的都會保持,這樣我就不用還要將 cookie 讀出來,下一次請求再設定了。
|
|
回傳資料是 JSON 格式,可以使用 requests 提供的 r.json()
轉換。
其他兩個"商品資訊"與"評價資訊"都是採用同樣的方法來尋找請求網址,這邊就不再重複說明。
下面我將"搜尋商品"、"商品資訊"、"評分資訊"所找出來的請求路徑、參數內容及回傳資料整理出來說明。
搜尋商品
搜尋商品的頁面大致上能分為三個部分,藍色方框為商品結果、綠色方框為篩選功能(雖然應該算排序)、紫色方框為條件篩選。
請求路徑
GET https://shopee.tw/api/v2/search_items/?by=relevancy&keyword={關鍵字}&limit=50&newest=0&order=desc&page_type=search&version=2
範例:https://shopee.tw/api/v2/search_items/?by=relevancy&keyword=手機保護殼&limit=50&newest=0&order=desc&page_type=search&version=2
referer
:https://shopee.tw/search?keyword={關鍵字}
(也就是搜尋頁面網址,記得將 url 編碼)
請求參數
來看一下請求網址帶的參數有哪些:
by
和order
排序用,也就是網頁上面這欄(雖然它這邊是寫篩選,但其功能是排序):
篩選 | by | order |
---|---|---|
綜合排名 | relevancy | desc |
最新 | ctime | desc |
熱銷 | sales | desc |
價格(高到低) | price | desc |
價格(低到高) | price | asc |
keyword
:很明顯就是想要搜尋的關鍵字。limit
:一次請求最大回傳的結果數量,預設20個、最多100個,但如果給超過100個,會回傳10個。newest
:偏移量的概念,如果limit設50、newest設100,就如同取得第三頁(第101~150個)。page_type
:設定search代表我們使用搜尋。還有像是shop,則用在查看某一賣場內商品。version
:可能是指 API 的版本。條件篩選
在網頁左邊的位置,有許多類別可以選擇,底下會一一介紹,至於參數的值,某些數量較多就不全部列出了(像是"用送方式"、"分類"、"品牌")。
如果有使用"條件篩選",請求會再多加上 skip_autocorrect=1 (跳過自動修正),這個參數不確定會產生怎樣的影響。
某些參數可以給多個值,其中就使用,
隔開,例如運送方式要"全家、7-11",參數就設定為shippings=1,2
條件 | 參數 |
---|---|
運送方式 | |
全家 | shippings=1 |
7-11 | shippings=2 |
賣家宅配 | shippings=8 |
出貨地點 | |
台灣 | locations=-1 |
海外 | locations=-2 |
分類 | |
ASUS保護殼 | categoryids=7964 |
卡通殼 | categoryids=17360 |
品牌 | |
NOKIA | brandids=137374 |
ASUS | brandids=4747 |
價格 | |
最小 100 元 | price_min=100 |
最大 500 元 | price_max=500 |
評價 | |
5星 | rating_filter=5 |
4星或以上 | rating_filter=4 |
賣場類型 | |
蝦皮商城 | official_mall=1 |
蝦皮優選 | shopee_verified=1 |
商品保存狀況 | |
新商品 | conditions=new |
二手商品 | conditions=used |
付款方式 | |
信用卡 | pay_credit_card=1 |
服務與促銷 | |
目前有折扣 | with_discount=true |
運費補助 | shipping_fee_included=true |
商城最低價 | filter_lowest_price_guarantee=1 |
多件優惠 | wholesale=1 |
影音介紹 | filter_video=1 |
快速出貨 | label_ids=1000028 |
蝦幣回饋 | label_ids=1000040 |
* "商品保存狀況"裡如果你兩個都勾,會等於兩個都不勾。
* 舉例來說:
我查詢"手機保護殼",並以"最熱銷"排序,
條件篩選有"運送方式 7-11"、"價格最高 600 元"、"評價四星或以上"、"新商品",
一次最多 100 筆商品https://shopee.tw/api/v2/search_items/?by=sales&conditions=new&keyword=手機保護殼&limit=100&newest=0&order=desc&page_type=search&price_max=600&rating_filter=4&shippings=2&skip_autocorrect=1&version=2
回傳資料
它以 JSON 格式回傳,商品會在 items 欄位內,每一個商品有許多欄位,這邊挑幾個來說明。
欄位 | 代表意思 |
---|---|
itemid | 商品ID |
shopid | 賣場ID |
name | 商品名稱 |
brand | 品牌 |
shop_location | 賣場位置(出貨地) |
ctime | 上架時間(時間戳) |
can_use_wholesale | 是否有多件優惠 |
show_free_shipping | 是否顯示免運 |
shopee_verified | 是否為蝦皮優選 |
show_shopee_verified_label | 是否顯示蝦皮優選標籤 |
is_official_shop | 是否為官方商店 |
show_official_shop_label | 是否顯示官方商店標籤 |
show_official_shop_label_in_title | 是否在標題中顯示官方商店標籤 |
is_adult | 是否為成人商品 |
historical_sold | 已售出數量 |
stock | 庫存 |
liked_count | 喜歡數 |
view_count | 瀏覽數 |
currency | 貨幣 |
has_lowest_price_guarantee | 最低價格保證 |
discount | 折扣 |
price | 價格(要再除100000) |
price_before_discount | 折扣前價格 |
price_min | 價格範圍(最低) |
price_max | 價格範圍(最高) |
price_min_before_discount | 折扣前價格範圍(最低) |
price_max_before_discount | 折扣前價格範圍(最高) |
cmt_count | 評價數量 |
item_rating | 評價 |
image | 商品圖片(封面) |
images | 商品圖片 |
video_info_list | 影片 |
tier_variations | 規格 |
voucher_info | 優惠券資訊 |
* 回傳資料裡面並無"商品網址",要自己串,如下所示:https://shopee.tw/{商品名稱}-i.{賣場ID}.{商品ID}
https://shopee.tw/犀牛盾-iPhone12-11-Pro-Mini-Se-XR-7-8-Xs-Max-手機-防摔殼-防摔邊框-台灣公司貨-i.9060351.1558498138
商品名稱中間加如有 " "(空白) 或 "/" 要轉換成 "-",而且如有連續多個也要合併成一個。
但…我發現商品網址其實不一定需要"商品網址",就算這部分隨便給也都可以(但不能不給),像是上方範例改成這樣也可😆。https://shopee.tw/一代一代-i.9060351.1558498138
[更新 2021/04/04] "商品網址"還有另一種樣式,就不需要包含商品名稱了,如下:https://shopee.tw/product/{賣場ID}/{商品ID}
https://shopee.tw/product/6453718/103810019
* 商品圖片是一串碼,要取得圖片網址需再如下自行補上,如要取得其縮圖(解析度較低、檔案較小)則再加上 _tn
即可:
圖片網址:https://cf.shopee.tw/file/a8b82098b055a69c3b63b73fe1978caf
縮圖網址:https://cf.shopee.tw/file/a8b82098b055a69c3b63b73fe1978caf_tn
* 影片網址則是先從 video_info_list 讀到 video_id,再如下組成網址:
影片網址:https://cv.shopee.tw/video/JmkCD3CvRP50uxb-
* 可以從 adsid
是否有值來判斷這間商品是否為廣告。
商品資訊
在商品頁面取得,相比上方"搜尋商品"得到的資訊來說,這邊會有更多的資訊,例如商品詳情、各規格較詳細資訊等等。
請求路徑
GET https://shopee.tw/api/v2/item/get?itemid={商品ID}&shopid={賣場ID}
範例:https://shopee.tw/api/v2/item/get?itemid=1558498138&shopid=9060351
referer
:https://shopee.tw/{商品名稱}-i.{賣場ID}.{商品ID}
(也就是此商品網址,還有記得將 url 編碼)
[更新 2021/04/04] 或是 https://shopee.tw/product/{賣場ID}/{商品ID}
請求參數
參數很簡單,就只有 itemid
和 shopid
兩項:
itemid
:商品ID。shopid
:賣場ID。
回傳資料
同樣是以 JSON 格式回傳,資料內欄位很多,但大部分欄位都跟上面"搜尋商品"一樣,這邊列出幾個上面沒有但較重要的欄位:
欄位 | 代表意思 |
---|---|
description | 商品詳情 |
estimated_days | 估計出貨天數 |
models | 各規格較詳細資訊 |
評價資訊
評價資訊指的是商品頁面底下,買家對於此商品的評分、評論、照片、影片等資料。
請求路徑
GET https://shopee.tw/api/v2/item/get_ratings?filter=0&flag=1&itemid={商品ID}&limit=6&offset=0&shopid={賣場ID}&type=0
範例:https://shopee.tw/api/v2/item/get_ratings?filter=0&flag=1&itemid=1558498138&limit=6&offset=0&shopid=9060351&type=0
referer
:https://shopee.tw/{商品名稱}-i.{賣場ID}.{商品ID}
(同樣是此商品網址,一樣記得將 url 編碼)
請求參數
來看一下評價資訊的請求網址帶哪些參數:
shopid
:賣場ID。itemid
:商品ID。flag
和type
:篩選條件。
篩選 | filter | type |
---|---|---|
全部留言 | 0 | 0 |
五星留言 | 0 | 5 |
四星留言 | 0 | 4 |
三星留言 | 0 | 3 |
二星留言 | 0 | 2 |
一星留言 | 0 | 1 |
附上評論 | 1 | 0 |
附上照片/影片 | 3 | 0 |
* 經過嘗試,發現兩者貌似無法混用,例如無法篩選"附上評論的三星留言"這樣。
limit
:一次請求最大回傳的結果數量,預設 15 個、最多 59 個,但如果給超過 59 個,反而會回傳 0 個。offset
:偏移值。flag
:未知。
回傳資料
它也是以 JSON 格式回傳,data
底下有 item_rating_summary
與 ratings
兩個欄位。item_rating_summary
是總評價的統計,像是總評分為幾分、有幾個五星評價、有幾個加上照片/影片的評價;ratings
裡面就是各評價的詳細資料。
以下我列出一些各評價中比較重要的欄位,如與上方有重複的就不再寫出來:
欄位 | 代表意思 |
---|---|
rating_star | 評分(星等) |
author_portrait | 作者大頭照 |
cmtid | 評價ID |
author_username | 評分者帳號 |
author_shopid | 評分者賣場ID |
comment | 評論 |
anonymous | 是否匿名 |
ctime | 創建評分時間(時間戳) |
mtime | 修改評分時間(時間戳) |
product_items > model_name | 評分者購買商品的規格 |
ItemRatingReply | 賣家回應 |
* 作者大頭照與之前圖片一樣,網址 https://cf.shopee.tw/file/
再加上圖片ID即可。
* 這邊影片網址不需要再像上面那樣串,它直接給影片網址了。
延伸練習
試著將"搜尋商品"、"商品資訊"、"評分資訊"的抓取資料挑選、整理之後,儲存到檔案(txt、csv、json)中。
以上文章說明抓取"搜尋商品"、"商品資訊"、"評分資訊",請試著自己寫寫看"如何取得指定賣場內商品"?
例如:Logitech羅技官方旗艦館 裡頭所販售的所有商品。
注意事項
後來發現如果短時間太頻繁的送出請求,會被伺服器阻擋,貌似正常獲得資料,但其實仔細看會發現資料有誤,例如價格很明顯不正確等等。
結語
在尋找、爬取"蝦皮購物"的相關資料時會覺得很有趣,因為它是使用 API 的方式去請求資料,也不用自己寫 BeautifulSoup 來解析網頁,一步步尋找個參數代表什麼意思,我想這也是在寫爬蟲程式過程的樂趣吧。
之後會繼續陸續寫一些網站的Python網路爬蟲實例,如果你正好是剛開始想學爬蟲的新手、想知道某網站如何爬取資料,又或遇到其他問題,歡迎參考與在底下留言喔~🔖
逆風的方向,更適合飛翔,我不怕千萬人阻擋,只怕自己投降。
—— 五月天《倔強》
🔻 如果覺得喜歡,歡迎在下方獎勵我 5 個讚~