薅羊毛 | Python 自動化帶你輕鬆賺錢(完結版)

  • 2019 年 11 月 1 日
  • 筆記

1

目 標 場 景

最近,有一個朋友告訴我,她在某平台上購買了一部手機,收到貨之後發現商品品質挺好的,價格也不貴。

臨了隨手給了個好評,商家最後還給她發一個 小紅包,她把這個商品分享給了我。

本篇文章的目的是利用 Python 自動化完成商品購買的操作。

ps:本文僅限用於技術交流,請勿用於其他用途。

2

准 備 工 作

在編寫程式碼之前,需要做如下準備工作:

1、配置好 Android ADB 開發環境

2、Python 虛擬環境內安裝 pocoui 依賴庫

3、操作剪切板的應用 APK,下載鏈接見文末

3

編 寫 代 碼

我們分 7 個步驟來實現這個功能,分別是:打開目標應用客戶端、搜索關鍵字到商品列表介面、裁剪原圖拿到商品主圖、商品匹配、商品收藏和瀏覽、購買商品、獲取訂單號和截圖。

1 步,使用 Airtest 自動化打開目標應用。

# 目標應用  package_name = '應用包名'  activity = 'Home Activity'    def __pre(self):      """      準備工作      :return:      """      # 刪除快取文件      remove_cache('./part.jpg', './screenshot.png', './uidump.xml')        home()      stop_app(package_name)      start_my_app(package_name, activity)

打開應用之後,就可以進行第 2 步操作了。

通過預先得到的關鍵字,置入到輸入框中,然後點擊搜索按鈕,一直等待搜過列表出現為止。

需要注意的是,有些控制項元素需要點擊多次才能算一次有效的點擊事件。

def __search_good_by_key(self):      """      通過關鍵字搜索商品      :return:      """      self.poco(id_page_main_button_search).wait(5).click()        perform_view_input(self.poco, id_page_search_edittext_search, self.key)        # 點擊搜索      self.poco(id_page_search_button_search).wait_for_appearance()      while self.poco(id_page_search_button_search).exists():           print('點擊一次搜索')           perform_view_id_click(self.poco, id_page_search_button_search)        # 等待列表載入出來      self.poco(id_page_goods_rv).wait_for_appearance()

3 步,剪切原圖,需要對原圖中多餘的白色區域進行刪除,只保留左側的商品主圖。

通過 遍歷 x 軸、y 軸,拿到每一個像素的顏色值,如果是連續的白色就做一個標識,進而拿到主圖的上、下、左、右坐標值,最後利用 cv2 庫進行裁剪,得到商品主圖

def crop_main_img(img_path):      """      獲取商品主圖      :return:      """      img = cv2.imread(img_path)      # 圖片大小(高、寬、the pixels value is made up of three primary colors)      size = img.shape        img_height = size[0]      img_width = size[1]      channels = size[2]        # 1080*458      print(f'圖片寬度:{img_width},高度:{img_height}'        # 標識數組,針對x軸和y軸      arr_x = []      arr_y = []        # 遍歷寬,得到主圖的x軸坐標      for x in range(img_width):          is_black = True            # 遍歷高          for y in range(img_height):              # 獲取顏色值              color_position = img[y, x]              if (color_position == color_white).all():                  pass              else:                  is_black = False            arr_x.append(is_black)        # 遍歷高,得到主圖的y軸坐標      for y in range(img_height):          is_black = True            # 遍歷高          for x in range(img_width):              # 獲取顏色值              color_position = img[y, x]              if (color_position == color_white).all():                  pass              else:                  is_black = False            arr_y.append(is_black)        position_x = get_space_index(arr_x)      position_y = get_space_index(arr_y)        main_img_path = "./head_img.jpeg"        # 剪切      # 裁剪坐標為[y0:y1, x0:x1]      cropped = img[position_y[0]:position_y[1], position_x[0]: position_x[1]]      cv2.imwrite(main_img_path, cropped)        return main_img_path

4 步,商品匹配。

