爬取網易buff CSGO飾品數據 - 優化篇


繼上週末搞了csgo飾品的爬蟲之後,最近一週一直在根據社區小夥伴的意見建議進行優化。不得不說,玩家纔是最好的產品經理,很多提出來的建議都讓人爲之一振,這也直接優化了最終的程序效率、實現方式等,同時也增加了一些新的功能。在這裏就以優化篇記錄一下本週進行的優化流程吧。

思路回顧

爬取網易buff CSGO飾品數據

配置優化

先說個功能性不那麼強,但直接關乎程序上手熱度的更新吧。

配置這問題確實之前沒太關注過,自己給自己寫程序,更關注的是功能。和後端程序猿做出來的前端一樣:能用就行,要啥自行車。不過一旦想推廣自己的程序,尤其是在遊戲社區中推廣,一個良好的UI是極其重要的。在這裏,就是自定義配置的方式。

之前寫Python一貫的配置方式是直接在一個統一的變量文件中修改變量,比如definitions.py,雖然是專門定義配置的地方,但是免不了定義的變量和一些簡單的處理變量的邏輯交織在一起,對一些剛接觸工程的人其實是不甚友好的。所以上週發佈不久就優先更新了配置的方式。

這裏配置使用的是python的configparser,依舊在definitions.py裏處理變量,但是配置源設定在config/config.ini中,可以讓用戶專心只做自己心儀的配置,不需要思考太多東西,對於發佈出去的程序來說,的確是一個非常重要的更新。

RawConfigParser

有小夥伴使用發現configparser.ConfigParser()會轉義一些特殊字符,比如百分號,這個在我自己使用的時候確實沒有發現。查了一下,使用configparser.RawConfigParser()就不會對字符進行轉義了。

處理配置列表

有一些參數需要配置爲列表,但是是以string的形式讀進來的。之前面對[a, b, c, ..., n]這種列表形式的string我都是掐頭去尾再將元素一個一個split出來,後來看別人的建議,json.loads('[a, b, c, ..., n]')直接就解析爲list了,確實方便。python對json的支持的確挺好的,寫着寫着就發現,python確實是一門有趣的語言。

價格取捨

之前取steam售價的時候,使用的是去掉一個最高價一個最低價。但是考慮程序的初衷:使用底價從buff收飾品,丟到steam市場賣掉。經社區老哥提醒,像多普勒這種飾品,溢價的很多,很有可能均價是被拉的偏高的。顯然如果buff底價收的多普勒,不可能在steam有這麼高的價格。(唉,不碰那些玄學飾品,果然就考慮不到這些)

所以後續更新該用歷史售價的.25作爲steam售價,這種情況應該會緩解很多。同時,這麼做也相當於壓低了收益期望值,真實獲益也許會比算出來更高一些。

價格過濾

這是一個比較重要的更新,對爬取時間產生了重大影響。

一開始做價格篩選的時候,思維比較直:爬取所有物品,篩選出在用戶自定義價格區間內的物品,然後分析。

後來經過社區老哥提醒,可以直接使用buff的價格篩選功能!buff是有數據庫的,他們篩選起來肯定賊快,我們使用buff帶加個篩選的api請求物品,這樣只需要爬取這些物品就行了,不用每次都先把所有飾品爬取一遍,大大提升了程序效率。把buff當做工具人,成了!

用了和之前同樣的分析方法,發現加個篩選其實就是在之前請求物品的api上增加三個參數:

  • sort_by:取值如price.desc;
  • min_price
  • max_price

不用多說,含義自明。這樣請求所有100到200的飾品,只需要:https://buff.163.com/api/market/goods?game=csgo&page_num=99999999&sort_by=price.desc&min_price=100&max_price=200就行了。

不過這裏還是有個奇葩的地方,注意到上面url裏的99999999了嗎?不得不說buff的區間篩選API很是清奇,限定價格之後,返回的page_numpage_size竟然都是錯的。也就是說返回的數據並不能告訴我們在這個價格區間內一共有多少頁共計多少飾品。然鵝機智的我發現,如果將page number設定爲超出實際頁數的值,這兩個數據就會變成正確值。

比如,98~99.9的飾品共計3頁42件,但是返回值告訴我們一共有720頁14388件,而這實際是buff現售物品總數,並不是價格篩選後的件數。
想獲取準確值3頁42件,只需給page number設定爲超出3的值即可,所以我用了sys.maxsize,一個巨大無比的值。

飾品類別限定

飾品類別限定也是一項比較大的更新,主要是引入了這項功能之後,系統實現又被調整了。

