閑魚(yú)上哪些商品搶手?Python分析后告訴你
1.目標(biāo)場(chǎng)景
經(jīng)常看到有朋友在閑魚(yú)賣些小東西又或是自己擅長(zhǎng)的一些技能,都能為他們帶來(lái)不錯(cuò)的睡后收入。
閑魚(yú)上大量的商品,很難精準(zhǔn)判斷哪些受歡迎,哪些好賣;一個(gè)個(gè)錄入數(shù)據(jù)去做數(shù)據(jù)分析,浪費(fèi)時(shí)間的同時(shí),效率也極其的低效。
本篇文章的目的是利用 Python 自動(dòng)化 來(lái)獲取某類商品中很好賣的商品以供參考。
ps:本文僅限用于技術(shù)交流,請(qǐng)勿用于其他用途。
2.準(zhǔn)備工作
在編寫(xiě)代碼之前,需要做如下準(zhǔn)備工作:
(1)配置好 Android ADB 開(kāi)發(fā)環(huán)境
(2)Python 虛擬環(huán)境內(nèi)安裝 pocoui 依賴庫(kù)
(3)安裝數(shù)據(jù)可視化依賴庫(kù) pyecharts
- # pocoui
- pip3 install pocoui
- # 數(shù)據(jù)可視化圖表
- pip3 install pyecharts -U
3.編寫(xiě)代碼
我們分 7 個(gè)步驟來(lái)實(shí)現(xiàn)這個(gè)功能,分別是:打開(kāi)目標(biāo)應(yīng)用客戶端、檢索關(guān)鍵字到商品列表界面、計(jì)算優(yōu)秀滑動(dòng)距離、篩選商品、獲取商品鏈接地址、寫(xiě)入文件排序并統(tǒng)計(jì)商品、配置參數(shù)。
第 1 步,使用 pocoui 自動(dòng)化打開(kāi)目標(biāo)應(yīng)用。
- def __pre(self):
- """
- 準(zhǔn)備工作
- :return:
- """
- home()
- stop_app(package_name)
- start_my_app(package_name, activity)
- # 等待到達(dá)桌面
- self.poco(text='閑魚(yú)').wait_for_appearance()
- self.poco(text='魚(yú)塘').wait_for_appearance()
- self.poco(text='消息').wait_for_appearance()
- self.poco(text='我的').wait_for_appearance()
- print('進(jìn)入閑魚(yú)主界面')
進(jìn)入到閑魚(yú)首頁(yè)之后,應(yīng)用端會(huì)拿到剪切板的數(shù)據(jù),當(dāng)存在特定規(guī)律的口令的時(shí),會(huì)立馬彈出一個(gè)對(duì)話框,因此需要模擬關(guān)閉對(duì)話框的操作。
- # 如果指定時(shí)間內(nèi)內(nèi)有淘口令,就關(guān)閉
- for i in range(10, -1, -1):
- close_element = self.poco('com.taobao.idlefish:id/ivClose')
- if close_element.exists():
- close_element.click()
- break
- time.sleep(1)
打開(kāi)應(yīng)用之后,就可以進(jìn)行第 2 步操作了。
通過(guò)要檢索的關(guān)鍵字,模擬輸入到輸入框內(nèi),然后點(diǎn)擊搜索按鈕,一直等待搜過(guò)列表出現(xiàn)為止。
另外,為了更加方便地處理數(shù)據(jù),商品列表切換到列表模式,即一行只顯示一個(gè)商品。
- def __input_key_word(self):
- """
- 輸入關(guān)鍵字
- :return:
- """
- # 進(jìn)入搜索界面
- perform_click(self.poco('com.taobao.idlefish:id/bar_tx'))
- # 搜索框內(nèi)輸入文本
- self.poco('com.taobao.idlefish:id/search_term').set_text(self.good_msg)
- # 點(diǎn)擊搜索按鈕
- while True:
- # 等待檢索結(jié)果列表出現(xiàn)
- if not self.poco('com.taobao.idlefish:id/list_recyclerview').exists():
- perform_click(self.poco('com.taobao.idlefish:id/search_button', text='搜索'))
- else:
- break
- # 等待商品列表完全出現(xiàn)
- self.poco('com.taobao.idlefish:id/list_recyclerview').wait_for_appearance()
- # 切換到列表
- perform_click(self.poco('com.taobao.idlefish:id/switch_search'))
第 3 步,計(jì)算優(yōu)秀滑動(dòng)距離。
為了保證爬取數(shù)據(jù)的高效性,獲取計(jì)算出每次滑動(dòng)的優(yōu)秀距離。
首先先拿到當(dāng)前界面的 UI 控件樹(shù),然后通過(guò)控件的屬性 ID 拿到商品的坐標(biāo),進(jìn)而得到每一項(xiàng)商品的高度。
最后,通過(guò)觀察屏幕中出現(xiàn)商品的數(shù)目得到優(yōu)秀滑動(dòng)距離。
- def __get_good_swipe_distance(self):
- """
- 獲取每次滑動(dòng),最合適的距離
- :return:
- """
- element = Element()
- # 保存當(dāng)前的UI樹(shù)到本地
- element.get_current_ui_tree()
- # 第一個(gè)商品Item的坐標(biāo)
- position_item = element.find_elment_position_by_id_and_index("com.taobao.idlefish:id/card_root",
- "1")
- # 商品的高度
- item_height = position_item[1][1] - position_item[0][1]
- # 通過(guò)觀察,當(dāng)前屏幕有3件商品
- return item_height * 3
第 4 步,篩選商品。
上面的步驟拿到優(yōu)秀的滑動(dòng)距離,不停的滑動(dòng)頁(yè)面遍歷列表元素的子 Item。
需要注意的是,為了避免滑動(dòng)慣性導(dǎo)致的誤差,每一次的滑動(dòng)時(shí)長(zhǎng)最好設(shè)置為 2s 以上。
通過(guò)商品 Item 篩選出想要數(shù)目大于預(yù)設(shè)數(shù)字的商品。
- # 多少人想要
- want_element_parent = item.offspring('com.taobao.idlefish:id/search_item_flowlayout')
- if want_element_parent.exists():
- # 想要數(shù)/已付款數(shù)目
- want_element = want_element_parent.children()[0]
- want_content = want_element.get_text()
- # 過(guò)濾掉【已付款】等其他商品,只保留個(gè)人發(fā)布商品
- if '人想要' not in want_content:
- continue
- # 拿到商品想要的具體數(shù)目,代表商品熱度
- want_num = get_num(want_content)
- if int(want_num) < self.num_assign:
- # print('不達(dá)標(biāo),過(guò)濾掉')
- pass
- else:
- # 商品想要數(shù)達(dá)標(biāo),加入統(tǒng)計(jì)
第 5 步,獲取商品鏈接地址。
對(duì)于上一步滿足條件的商品,點(diǎn)擊商品 Item 進(jìn)入到商品詳情頁(yè)面。
接著點(diǎn)擊右上角的分享按鈕,會(huì)立即彈出分享對(duì)話框。
然后點(diǎn)擊口令控件,會(huì)提示口令復(fù)制到系統(tǒng)剪切板成功。
- # 點(diǎn)擊更多
- while True:
- if self.poco('com.taobao.idlefish:id/ftShareName').exists():
- break
- print('點(diǎn)擊更多~')
- perform_click(self.poco(text='更多'))
- # 點(diǎn)擊復(fù)制淘口令
- perform_click(self.poco('com.taobao.idlefish:id/ftShareName', text='淘口令'))
- # 拿到口令碼
- taobao_code_element = self.poco('com.taobao.idlefish:id/tvWarnDetail')
- taobao_code = taobao_code_element.get_text()
第 6 步,寫(xiě)入商品、排序并統(tǒng)計(jì)數(shù)據(jù)。
將上面獲取到的商品標(biāo)題、想要數(shù)、分享地址寫(xiě)入到 CSV 文件中。
然后讀取數(shù)據(jù)文件,通過(guò)對(duì)表格中的第二列進(jìn)行反向排序,使商品按照想要數(shù)進(jìn)行降序排列。
- def __sort_result(self):
- """
- 對(duì)爬取的結(jié)果進(jìn)行排序
- :return:
- """
- reader = csv.reader(open(self.file_path), delimiter=",")
- # 頭部標(biāo)題
- head_title = next(reader)
- # 按照第二列進(jìn)行逆序排列
- sortedlist = sorted(reader, key=lambda x: (int(x[1])), reverse=True)
- # 寫(xiě)入頭部數(shù)據(jù)
- write_to_csv(self.file_path, [(head_title[0], head_title[1], head_title[2])], False)
- for value in sortedlist:
- write_to_csv(self.file_path, [(value[0], value[1], value[2])], False)
- return sortedlist
最后拿到前 10 項(xiàng)數(shù)據(jù),利用 pyecharts 生成統(tǒng)計(jì)圖表。
- def draw_image(self, sortedlist):
- """
- 畫(huà)圖
- :param sortedlist:
- :return:
- """
- # 標(biāo)題列表
- titles = []
- # 銷量
- sales_num = []
- # 拿到爬取結(jié)果的標(biāo)題、銷量?jī)蓚€(gè)列表
- with open(self.file_path, 'r') as csvfile:
- # 讀取文件
- reader = csv.DictReader(csvfile)
- # 加入列表中
- for row in reader:
- titles.append(row['title'])
- sales_num.append(row['num'])
- # 數(shù)目限制
- if len(titles) > self.num:
- titles = titles[:self.num]
- sales_num = sales_num[:self.num]
- # 畫(huà)圖
- bar = (
- Bar()
- .add_xaxis(titles)
- .add_yaxis("哪些好賣", sales_num)
- .set_global_opts(title_opts=opts.TitleOpts(title="我要賣貨"))
- )
- bar.render('%s.html' % self.good_msg)
第 7 步,配置參數(shù)。
編寫(xiě) yaml 文件,指定要爬取商品的關(guān)鍵字、爬取時(shí)間、想要數(shù)考核指標(biāo)數(shù)、篩選商品數(shù)目。
- goods:
- # 搜索商品1,包含搜索關(guān)鍵字、爬取時(shí)間
- good1:
- key_word: '資料' # 搜索關(guān)鍵字
- key_num: 100 # 篩選【想要數(shù)】的臨界點(diǎn)
- num: 10 # 只篩選爆款
- time: 600 # 爬取時(shí)間(秒)
4.結(jié)果結(jié)論
提前配置好商品關(guān)鍵字、爬取時(shí)間等參數(shù),即可以爬取到符合要求的、最好賣的商品數(shù)據(jù),最終以圖表的方式展示出來(lái)。