分析了6000款A(yù)pp,竟有這么多佳軟神器沒用過
摘要: 如今移動互聯(lián)網(wǎng)越來越發(fā)達,各式各樣的 App 層出不窮,也就產(chǎn)生了優(yōu)劣之分,相比于普通 App,我們肯定愿意去使用那些良心佳軟,但去發(fā)現(xiàn)這些 App 并不太容易,本文使用 Scrapy 框架爬取了著名應(yīng)用下載市場「酷安網(wǎng)」上的 6000 余款 App,通過分析,發(fā)現(xiàn)了各個類別領(lǐng)域下的佼佼者,這些 App 堪稱真正的良心之作,使用它們將會給你帶來全新的手機使用體驗。
1. 分析背景
1.1. 為什么選擇酷安
如果說 GitHub 是程序員的天堂,那么 酷安 則是手機 App 愛好者們(別稱「搞機」愛好者)的天堂,相比于那些傳統(tǒng)的手機應(yīng)用下載市場,酷安有三點特別之處:
- 第一、可以搜索下載到各種 神器、佳軟,其他應(yīng)用下載市場幾乎很難找得到。比如之前的文章中說過的終端桌面「Aris」、安卓最強閱讀器「靜讀天下」、RSS 閱讀器 「Feedme」 等。
- 第二、可以找到很多 App 的 破解版。我們提倡「為好東西付費」,但是有些 App 很蛋疼,比如「百度網(wǎng)盤」,在這里面就可以找到很多 App 的破解版。
- 第三、可以找到 App 的 歷史版本。很多人喜歡用最新版本的 App,一有更新就馬上升級,但是現(xiàn)在很多 App 越來越功利、越更新越臃腫、廣告滿天飛,倒不如 回歸本源,使用體積小巧、功能精簡、無廣告的早期版本。
作為一名 App 愛好者,我在酷安上發(fā)現(xiàn)了很多不錯的 App,越用越感覺自己知道的僅僅是冰山一角,便想扒一扒這個網(wǎng)站上到底有多少好東西,手動一個個去找肯定是不現(xiàn)實了,自然想到最好的方法——用爬蟲來解決,為了實現(xiàn)此目的,最近就學(xué)習(xí)了一下 Scrapy 爬蟲框架,爬取了該網(wǎng) 6000 款左右的 App,通過分析,找到了不同領(lǐng)域下的精品 App,下面我們就來一探究竟。
1.2. 分析內(nèi)容
總體分析 6000 款 App 的評分、下載量、體積等指標。
根據(jù)日常使用功能場景,將 App 劃分為:系統(tǒng)工具、資訊閱讀、社交娛樂等 10 大類別,篩選出每個類別下的精品 App。
1.3. 分析工具
- Python
- Scrapy
- MongoDB
- Pyecharts
- Matplotlib
2. 數(shù)據(jù)抓取
由于酷安手機端 App 設(shè)置了反扒措施,使用 Charles 嘗試后發(fā)現(xiàn)無法抓包, 暫退而求其次,使用 Scrapy 抓取網(wǎng)頁端的 App 信息。抓取時期截止到 2018 年 11 月 23日,共計 6086 款 App,共抓取 了 8 個字段信息:App 名稱、下載量、評分、評分人數(shù)、評論數(shù)、關(guān)注人數(shù)、體積、App 分類標簽。
2.1. 目標網(wǎng)站分析
這是我們要抓取的 目標網(wǎng)頁,點擊翻頁可以發(fā)現(xiàn)兩點有用的信息:
- 每頁顯示了 10 條 App 信息,一共有610頁,也就是 6100 個左右的 App 。
- 網(wǎng)頁請求是 GET 形式,URL 只有一個頁數(shù)遞增參數(shù),構(gòu)造翻頁非常簡單。
接下來,我們來看看選擇抓取哪些信息,可以看到,主頁面內(nèi)顯示了 App 名稱、下載量、評分等信息,我們再點擊 App 圖標進入詳情頁,可以看到提供了更齊全的信息,包括:分類標簽、評分人數(shù)、關(guān)注人數(shù)等。由于,我們后續(xù)需要對 App 進行分類篩選,故分類標簽很有用,所以這里我們選擇進入每個 App 主頁抓取所需信息指標。
通過上述分析,我們就可以確定抓取流程了,首先遍歷主頁面 ,抓取 10 個 App 的詳情頁 URL,然后詳情頁再抓取每個 App 的指標,如此遍歷下來,我們需要抓取 6000 個左右網(wǎng)頁內(nèi)容,抓取工作量不算小,所以,我們接下來嘗試使用 Scrapy 框架進行抓取。
2.2. Scrapy 框架介紹
介紹 Scrapy 框架之前,我們先回憶一下 Pyspider 框架,我們之前使用它爬取了 虎嗅網(wǎng) 5 萬篇文章 ,它是由國內(nèi)大神編寫的一個爬蟲利器, Github Star 超過 10K,但是它的整體功能還是相對單薄一些,還有比它更強大的框架么?有的,就是這里要說的 Scrapy 框架,Github Star 超過 30K,是 Python 爬蟲界使用最廣泛的爬蟲框架,玩爬蟲這個框架必須得會。
網(wǎng)上關(guān)于 Scrapy 的官方文檔和教程很多,這里羅列幾個。
- Scrapy 中文文檔
- 崔慶才的 Scrapy 專欄
- Scrapy 爬拉勾
- Scrapy 爬豆瓣電影
Scrapy 框架相對于 Pyspider 相對要復(fù)雜一些,有不同的處理模塊,項目文件也由好幾個程序組成,不同的爬蟲模塊需要放在不同的程序中去,所以剛開始入門會覺得程序七零八散,容易把人搞暈,建議采取以下思路快速入門 Scrapy:
- 首先,快速過一下上面的參考教程,了解 Scrapy 的爬蟲邏輯和各程序的用途與配合。
- 接著,看上面兩個實操案例,熟悉在 Scrapy 中怎么寫爬蟲。
- 最后,找個自己感興趣的網(wǎng)站作為爬蟲項目,遇到不懂的就看教程或者 Google。
這樣的學(xué)習(xí)路徑是比較快速而有效的,比一直摳教程不動手要好很多。下面,我們就以酷安網(wǎng)為例,用 Scrapy 來爬取一下。
2.3. 抓取數(shù)據(jù)
首先要安裝好 Scrapy 框架,如果是 Windwos 系統(tǒng),且已經(jīng)安裝了 Anaconda,那么安裝 Scrapy 框架就非常簡單,只需打開 Anaconda Prompt 命令窗口,輸入下面一句命令即可,會自動幫我們安裝好 Scrapy 所有需要安裝和依賴的庫。
- conda pip scrapy
2.3.1. 創(chuàng)建項目
接著,我們需要創(chuàng)建一個爬蟲項目,所以我們先從根目錄切換到需要放置項目的工作路徑,比如我這里設(shè)置的存放路徑為:E:\my_Python\training\kuan,接著繼續(xù)輸入下面一行代碼即可創(chuàng)建 kuan 爬蟲項目:
- # 切換工作路徑
- e:
- cd E:\my_Python\training\kuan
- # 生成項目
- scrapy startproject kuspider
執(zhí)行上面的命令后,就會生成一個名為 kuan 的 scrapy 爬蟲項目,包含以下幾個文件:
- scrapy. cfg # Scrapy 部署時的配置文件
- kuan # 項目的模塊,需要從這里引入
- _init__.py
- items.py # 定義爬取的數(shù)據(jù)結(jié)構(gòu)
- middlewares.py # Middlewares 中間件
- pipelines.py # 數(shù)據(jù)管道文件,可用于后續(xù)存儲
- settings.py # 配置文件
- spiders # 爬取主程序文件夾
- _init_.py
下面,我們需要再 spiders 文件夾中創(chuàng)建一個爬取主程序:kuan.py,接著運行下面兩行命令即可:
- cd kuan # 進入剛才生成的 kuan 項目文件夾
- scrapy genspider kuan www.coolapk.com # 生成爬蟲主程序文件 kuan.py
2.3.2. 聲明 item
項目文件創(chuàng)建好以后,我們就可以開始寫爬蟲程序了。
首先,需要在 items.py 文件中,預(yù)先定義好要爬取的字段信息名稱,如下所示:
- class KuanItem(scrapy.Item):
- # define the fields for your item here like:
- name = scrapy.Field()
- volume = scrapy.Field()
- download = scrapy.Field()
- follow = scrapy.Field()
- comment = scrapy.Field()
- tags = scrapy.Field()
- score = scrapy.Field()
- num_score = scrapy.Field()
這里的字段信息就是我們前面在網(wǎng)頁中定位的 8 個字段信息,包括:name 表示 App 名稱、volume 表示體積、download 表示下載數(shù)量。在這里定義好之后,我們在后續(xù)的爬取主程序中會利用到這些字段信息。
2.3.3. 爬取主程序
創(chuàng)建好 kuan 項目后,Scrapy 框架會自動生成爬取的部分代碼,我們接下來就需要在 parse 方法中增加網(wǎng)頁抓取的字段解析內(nèi)容。
- class KuanspiderSpider(scrapy.Spider):
- name = 'kuan'
- allowed_domains = ['www.coolapk.com']
- start_urls = ['http://www.coolapk.com/']
- def parse(self, response):
- pass
打開主頁 Dev Tools,找到每項抓取指標的節(jié)點位置,然后可以采用 CSS、Xpath、正則等方法進行提取解析,這些方法 Scrapy 都支持,可隨意選擇,這里我們選用 CSS 語法來定位節(jié)點,不過需要注意的是,Scrapy 的 CSS 語法和之前我們利用 pyquery 使用的 CSS 語法稍有不同,舉幾個例子,對比說明一下。
首先,我們定位到第一個 APP 的主頁 URL 節(jié)點,可以看到 URL 節(jié)點位于 class 屬性為 app_left_list 的 div 節(jié)點下的 a 節(jié)點中,其 href 屬性就是我們需要的 URL 信息,這里是相對地址,拼接后就是完整的 URL。
接著我們進入酷安詳情頁,選擇 App 名稱并進行定位,可以看到 App 名稱節(jié)點位于 class 屬性為 .detail_app_title 的 p 節(jié)點的文本中。
定位到這兩個節(jié)點之后,我們就可以使用 CSS 提取字段信息了,這里對比一下常規(guī)寫法和 Scrapy 中的寫法:
- # 常規(guī)寫法
- url = item('.app_left_list>a').attr('href')
- name = item('.list_app_title').text()
- # Scrapy 寫法
- url = item.css('::attr("href")').extract_first()
- name = item.css('.detail_app_title::text').extract_first()
可以看到,要獲取 href 或者 text 屬性,需要用 :: 表示,比如獲取 text,則用 ::text。extract_first() 表示提取第一個元素,如果有多個元素,則用 extract() 。接著,我們就可以參照寫出 8 個字段信息的解析代碼。
首先,我們需要在主頁提取 App 的 URL 列表,然后再進入每個 App 的詳情頁進一步提取 8 個字段信息。
- def parse(self, response):
- contents = response.css('.app_left_list>a')
- for content in contents:
- url = content.css('::attr("href")').extract_first()
- url = response.urljoin(url) # 拼接相對 url 為絕對 url
- yield scrapy.Request(url,callback=self.parse_url)
這里,利用 response.urljoin() 方法將提取出的相對 URL 拼接為完整的 URL,然后利用 scrapy.Request() 方法構(gòu)造每個 App 詳情頁的請求,這里我們傳遞兩個參數(shù):url 和 callback,url 為詳情頁 URL,callback 是回調(diào)函數(shù),它將主頁 URL 請求返回的響應(yīng) response 傳給專門用來解析字段內(nèi)容的 parse_url() 方法,如下所示:
- def parse_url(self,response):
- item = KuanItem()
- item['name'] = response.css('.detail_app_title::text').extract_first()
- results = self.get_comment(response)
- item['volume'] = results[0]
- item['download'] = results[1]
- item['follow'] = results[2]
- item['comment'] = results[3]
- item['tags'] = self.get_tags(response)
- item['score'] = response.css('.rank_num::text').extract_first()
- num_score = response.css('.apk_rank_p1::text').extract_first()
- item['num_score'] = re.search('共(.*?)個評分',num_score).group(1)
- yield item
- def get_comment(self,response):
- messages = response.css('.apk_topba_message::text').extract_first()
- result = re.findall(r'\s+(.*?)\s+/\s+(.*?)下載\s+/\s+(.*?)人關(guān)注\s+/\s+(.*?)個評論.*?',messages) # \s+ 表示匹配任意空白字符一次以上
- if result: # 不為空
- 19 results = list(result[0]) # 提取出list 中第一個元素
- 20 return results
- 21
- 22def get_tags(self,response):
- 23 data = response.css('.apk_left_span2')
- 24 tags = [item.css('::text').extract_first() for item in data]
- 25 return tags
這里,單獨定義了 get_comment() 和 get_tags() 兩個方法.
get_comment() 方法通過正則匹配提取 volume、download、follow、comment 四個字段信息,正則匹配結(jié)果如下:
- result = re.findall(r'\s+(.*?)\s+/\s+(.*?)下載\s+/\s+(.*?)人關(guān)注\s+/\s+(.*?)個評論.*?',messages)
- print(result) # 輸出第一頁的結(jié)果信息
- # 結(jié)果如下:
- [('21.74M', '5218萬', '2.4萬', '5.4萬')]
- [('75.53M', '2768萬', '2.3萬', '3.0萬')]
- [('46.21M', '1686萬', '2.3萬', '3.4萬')]
- [('54.77M', '1603萬', '3.8萬', '4.9萬')]
- [('3.32M', '1530萬', '1.5萬', '3343')]
- [('75.07M', '1127萬', '1.6萬', '2.2萬')]
- [('92.70M', '1108萬', '9167', '1.3萬')]
- [('68.94M', '1072萬', '5718', '9869')]
- [('61.45M', '935萬', '1.1萬', '1.6萬')]
- [('23.96M', '925萬', '4157', '1956')]
然后利用 result[0]、result[1] 等分別提取出四項信息,以 volume 為例,輸出第一頁的提取結(jié)果:
- item['volume'] = results[0]
- print(item['volume'])
- 21.74M
- 75.53M
- 46.21M
- 54.77M
- 3.32M
- 75.07M
- 92.70M
- 68.94M
- 61.45M
- 23.96M
這樣一來,第一頁 10 款 App 的所有字段信息都被成功提取出來,然后返回到 yied item 生成器中,我們輸出一下它的內(nèi)容:
- [
- {'name': '酷安', 'volume': '21.74M', 'download': '5218萬', 'follow': '2.4萬', 'comment': '5.4萬', 'tags': "['酷市場', '酷安', '市場', 'coolapk', '裝機必備']", 'score': '4.4', 'num_score': '1.4萬'},
- {'name': '微信', 'volume': '75.53M', 'download': '2768萬', 'follow': '2.3萬', 'comment': '3.0萬', 'tags': "['微信', 'qq', '騰訊', 'tencent', '即時聊天', '裝機必備']",'score': '2.3', 'num_score': '1.1萬'},
- ...
- ]
2.3.4. 分頁爬取
以上,我們爬取了第一頁內(nèi)容,接下去需要遍歷爬取全部 610 頁的內(nèi)容,這里有兩種思路:
- 第一種是提取翻頁的節(jié)點信息,然后構(gòu)造出下一頁的請求,然后重復(fù)調(diào)用 parse 方法進行解析,如此循環(huán)往復(fù),直到解析完最后一頁。
- 第二種是先直接構(gòu)造出 610 頁的 URL 地址,然后批量調(diào)用 parse 方法進行解析。
這里,我們分別寫出兩種方法的解析代碼,第一種方法很簡單,直接接著 parse 方法繼續(xù)添加以下幾行代碼即可:
- def parse(self, response):
- contents = response.css('.app_left_list>a')
- for content in contents:
- ...
- next_page = response.css('.pagination li:nth-child(8) a::attr(href)').extract_first()
- url = response.urljoin(next_page)
- yield scrapy.Request(url,callback=self.parse )
第二種方法,我們在最開頭的 parse() 方法前,定義一個 start_requests() 方法,用來批量生成 610 頁的 URL,然后通過 scrapy.Request() 方法中的 callback 參數(shù),傳遞給下面的 parse() 方法進行解析。
- def start_requests(self):
- pages = []
- for page in range(1,610): # 一共有610頁
- url = 'https://www.coolapk.com/apk/?page=%s'%page
- page = scrapy.Request(url,callback=self.parse)
- pages.append(page)
- return pages
以上就是全部頁面的爬取思路,爬取成功后,我們需要存儲下來。這里,我面選擇存儲到 MongoDB 中,不得不說,相比 MySQL,MongoDB 要方便省事很多。
2.3.5. 存儲結(jié)果
我們在 pipelines.py 程序中,定義數(shù)據(jù)存儲方法,MongoDB 的一些參數(shù),比如地址和數(shù)據(jù)庫名稱,需單獨存放在 settings.py 設(shè)置文件中去,然后在 pipelines 程序中進行調(diào)用即可。
- import pymongo
- class MongoPipeline(object):
- def __init__(self,mongo_url,mongo_db):
- self.mongo_url = mongo_url
- self.mongo_db = mongo_db
- @classmethod
- def from_crawler(cls,crawler):
- return cls(
- mongo_url = crawler.settings.get('MONGO_URL'),
- mongo_db = crawler.settings.get('MONGO_DB')
- )
- def open_spider(self,spider):
- self.client = pymongo.MongoClient(self.mongo_url)
- self.db = self.client[self.mongo_db]
- def process_item(self,item,spider):
- name = item.__class__.__name__
- self.db[name].insert(dict(item))
- return item
- def close_spider(self,spider):
- self.client.close()
首先,我們定義一個 MongoPipeline()存儲類,里面定義了幾個方法,簡單進行一下說明:
- from crawler() 是一個類方法,用 @class method 標識,這個方法的作用主要是用來獲取我們在 settings.py 中設(shè)置的這幾項參數(shù):
- 1MONGO_URL = 'localhost'2MONGO_DB = 'KuAn'3ITEM_PIPELINES = {4 'kuan.pipelines.MongoPipeline': 300,5}
- open_spider() 方法主要進行一些初始化操作 ,在 Spider 開啟時,這個方法就會被調(diào)用 。
- process_item() 方法是最重要的方法,實現(xiàn)插入數(shù)據(jù)到 MongoDB 中。
完成上述代碼以后,輸入下面一行命令就可以開始整個爬蟲的抓取和存儲過程了,單機跑的話,6000 個網(wǎng)頁需要不少時間才能完成,保持耐心。
- scrapy crawl kuan
這里,還有兩點補充:
第一,為了減輕網(wǎng)站壓力,我們最好在每個請求之間設(shè)置幾秒延時,可以在 KuanSpider() 方法開頭出,加入以下幾行代碼:
- custom_settings = {
- "DOWNLOAD_DELAY": 3, # 延遲3s,默認是0,即不延遲
- "CONCURRENT_REQUESTS_PER_DOMAIN": 8 # 每秒默認并發(fā)8次,可適當降低
- }
第二,為了更好監(jiān)控爬蟲程序運行,有必要 設(shè)置輸出日志文件,可以通過 Python 自帶的 logging 包實現(xiàn):
- import logging
- logging.basicConfig(filename='kuan.log',filemode='w',level=logging.WARNING,format='%(asctime)s %(message)s',datefmt='%Y/%m/%d %I:%M:%S %p')
- logging.warning("warn message")
- logging.error("error message")
這里的 level 參數(shù)表示警告級別,嚴重程度從低到高分別是:DEBUG < INFO < WARNING < ERROR < CRITICAL,如果想日志文件不要記錄太多內(nèi)容,可以設(shè)置高一點的級別,這里設(shè)置為 WARNING,意味著只有 WARNING 級別以上的信息才會輸出到日志中去。
添加 datefmt 參數(shù)是為了在每條日志前面加具體的時間,這點很有用處。
以上,我們就完成了整個數(shù)據(jù)的抓取,有了數(shù)據(jù)我們就可以著手進行分析,不過這之前還需簡單地對數(shù)據(jù)做一下清洗和處理。
3. 數(shù)據(jù)清洗處理
首先,我們從 MongoDB 中讀取數(shù)據(jù)并轉(zhuǎn)化為 DataFrame,然后查看一下數(shù)據(jù)的基本情況。
- def parse_kuan():
- client = pymongo.MongoClient(host='localhost', port=27017)
- db = client['KuAn']
- collection = db['KuAnItem']
- # 將數(shù)據(jù)庫數(shù)據(jù)轉(zhuǎn)為DataFrame
- data = pd.DataFrame(list(collection.find()))
- print(data.head())
- print(df.shape)
- print(df.info())
- print(df.describe())
從 data.head() 輸出的前 5 行數(shù)據(jù)中可以看到,除了 score 列是 float 格式以外,其他列都是 object 文本類型。
comment、download、follow、num_score 這 5 列數(shù)據(jù)中部分行帶有「萬」字后綴,需要將字符去掉再轉(zhuǎn)換為數(shù)值型;volume 體積列,則分別帶有「M」和「K」后綴,為了統(tǒng)一大小,則需將「K」除以 1024,轉(zhuǎn)換為 「M」體積。
整個數(shù)據(jù)一共有 6086 行 x 8 列,每列均沒有缺失值。
df.describe() 方法對 score 列做了基本統(tǒng)計,可以看到,所有 App 的平均得分是 3.9 分(5 分制),最低得分 1.6 分,最高得分 4.8 分。
下面,我們將以上幾列文本型數(shù)據(jù)轉(zhuǎn)換為數(shù)值型數(shù)據(jù),代碼實現(xiàn)如下:
- def data_processing(df):
- #處理'comment','download','follow','num_score','volume' 5列數(shù)據(jù),將單位萬轉(zhuǎn)換為單位1,再轉(zhuǎn)換為數(shù)值型
- str = '_ori'
- cols = ['comment','download','follow','num_score','volume']
- for col in cols:
- colori = col+str
- df[colori] = df[col] # 復(fù)制保留原始列
- if not (col == 'volume'):
- df[col] = clean_symbol(df,col)# 處理原始列生成新列
- else:
- df[col] = clean_symbol2(df,col)# 處理原始列生成新列
- # 將download單獨轉(zhuǎn)換為萬單位
- df['download'] = df['download'].apply(lambda x:x/10000)
- # 批量轉(zhuǎn)為數(shù)值型
- df = df.apply(pd.to_numeric,errors='ignore')
- def clean_symbol(df,col):
- # 將字符“萬”替換為空
- con = df[col].str.contains('萬$')
- df.loc[con,col] = pd.to_numeric(df.loc[con,col].str.replace('萬','')) * 10000
- df[col] = pd.to_numeric(df[col])
- return df[col]
- def clean_symbol2(df,col):
- # 字符M替換為空
- df[col] = df[col].str.replace('M$','')
- # 體積為K的除以 1024 轉(zhuǎn)換為M
- con = df[col].str.contains('K$')
- df.loc[con,col] = pd.to_numeric(df.loc[con,col].str.replace('K$',''))/1024
- df[col] = pd.to_numeric(df[col])
- return df[col]
以上,就完成了幾列文本型數(shù)據(jù)的轉(zhuǎn)換,我們再來查看一下基本情況:
download 列為 App 下載數(shù)量,下載量最多的 App 有 5190 萬次,最少的為 0 (很少很少),平均下載次數(shù)為 14 萬次;從中可以看出以下幾點信息:
- volume 列為 App 體積,體積最大的 App 達到近 300M,體積最小的幾乎為 0,平均體積在 18M 左右。
- comment 列為 App 評分,評分數(shù)最多的達到了 5 萬多條,平均有 200 多條。
以上,就完成了基本的數(shù)據(jù)清洗處理過程,下面將對數(shù)據(jù)進行探索性分析。
4. 數(shù)據(jù)分析
我們主要從總體和分類兩個維度對 App 下載量、評分、體積等指標進行分析。
4.1. 總體情況
4.1.1. 下載量排名
首先來看一下 App 的下載量情況,很多時候我們下載一個 App ,下載量是一個非常重要的參考指標,由于絕大多數(shù) App 的下載量都相對較少,直方圖無法看出趨勢,所以我們擇將數(shù)據(jù)進行分段,離散化為柱狀圖,繪圖工具采用的是 Pyecharts。
可以看到多達 5517 款(占總數(shù) 84%)App 的下載量不到 10 萬, 而下載量超過 500 萬的僅有 20 款,開發(fā)一個要想盈利的 App ,用戶下載量尤為重要,從這一點來看,大部分 App 的處境都比較尷尬,至少是在酷安平臺上。
代碼實現(xiàn)如下:
- from pyecharts import Bar
- # 下載量分布
- bins = [0,10,100,500,10000]
- group_names = ['<=10萬','10-100萬','100-500萬','>500萬']
- cats = pd.cut(df['download'],bins,labels=group_names) # 用 pd.cut() 方法進行分段
- cats = pd.value_counts(cats)
- bar = Bar('App 下載數(shù)量區(qū)間分布','絕大部分 App 下載量低于 10 萬')
- # bar.use_theme('macarons')
- bar.add(
- 'App 數(shù)量 (個)',
- list(cats.index),
- list(cats.values),
- is_label_show = True,
- is_splitline_show = False,
- )
- bar.render(path='download_interval.png',pixel_ration=1)
接下來,我們看看 下載量最多的 20 款 App 是哪些:
可以看到,這里「酷安」App 以 5000 萬+ 次的下載量遙遙領(lǐng)先,是第二名微信 2700 萬下載量的近兩倍,這么巨大的優(yōu)勢也很容易理解,畢竟是自家的 App,如果你手機上沒有「酷安」,說明你還不算是一個真正的「搞機愛好者」,從圖中我們還可以看出以下幾點信息:
- TOP 20 款 App 中,很多都是裝機必備,算是比較大眾型的 App。
- 右側(cè) App 評分圖中可以看到僅有 5 款 App 評分超過了 4 分(5 分制),絕大多數(shù)的評分都不到 3 分,甚至到不到 2 分,到底是因為這些 App 開發(fā)者做不出好 App 還是根本不想做出來?
- 相較于其他 App,RE 管理器、綠色守護 這幾款非常突出,其中 RE 管理器在如此高的下載量下,仍然能夠得到 4.8 分(最高分)并且體積只有幾 M,實屬難得,什么是「良心 App」,這類就是。
作為對比,我們再來看看下載量最少的 20 款 App。
可以看到,與上面的那些下載量多的 App 相比,這些就相形見絀了,下載量最少的 「廣州限行通」更是只有 63 次下載。
這也不奇怪,可能是 App 沒有宣傳、也可能是剛開發(fā)出來,這么少的下載量評分還不錯,也還能繼續(xù)更新,為這些開發(fā)者點贊。
其實,這類 App 不算囧,真正囧的應(yīng)該是那些 下載量很多、評分卻低到不能再低 的 App,給人的感覺是:「我就這么爛愛咋咋地,有本事別用」。
4.1.2. 評分排名
接下來,我們看看 App 的總體得分情況。這里,將得分分為了以下 4 個區(qū)間段,并且為不同分數(shù)定義了相應(yīng)的等級。
可以發(fā)現(xiàn)這么幾點有意思的現(xiàn)象:
- 3 分以下的軟件非常少,只占不到 10%,而之前下載量最多的 20 款 APP 中,微信、QQ、淘寶、支付寶等大多數(shù)軟件的得分都不到 3 分,這就有點尷尬了。
- 中品也就是中等得分的 App 數(shù)量最多。
- 4 分以上的 高分 APP 數(shù)量占了近一半(46%),可能是這些 App 的確還不錯,也可能是由于評分數(shù)量過少,為了優(yōu)中選優(yōu),后續(xù)有必要設(shè)置一定篩選門檻。
接下來,我們看看評分最高的 20 款 App 有哪些,很多時候我們下載 App 都是跟著「哪個評分高,下載哪個」這種感覺走。
可以看到,評分最高的 20 個 App,它們都得到了 4.8 分 ,包括:RE 管理器(再次出現(xiàn))、Pure 輕雨圖標包等,還有一些不太常見,可能這些都是不錯的 App,不過我們還需要結(jié)合看一下下載量,它們的下載量都在 1 萬以上,有了一定的下載量,評分才算比較可靠,我們就能放心的下載下來體驗一下了。
經(jīng)過上面的總體分析,我們大致發(fā)現(xiàn)了一些不錯的 App ,但還不夠,所以接下來將進行細分并設(shè)置一定篩選條件。
4.2. 分類情況
按照 App 功能和日常使用場景,將 App 分為以下 9 大類別,然后 從每個類別中篩選出 20 款最棒的 App。
為了盡可能找出最好的 App,這里不妨設(shè)置 3 個條件:
- 評分不低于 4 分
- 下載量不低于 1 萬
- 設(shè)置一個總分評價指標(總分 = 下載量 * 評分),再標準化為滿分 1000 分,作為 App 的排名參照指標。
經(jīng)過評選之后,我們依次得到了各個類別下分數(shù)最高的 20 款 App,這些 App 大部分的確是良心軟件。
4.2.1. 系統(tǒng)工具
系統(tǒng)工具包括了:輸入法、文件管理 、系統(tǒng)清理、桌面、插件、鎖屏等。
可以看到,第一名是大名鼎鼎的老牌文件管理器「RE 管理器」,僅有 5 M 大小的它除了具備普通文件管理器的各項功能以外,最大的特點是能夠卸載手機自帶的 App,不過需要 Root。
「ES 文件瀏覽器」的文件分析器功能非常強大,能夠有效清理臃腫的手機空間。
「一個木函」這款 App 就比較牛逼了,正如它的軟件介紹「擁有很多,不如有我」所說,打開它你能發(fā)現(xiàn)它提供了好幾十項實用功能,比如:翻譯、以圖搜圖、快遞查詢、制作表情包等等。
再往下的「Super SU」、「存儲空間清理」、「鑭」、「MT 管理器」、「My Android Tools」都力薦,總之,這份榜單上的 App 可以說都值得進入你的手機 App 使用名單。
4.2.2. 社交聊天
社交聊天類中, 「Share 微博客戶端」位居第一,作為一款第三方客戶端 App,它自然有比官方版本好的地方,比如相比正版 70M 的體積,它只有其十分之一大小,也幾乎沒有廣告,還有額外強大的諸多功能,如果你愛刷微博,那么不妨嘗試下這款「Share」。
「即刻」這款 App 也相當不錯,再往下還能看到前陣子很火的「子彈短信」,宣稱將要取代微信,看來短期內(nèi)應(yīng)該是做不到了。
你可能會發(fā)現(xiàn),這份社交榜單上沒有出現(xiàn)「知乎」、「豆瓣」、「簡書」這類常見的 App,是因為它們的評分都比較低,分別只有 2.9分、3.5分和 2.9 分,自然進入不了這份名單,如果你一定想用它們,推薦去使用它們的第三方客戶端或者歷史版本。
4.2.3. 資訊閱讀
可以看到,在資訊閱讀類中,「靜讀天下」牢牢占據(jù)了第一名,我之前專門寫過一篇文章介紹它:安卓最強閱讀器。
同類別中的「多看閱讀」、「追書神器」、「微信讀書」也都進入了榜單。
另外,如果你經(jīng)常為不知道去哪里下載電子書而頭疼,那不妨試一下「搜書大師」、「老子搜書」。
4.2.4. 影音娛樂
接下來是影音娛樂版塊,網(wǎng)易家的「網(wǎng)易云音樂」毫無壓力地占據(jù)頭名,難得的大廠精品。
如果你愛玩游戲,那么 「Adobe AIR」應(yīng)該嘗試一下。
如果你很文藝,那么應(yīng)該會喜歡「VUE」這款短視頻拍攝 App,創(chuàng)作好以后發(fā)到朋友圈絕對能裝逼。
最后一位的「海貝音樂」很贊,最近發(fā)現(xiàn)它有一個強大的功能是結(jié)合百度網(wǎng)盤使用,它能夠自動識別音頻文件然后播放。
4.2.5. 通訊網(wǎng)絡(luò)
下面到了通訊網(wǎng)絡(luò)類別,這個類別主要包括:瀏覽器、通訊錄、通知、郵箱等小類。
瀏覽器,我們每個人手機上都有,用的也五花八門,有些人就用手機自帶的瀏覽器,有些人用 Chrome、火狐這類大牌瀏覽器。
不過你會發(fā)現(xiàn)榜單上的前三位你可能聽都沒聽過,但是它們真的很牛逼,用「極簡高效、清爽極速」來形容再適合不過,其中 「Via 」和 「X 瀏覽器」 體積不到 1M ,真正的「麻雀雖小、五臟俱全」,強烈推薦。
4.2.6. 攝影圖片
拍照修圖也是我們常用的功能。也許你有自己的圖片管理軟件,但是這里要強烈推薦第一名「快圖瀏覽」這款 App,只有 3M 大小的它,能夠瞬間發(fā)現(xiàn)和加載上萬張圖片,如果你是拍照狂魔,用它打開再多的照片也能秒開,另外還擁有隱藏私密照片、自動備份百度網(wǎng)盤等功能。它是我使用時間最久的 App 之一。
4.2.7. 文檔寫作
我們時常需要在手機上寫作、做備忘錄,那么自然需要好的文檔寫作類 App。
「印象筆記」就不用多說了,我覺得最好用的筆記總結(jié)類 App。
如果你喜歡使用 Markdown 寫作,那么「純純寫作」這款精巧的 App 應(yīng)該會很適合你。
體積不到 3M 卻擁有云備份、生成長圖、中英文自動空格等數(shù)十項功能,即使這樣,仍然保持了蘊繁于簡的設(shè)計風(fēng)格,這大概就是兩三個月之內(nèi),下載量就從兩三萬飆升了十倍的原因,而這款 App 的背后是一位 犧牲了幾年的業(yè)余時間不斷開發(fā)和更新的大佬,值得敬佩。
4.2.8. 出行交通購物
這個類別中,排名第一的居然是 12306,一提起它,就會想起那一張張奇葩的驗證碼,不過這里的 App 不是官網(wǎng)的 ,而是第三方開發(fā)的。最牛逼的功能應(yīng)該就是「搶票了」,如果你還在靠發(fā)朋友圈來搶票的話,那不妨試一下它。
4.2.9. Xposed 插件
最后一個類別是 Xposed,很多人應(yīng)該不太熟悉,但是一提微信上的搶紅包、防撤回功能,應(yīng)該很多人就知道了。這些牛逼又不同尋常的功能就用到了 Xposed 框架里的各種模塊功能。這個框架由國外著名的 XDA 手機論壇,你經(jīng)常聽到的一些所謂由 XDA 大神破解的軟件,就是來自這個論壇。
簡單地說就是,安裝了 Xposed 這個框架之后,就可以在里面安裝一些好玩有趣的插件,有了這些插件,你的手機就能實現(xiàn)更多更大的功能。比如:能夠去除廣告、破解 App 付費功能、殺死耗電的自啟動進程、虛擬手機定位等功能。
不過使用這個框架和這些插件需要刷機、ROOT,門檻有點高。
5. 小結(jié)
本文使用 Scrapy 框架爬取分析了酷安網(wǎng)的 6000 款 App,初學(xué) Scrapy 可能會覺得程序?qū)懫饋肀容^散亂,所以可以嘗試先使用普通的函數(shù)方法,把程序完整地寫在一起,再分塊拆分到 Scrapy 項目中,這樣也有助于從單一程序到框架寫法的思維轉(zhuǎn)變,之后會寫單獨寫一篇文章。
由于網(wǎng)頁版的 App 數(shù)量比 App 中的少,所以還有很多好用的 App 沒有包括進來,比如 Chrome 、MX player、Snapseed 等,建議使用酷安 App,那里有更多好玩的東西。
以上就是整篇文章的爬取與分析過程,文中涉及了很多精品佳軟,如有興趣可以去嘗試下載體驗一下