增設類別限定,可以配置自己只想爬取的類別(白名單)或者不想爬取(黑名單)的類別。

白名單優先級高於黑名單優先級。

所以規則如下:

  • 如果黑白名單均未設置,默認爬取所有類別,所有類別參考config/reference/category.md
  • 如果設置了白名單,僅爬取白名單類型飾品;
  • 如果只設置了黑名單,則爬取除了黑名單之外的所有物品;

比如:

category_white_list = ["weapon_ak47", "weapon_m4a1", "weapon_m4a1_silencer"]
category_black_list = ["weapon_m4a1"]

則最終會爬取AK、M4A1、M4A4三種物品。

NOTE: M4A1遊戲代號爲"weapon_m4a1_silencer"、M4A4遊戲代號爲"weapon_m4a1"。
不要問爲什麼,我猜是V社員工一開始起名的時候沒想好,後來由於兼容性等原因不好改了。那咋辦嘛,就這麼用着唄。

類別名稱一定不能寫錯了(建議複製粘貼),否則buff直接返回所有類別的物品……什麼鬼設定……

內部實現優化:結合價格篩選和飾品類別篩選

這樣設置類別和不設類別就有了兩套實現:

  • 如果未設定爬取類別,則不分類別直接爬取價格區間內的所有物品;
  • 如果設定了爬取類別,依次爬取有效類別內所有符合價格區間的物品;

價格區間篩選的時候是不分類別直接爬取的,但是設定類別之後又要按照類別爬取,二者能不能結合成一套實現呢?即設定價格區間時,也按照類別請求各個類別在價格區間內的飾品。

繼續去buff上同時加上價格和類別篩選,發現發送的api接口裏多了一個參數:

  • category

只要把飾品類別填入category就行了。

感覺再試下去,我要把buff所有對外接口的參數都試完了……

那麼現在想要篩選100-200之間的ak,只需要請求https://buff.163.com/api/market/goods?game=csgo&page_num=99999999&sort_by=price.desc&min_price=100&max_price=200&category=weapon_ak47就行了。

通過這個接口,我也得以將兩種實現合二爲一。有價格篩選的時候就帶上價格的參數,有類別篩選的時候就帶上類別的參數,一種實現就搞定了。

其他限定?

有老哥問能不能加磨損之類的篩選?加當然可以加,也不難,不過這個程序的本意是從buff底價買飾品賣到steam換餘額,也不是買來玩的,磨損這種東西不用很在意。

所以感覺做程序還是不要背離初衷,不然功能加來加去,成了一個龐大的集合體(再加就加成一個buff了……),功能越來越多,代碼越來越不好維護,80%的功能卻基本用不到,那和互聯網公司80%的產品經理做出來的破玩意兒有什麼區別!

命名

程序經過一個星期的優化,完成了我一開始設想的功能,甚至很多地方超出了我的期待(當然離不開社區小夥伴的意見建議,非常感謝)。那麼給它起什麼名字呢?之前臨時命名的buff_csgo_skin_crawler實在太醜了,絲毫沒有靈魂。一個用心做的程序,值得用心取一個好名字。

翻開神奇寶貝圖鑑,童年的一幕幕再次浮上心頭,終於走路草映入了我的眼簾:During the daytime, Oddish buries itself in soil to absorb nutrients from the ground using its entire body.

有兩個寓意很貼切:

  1. 白天沉睡,夜晚潛行,符合爬蟲行爲舉止如履薄冰;
  2. 走路草,在網頁上走來走去,收集所有信息;

那就將其命名爲oddish吧。

oddish

走路草,白天沉睡,夜晚潛行,我來過,並將信息鐫刻在深深的記憶裏。

Hello, I’m oddish.

The End

原來寫代碼真的可以有趣到一下班回家不顧疲憊就迫不及待開始完成前一天留下的TODO,可以爲了在睡覺前(半夜十二點甚至更晚,所以是不是可以稱之爲“新的一天”)發佈新的更新而不玩遊戲。雖然這還不是什麼大的工程,不是什麼真正有意義的開源項目,但是這的確是我的興趣所在,真的開心。

如果沒有其他什麼特別的需求,該工程大概可以archive了。歡迎感興趣的小夥伴github圍觀,star,fork,提出意見和建議,有趣的需求我會繼續更新。

本文從我的個人網站搬運過來,畢竟現在Google搜索好像並不能搜到我的文章,還是在csdn再放一份吧。以後我的blog基本都發在個人網站上了,thank you CSDN~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章