在這個萬物互聯的時代,手機端(App)、電腦端(Web),連線著你我他。
那麼就讓我們來看看噹噹圖書「活著」的差評吧!
/ 01 / Charles
Charles是一個APP抓包工具,與我之前最先使用的Filddler相似,可以得到手機App執行過程中發生的所有網路請求和響應內容。
這裡簡單說一下安裝。
電腦端下載安裝完Charles後,需要配置證書,最後開啟SSL監聽,這個具體大家自己自行百度。
手機端則是需要與電腦在同一網路下,比如都連線家裡的WIFI,然後在手機的WIFI高階選項裡使用Charles代理,輸入電腦的IP地址,埠8888,最後為證書命名。
連好以後,手機開啟噹噹App,到圖書「活著」的差評頁,不斷向下滑動差評頁面,便能在電腦上的Charles觀察到下面的資訊。
將電腦上的資訊與手機上的資訊匹配一下。
不過呢有的時候會碰見App介面帶有密匙的,我們不好確定出API介面,那麼就輪到mitmproxy上場了。
/ 02 / mitmproxy
mitmproxy也是用來抓包的,是一個控制檯形式,我理解的就是沒有UI介面,在命令列上展示的(windows上不能用,我瞎理解的...)。
mitmproxy有兩個關聯元件,一個是mitmdump,是mitmproxy的命令列介面,可以對接Python指令碼,用Python實現監聽後的處理,也就是用指令碼處理資訊。
另一個是mitmweb,為Web程式服務,本次不涉及。
mitmproxy的安裝同樣需要證書配置,電腦端配一個,手機端也要配一個。
這裡有個坑,我的華為手機直接識別不了pem格式的檔案,無法直接安裝,還得從SD卡那才能安裝,也就是有許可權問題。
手機WIFI代理設定和Charles差不多,只是埠需要改變,這裡是8080,。
然後命令列執行我都是在mitmdump.exe所在的資料夾開啟的,實在是不想去搞那些煩人的環境變數。
這裡就直接講mitmdump的應用,畢竟windows用不了mitmproxy。
通過手動下滑差評頁面,就能自動處理資訊並存儲。
Python指令碼如下,第一次深刻接觸指令碼大佬,以前還只是聽說了遊戲指令碼而已。
import jsondef response(flow): url = 'product.mapi.dangdang.com' page_size = 'page_size=15' # 對url進行篩選,只選取評論的url if url and page_size in flow.request.url: text = flow.response.text data = json.loads(text) for item in data['review_list']: # 獲取使用者暱稱 if len(item['cust_name']) > 0: name = item['cust_name'] else: name = '無名' print(item['cust_name']) # 獲取使用者評分 if len(item['score']) > 0: score = str(item['score']) else: score = '0' print(item['score'] + '\\n') # 獲取使用者評論 content = item['content'].replace(',', ',').replace('\\n', '') print(item['content'] + '\\n') # 獲取使用者評論時間 creation_date = item['creation_date'] print(item['creation_date']) # 獲取有用數 if len(str(item['total_helpful_num'])) > 0 : total_helpful_num = str(item['total_helpful_num']) else: total_helpful_num = '0' print(item['total_helpful_num']) # 獲取無用數 if len(str(item['total_useless_num'])) > 0 : total_useless_num = str(item['total_useless_num']) else: total_useless_num = '0' print(item['total_useless_num']) # 獲取評論數 if len(str(item['total_reply_num'])) > 0 : total_reply_num = str(item['total_reply_num']) else: total_reply_num = '0' print(item['total_reply_num']) print('\\n') # 將獲取資訊寫入csv檔案 with open('alive.csv', 'a+', encoding='utf-8-sig') as f: f.write(name + ',' + score + ',' + content + ',' + creation_date + ',' + total_helpful_num + ',' + total_useless_num + ',' + total_reply_num + '\\n')python
那麼我們現在已經實現了資訊的獲取和儲存,是不是已經完成工作了呢?
並不是,我們還要實現自動化,上面可是手動下滑頁面啊!
感謝程式讓人解放雙手,實現自動化,佩服佩服。
/ 03 / Appium
其實就跟selenium 一樣,只不過一個是電腦端自動化,一個是手機端自動化。
Appium安裝挺複雜的,而且新版本的命令還不一樣。
比如下滑,已經不能使用swip,而是使用TouchAction。
環境變數就是JDK,SDK等,坑太多,小夥伴慢慢體會...
都準備好了之後,將手機和電腦通過資料線連線,開啟USB除錯,允許訪問資料。
用adb命令獲取連線情況,及手機型號資訊。
用SDK包下的aapt命令獲取APK的包名及入口名,這裡不細說,有事找度娘。
這樣便能配置Appium引數了。
{ 左右滑動切換圖片 }
最後就是使用Python程式碼驅動App啦。
import timeimport randomfrom appium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom appium.webdriver.common.touch_action import TouchActionfrom selenium.webdriver.support import expected_conditions as ECdef main(): # 設定驅動配置 server = 'http://localhost:4723/wd/hub' desired_caps = { 'platformName': 'Android', 'deviceName': 'STF_AL00', 'appPackage': 'com.dangdang.buy2', 'appActivity': 'com.dangdang.buy2.StartupActivity' } driver = webdriver.Remote(server, desired_caps) # 這裡獲取一下手機螢幕實際大小,可以為設定滑動引數做參考 size = driver.get_window_size() print(size) wait = WebDriverWait(driver, 60) # 因為要叫我切換地區,選擇取消 button_1 = wait.until(EC.presence_of_element_located((By.ID, 'com.dangdang.buy2:id/left_bt'))) button_1.click() # 點選圖書榜按鈕 button_2 = wait.until(EC.presence_of_element_located((By.ID, 'com.dangdang.buy2:id/index_icon_iv0'))) button_2.click() # 點選圖書「活著」區域塊 button_3 = wait.until(EC.presence_of_element_located((By.XPATH, '/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.support.v4.view.ViewPager/android.widget.RelativeLayout/android.widget.ListView/android.widget.LinearLayout[2]'))) button_3.click() # 點選評論區域塊 button_4 = wait.until(EC.presence_of_element_located((By.ID, 'com.dangdang.buy2:id/product_component_book_score_ll'))) button_4.click() time.sleep(5) # 點選差評按鈕 button_5 = wait.until(EC.presence_of_element_located((By.XPATH, '/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.support.v4.view.ViewPager/android.widget.LinearLayout/android.support.v4.view.ViewPager/android.widget.RelativeLayout/android.widget.LinearLayout/android.view.ViewGroup/android.widget.RelativeLayout[6]/android.widget.TextView'))) button_5.click() # 向下滑動,y軸引數我隨便選的,向上滑就對了 while True: TouchAction(driver).press(x=515, y=1247).move_to(x=515, y=1026).release().perform() time.sleep(float(random.randint(5, 10)))if __name__ == '__main__': main()手機自動操作就在下面這個視訊裡,我錄下來的(小程式識別)。
最後成功儲存資料。
/ 04 / 資料視覺化
詞雲程式碼如下。
from wordcloud import WordCloud, ImageColorGeneratorimport matplotlib.pyplot as pltimport pandas as pdimport jiebadf = pd.read_excel('alive.xlsx', header=None, names=["name", "score", "comment", "date", "up_number", "down_number", "reply_number"])text = ''for line in df['comment']: text += ' '.join(jieba.cut(line, cut_all=False))backgroud_Image = plt.imread('book.jpg')stopwords = set('')stopwords.update(['沒有', '什麼', '不是', '知道', '怎麼', '就是', '本書', '噹噹', '這個 商品', '一個', '自己', '真的', '商品 不太好', '一本', '這樣', '但是', '現在', '你們', '一直', '以後', '這個', '商品'])wc = WordCloud( background_color='white', mask=backgroud_Image, font_path='C:\\Windows\\Fonts\\STZHONGS.TTF', max_words=2000, max_font_size=150, random_state=30, stopwords=stopwords)wc.generate_from_text(text)# 看看詞頻高的有哪些,把無用資訊去除process_word = WordCloud.process_text(wc, text)sort = sorted(process_word.items(), key=lambda e:e[1], reverse=True)print(sort[:50])img_colors = ImageColorGenerator(backgroud_Image)wc.recolor(color_func=img_colors)plt.imshow(wc)plt.axis('off')wc.to_file("活著.jpg")print('生成詞雲成功!')最後生成差評詞雲,來看看大家怎麼吐槽的。