拿到商品主圖之後,利用 Airtest 在當前頁面進行元素查找,如果沒有找到,就滑到下一個元素;否則,就拿到匹配商品的坐標。

def __search_good_from_list(self):      """      從列表中匹配商品      :return:      """      # 循環的圖片查找      while True:              try:                  pos = loop_find(Template(self.main_img_path), timeout=10, threshold=0.95)              except TargetNotFoundError:                  print('滑動一頁')                  self.__swipe(True)              else:                  print('找到了')                    # 螢幕寬度和高度                  screen_size = self.poco.get_screen_size()                  print(screen_size)                    # 點擊的坐標點(寬、高)                  # (0.22407407407407406, 0.8550925925925926)                  position_click = (pos[0] / screen_size[0], pos[1] / screen_size[1])                  print(position_click)                  self.poco.click(position_click)                  break

5 步,商品收藏和瀏覽。

跳轉到商品資訊介面之後,先收藏商品,然後跳轉到商品詳情頁面和評論頁面。

在預先設置的瀏覽時間內,執行休眠、滑動操作。

def __browser_good_detail(self):      """      瀏覽商品      :return:      """      # 切換到詳情Tab      self.poco('com.**:id/taodetail_nav_bar_tab_text', text='詳情').click()        # 滑動時長為: self.browser_detail_time      browser_start = datetime.datetime.now()      browser_end = browser_start        while (browser_end - browser_start).seconds < self.browser_detail_time:           # 休眠一會           time.sleep(random.randint(2, 5))             # 滑動一次           self.__swipe(True)             # 結束時間           browser_end = datetime.datetime.now()        print('詳情頁面查看完畢')

6 步,購買商品。

商品的購買操作很簡單,只要點擊一個購買按鈕即可完成;基於安全考慮,這裡選擇收貨地址、輸入支付密碼手動輸入。

def __buy_good(self):      """      購買商品      :return:      """      # 立即購買      self.poco('**/detail_main_sys_button', text='立即購買').click()        # 選擇商品屬性      sleep(10)        # 確定購買      self.poco('**/confirm_text', text='確定').parent().click()        # 提交訂單      self.poco(text='提交訂單').click()        # 手動輸入密碼或者指紋      sleep(10)

7 步,獲取訂單 ID 及商品截圖。

通過 Monitor 觀察發現,訂單號文本元素很難通過屬性或者子、父關係拿到。

可以通過點擊複製按鈕,將訂單號粘貼到系統的剪切板,然後利用 adb + clipper 這款 App拿到剪切板中的內容。

def __get_order_no(self):      """      獲取訂單編號      :return:      """      global copy_element      while True:           # 由於手機螢幕的限制,【複製】按鈕第一頁不一定能顯示出來           try:               copy_element = self.poco(text='複製')           except Exception as e:               print('沒有找到元素,往下滑動一頁')               self.__swipe(True)             break        # 複製到剪切版本      copy_element.click()        # 從剪切板拿到數據      result = exec_cmd('adb shell am broadcast -a clipper.get')[1]        # 匹配出訂單號      result = re.findall(r'data="(.*)"', result)        order_no = ''        if result and len(result) > 0:           order_no = result[0]        print(order_no)        return order_no

接著利用 adb 命令截取當前螢幕,然後保存到 PC 端,即完成了全部操作。

def get_order_pic(self):       """       拿到訂單截圖介面       :return:       """       screenshot_pic_result = './order_screenshot.png'         # 截取手機當前螢幕       exec_cmd('adb shell /system/bin/screencap -p /sdcard/screenshot.png')         # 保存到PC端       exec_cmd('adb pull /sdcard/screenshot.png %s' % screenshot_pic_result)         return screenshot_pic_result

4

結 果 結 論

通過以上的步驟,即可以完成自動化挑選商品、瀏覽、購買等一系列操作。

需要補充的是,由於手機解析度的不一致,導致商品主圖匹配會存在一定的誤差;但由於主圖寬、高比是一致的,可以通過縮放圖片達到 適配 的目的。