pyspider 爬取並分析虎嗅網 5 萬篇文章

摘要: 很多時候,一篇文章可否獲得普遍的傳播,除了文章自己實打實的質量之外,一個好的標題也相當重要。本文爬取了虎嗅網建站至今共 5 萬條新聞標題內容,助你找到起文章標題的技巧與靈感。同時,分享一些值得關注的文章和做者。html

1. 分析背景

1.1. 爲何選擇虎嗅

在衆多新媒體網站中,「虎嗅」網的文章內容和質量還算不錯。在「新榜」科技類公衆號排名中,它位居榜單第 3 名,仍是比較受歡迎的。因此選擇爬取該網站的文章信息,順便從中瞭解一下這幾年科技互聯網都出現了哪些熱點信息。python

「關於虎嗅」git

虎嗅網創辦於 2012 年 5 月,是一個聚合優質創新信息與人羣的新媒體平臺。該平臺專一於貢獻原創、深度、犀利優質的商業資訊,圍繞創新創業的觀點進行剖析與交流。虎嗅網的核心,是關注互聯網及傳統產業的融合、明星公司的起落軌跡、產業潮汐的動力與趨勢。github

1.2. 分析內容

  • 分析虎嗅網 5 萬篇文章的基本狀況,包括收藏數、評論數等
  • 發掘最受歡迎和最不受歡迎的文章及做者
  • 分析文章標題形式(長度、句式)與受歡迎程度之間的關係
  • 展示近些年科技互聯網行業的熱門詞彙

1.3. 分析工具

  • Python
  • pyspider
  • MongoDB
  • Matplotlib
  • WordCloud
  • Jieba

2. 數據抓取

使用 pyspider 抓取了虎嗅網的主頁文章,文章抓取時期爲 2012 年建站至 2018 年 11 月 1 日,共計約 5 萬篇文章。抓取 了 7 個字段信息:文章標題、做者、發文時間、評論數、收藏數、摘要和文章連接。web

2.1. 目標網站分析

這是要爬取的 網頁界面,能夠看到是經過 AJAX 加載的。數據庫

右鍵打開開發者工具查看翻頁規律,能夠看到 URL 請求是 POST 類型,下拉到底部查看 Form Data,表單需提交參數只有 3 項。經嘗試, 只提交 page 參數就能成功獲取頁面的信息,其餘兩項參數可有可無,因此構造分頁爬取很是簡單。json

huxiu_hash_code: 39bcd9c3fe9bc69a6b682343ee3f024a
page: 4
last_dateline: 1541123160
複製代碼

接着,切換選項卡到 Preview 和 Response 查看網頁內容,能夠看到數據都位於 data 字段裏。total_page 爲 2004,表示一共有 2004 頁的文章內容,每一頁有 25 篇文章,總共約 5 萬篇,也就是咱們要爬取的數量。api

以上,咱們就找到了所需內容,接下來能夠開始構造爬蟲,整個爬取思路比較簡單。以前咱們也練習過這一類 Ajax 文章的爬取,能夠參考:瀏覽器

抓取澎湃網建站至今 1500 期信息圖欄目圖片微信

2.2. pyspider 介紹

和以前文章不一樣的是,這裏咱們使用一種新的工具來進行爬取,叫作:pyspider 框架。由國人 binux 大神開發,GitHub Star 數超過 12 K,足以證實它的知名度。能夠說,學習爬蟲不能不會使用這個框架。

網上關於這個框架的介紹和實操案例很是多,這裏僅簡單介紹一下。

咱們以前的爬蟲都是在 Sublime 、PyCharm 這種 IDE 窗口中執行的,整個爬取過程能夠說是處在黑箱中,內部運行的些細節並不太清楚。而 pyspider 一大亮點就在於提供了一個可視化的 WebUI 界面,可以清楚地查看爬蟲的運行狀況。

pyspider 的架構主要分爲 Scheduler(調度器)、Fetcher(抓取器)、Processer(處理器)三個部分。Monitor(監控器)對整個爬取過程進行監控,Result Worker(結果處理器)處理最後抓取的結果。

咱們看看該框架的運行流程大體是怎麼樣的:

  • 一個 pyppider 爬蟲項目對應一個 Python 腳本,腳本里定義了一個 Handler 主類。爬取時首先調用 on_start() 方法生成最初的抓取任務,而後發送給 Scheduler。
  • Scheduler 將抓取任務分發給 Fetcher 進行抓取,Fetcher 執行而後獲得 Response、隨後將 Response 發送給 Processer。
  • Processer 處理響應並提取出新的 URL 而後生成新的抓取任務,而後經過消息隊列的方式通知 Scheduler 當前抓取任務執行狀況,並將新生成的抓取任務發送給 Scheduler。若是生成了新的提取結果,則將其發送到結果隊列等待 Result Worker 處理。
  • Scheduler 接收到新的抓取任務,而後查詢數據庫,判斷其若是是新的抓取任務或者是須要重試的任務就繼續進行調度,而後將其發送回 Fetcher 進行抓取。
  • 不斷重複以上工做、直到全部的任務都執行完畢,抓取結束。
  • 抓取結束後、程序會回調 on_finished() 方法,這裏能夠定義後處理過程。

該框架比較容易上手,網頁右邊是代碼區,先定義類(Class)而後在裏面添加爬蟲的各類方法(也能夠稱爲函數),運行的過程會在左上方顯示,左下方則是輸出結果的區域。

這裏,分享幾個不錯的教程以供參考:

GitHub 項目地址:github.com/binux/pyspi…

官方主頁:docs.pyspider.org/en/latest/

pyspider 中文網:www.pyspider.cn/page/1.html

pyspider 爬蟲原理剖析:python.jobbole.com/81109/

pyspider 爬淘寶圖案例實操:cuiqingcai.com/2652.html

安裝好該框架後,下面咱們能夠就開始爬取了。

2.3. 抓取數據

CMD 命令窗口執行:pyspider all 命令,而後瀏覽器輸入:http://localhost:5000/ 就能夠啓動 pyspider 。

點擊 Create 新建一個項目,Project Name 命名爲:huxiu,由於要爬取的 URL 是 POST 類型,因此這裏能夠先不填寫,以後能夠在代碼中添加,再次點擊 Creat 便完成了該項目的新建。

新項目創建好後會自動生成一部分模板代碼,咱們只需在此基礎上進行修改和完善,而後就能夠運行爬蟲項目了。如今,簡單梳理下代碼編寫步驟。

from pyspider.libs.base_handler import *
class Handler(BaseHandler):
    crawl_config:{
        "headers":{
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',
            'X-Requested-With': 'XMLHttpRequest'
            }
    }
	def on_start(self):
        for page in range(2,3): # 先循環1頁
            print('正在爬取第 %s 頁' % page)
            self.crawl('https://www.huxiu.com/v2_action/article_list',method='POST',data={'page':page}, callback=self.index_page)
複製代碼

這裏,首先定義了一個 Handler 主類,整個爬蟲項目都主要在該類下完成。 接着,能夠將爬蟲基本的一些基本配置,好比 Headers、代理等設置寫在下面的 crawl_config 屬性中。(若是你尚未習慣從函數(def)轉換到類(Class)的代碼寫法,那麼須要先了解一下類的相關知識,以後我也會單獨用一篇文章介紹一下。)

下面的 on_start() 方法是程序的入口,也就是說程序啓動後會首先從這裏開始運行。首先,咱們將要爬取的 URL傳入 crawl() 方法,同時將 URL 修改爲虎嗅網的:www.huxiu.com/v2_action/a… 因爲 URL 是 POST 請求,因此咱們還須要增長兩個參數:method 和 data。method 表示 HTTP 請求方式,默認是 GET,這裏咱們須要設置爲 POST;data 是 POST 請求表單參數,只須要添加一個 page 參數便可。

接着,經過 callback 參數定義一個 index_page() 方法,用來解析 crawl() 方法爬取 URL 成功後返回的 Response 響應。在後面的 index_page() 方法中,可使用 PyQuery 提取響應中的所需內容。具體提取方法以下:

import json
from pyquery import PyQuery as pq
def index_page(self, response):
        content = response.json['data']
        # 注意,在sublime中,json後面須要添加(),pyspider 中則不用
        doc = pq(content)
        lis = doc('.mod-art').items()
        data = [{
            'title': item('.msubstr-row2').text(),
            'url':'https://www.huxiu.com'+ str(item('.msubstr-row2').attr('href')),
            'name': item('.author-name').text(),
            'write_time':item('.time').text(),
            'comment':item('.icon-cmt+ em').text(),
            'favorites':item('.icon-fvr+ em').text(),
            'abstract':item('.mob-sub').text()
            } for item in lis ]   # 列表生成式結果返回每頁提取出25條字典信息構成的list
        print(data)
        return data
    
複製代碼

這裏,網頁返回的 Response 是 json 格式,待提取的信息存放在其中的 data 鍵值中,由一段 HTML 代碼構成。咱們可使用 response.json['data'] 獲取該 HTML 信息,接着使用 PyQuery 搭配 CSS 語法提取出文章標題、連接、做者等所需信息。這裏使用了列表生成式,可以精簡代碼而且轉換爲方便的 list 格式,便於後續存儲到 MongoDB 中。咱們輸出並查看一下第 2 頁的提取結果:

# 由25個 dict 構成的 list
[{'title': '想要長生不老?殺死體內的「殭屍細胞」吧', 'url': 'https://www.huxiu.com/article/270086.html', 'name': '造就Talk', 'write_time': '19小時前', 'comment': '4', 'favorites': '28', 'abstract': '若是有了最終療法,也不該該是天天都須要接受治療'}, 
 {'title': '日本步入下流社會,咱們還在買買買', 'url': 'https://www.huxiu.com/article/270112.html', 'name': '騰訊《你們》©', 'write_time': '20小時前', 'comment': '13', 'favorites': '142', 'abstract': '我買,故我在'}
...
]
複製代碼

能夠看到,成功獲得所需數據,而後就能夠保存了,能夠選擇輸出爲 CSV、MySQL、MongoDB 等方式,這裏咱們選擇保存到 MongoDB 中。

import pandas as pd
import pymongo
import time
import numpy as np
client = pymongo.MongoClient('localhost',27017)
db = client.Huxiu
mongo_collection = db.huxiu_news

def on_result(self,result):
        if result:
            self.save_to_mongo(result)  
def save_to_mongo(self,result):
    df = pd.DataFrame(result)
    #print(df)
    content = json.loads(df.T.to_json()).values()
    if mongo_collection.insert_many(content):
        print('存儲到 mongondb 成功')
        # 隨機暫停
        sleep = np.random.randint(1,5)
        time.sleep(sleep)
複製代碼

上面,定義了一個 on_result() 方法,該方法專門用來獲取 return 的結果數據。這裏用來接收上面 index_page() 返回的 data 數據,在該方法裏再定義一個存儲到 MongoDB 的方法就能夠保存到 MongoDB 中。關於數據如何存儲到 MongoDB 中,咱們在以前的 一篇文章 中有過介紹,若是忘記了能夠回顧一下。

下面,咱們來測試一下整個爬取和存儲過程。點擊左上角的 run 就能夠順利運行單個網頁的抓取、解析和存儲,結果以下:

上面完成了單頁面的爬取,接下來,咱們須要爬取所有 2000 餘頁內容。

須要修改兩個地方,首先在 on_start() 方法中將 for 循環頁數 3 改成 2002。改好之後,若是咱們直接點擊 run ,會發現仍是隻能爬取第 2 頁的結果。這是由於,pyspider 以 URL的 MD5 值做爲 惟一 ID 編號,ID 編號相同的話就視爲同一個任務,便不會再重複爬取。因爲 GET 請求的 分頁URL 一般是有差別的,因此 ID 編號會不一樣,也就天然可以爬取多頁。但這裏 POST 請求的分頁 URL 是相同的,因此爬完第 2 頁,後面的頁數便不會再爬取。

那有沒有解決辦法呢? 固然是有的,咱們須要從新寫下 ID 編號的生成方式,方法很簡單,在 on_start() 方法前面添加下面 2 行代碼便可:

def get_taskid(self,task):
    return md5string(task['url']+json.dumps(task['fetch'].get('data','')))
複製代碼

這樣,咱們再點擊 run 就可以順利爬取 2000 頁的結果了,我這裏一共抓取了 49,996 條結果,耗時 2 小時左右完成。

以上,就完成了數據的獲取。有了數據咱們就能夠着手分析,不過這以前還需簡單地進行一下數據的清洗、處理。

3. 數據清洗處理

首先,咱們須要從 MongoDB 中讀取數據,並轉換爲 DataFrame。

client = pymongo.MongoClient(host='localhost', port=27017)
db = client['Huxiu']
collection = db['huxiu_news']
# 將數據庫數據轉爲DataFrame
data = pd.DataFrame(list(collection.find()))
複製代碼

下面咱們看一下數據的整體狀況,能夠看到數據的維度是 49996 行 × 8 列。發現多了一列無用的 _id 需刪除,同時 name 列有一些特殊符號,好比© 需刪除。另外,數據格式所有爲 Object 字符串格式,須要將 comment 和 favorites 兩列更改成數值格式、 write_time 列更改成日期格式。

print(data.shape)  # 查看行數和列數
print(data.info()) # 查看整體狀況
print(data.head()) # 輸出前5行

# 結果:
(49996, 8)
Data columns (total 8 columns):
_id           49996 non-null object
abstract      49996 non-null object
comment       49996 non-null object
favorites     49996 non-null object
name          49996 non-null object
title         49996 non-null object
url           49996 non-null object
write_time    49996 non-null object
dtypes: object(8)
    
	_id	abstract	comment	favorites	name	title	url	write_time
0	5bdc2	「在大家看到…	22	50	普象工業設計小站©	看了蘋果屌	https://	10小時前
1	5bdc2	中國」綠卡」號稱「世界最難拿」	9	16	經濟觀察報©	遞交材料厚	https://	10小時前
2	5bdc2	鮮衣怒馬少年時	2	13	小馬宋	金庸小說陪	https://	11小時前
3	5bdc2	預告仍是預警?	3	10	Cuba Libre	阿里即將發	https://	11小時前
4	5bdc2	庫克:咋回事?	2	3	Cuba Libre	【虎嗅早報	https://	11小時前
複製代碼

代碼實現以下:

# 刪除無用_id列
data.drop(['_id'],axis=1,inplace=True)
# 替換掉特殊字符©
data['name'].replace('©','',inplace=True,regex=True)
# 字符更改成數值
data = data.apply(pd.to_numeric,errors='ignore')
# 更該日期格式
data['write_time'] = data['write_time'].replace('.*前','2018-10-31',regex=True) 
# 爲了方便,將write_time列,包含幾小時前和幾天前的行,都替換爲10月31日最後1天。
data['write_time'] = pd.to_datetime(data['write_time'])
複製代碼

下面,咱們看一下數據是否有重複,若是有,那麼須要刪除。

# 判斷整行是否有重複值
print(any(data.duplicated()))
# 顯示True,代表有重複值,進一步提取出重複值數量
data_duplicated = data.duplicated().value_counts()
print(data_duplicated) # 顯示2 True ,代表有2個重複值
# 刪除重複值
data = data.drop_duplicates(keep='first')
# 刪除部分行後,index中斷,需從新設置index
data = data.reset_index(drop=True)
#結果:
True 
False    49994
True         2
複製代碼

而後,咱們再增長兩列數據,一列是文章標題長度列,一列是年份列,便於後面進行分析。

data['title_length'] = data['title'].apply(len)
data['year'] = data['write_time'].dt.year
Data columns (total 9 columns):
abstract        49994 non-null object
comment         49994 non-null int64
favorites       49994 non-null int64
name            49994 non-null object
title           49994 non-null object
url             49994 non-null object
write_time      49994 non-null datetime64[ns]
title_length    49994 non-null int64
year            49994 non-null int64
複製代碼

以上,就完成了基本的數據清洗處理過程,針對這 9 列數據能夠開始進行分析了。

4. 描述性數據分析

一般,數據分析主要分爲四類: 「描述型分析」、「診斷型分析」「預測型分析」「規範型分析」。「描述型分析」是用來歸納、表述事物總體情況以及事物間關聯、類屬關係的統計方法,是這四類中最爲常見的數據分析類型。經過統計處理能夠簡潔地用幾個統計值來表示一組數據地集中性(如平均值、中位數和衆數等)和離散型(反映數據的波動性大小,如方差、標準差等)。

這裏,咱們主要進行描述性分析,數據主要爲數值型數據(包括離散型變量和連續型變量)和文本數據。

4.1. 整體狀況

先來看一下整體狀況。

print(data.describe())
             comment     favorites  title_length 
count  49994.000000  49994.000000  49994.000000  
mean      10.860203     34.081810     22.775333  
std       24.085969     48.276213      9.540142  
min        0.000000      0.000000      1.000000  
25%        3.000000      9.000000     17.000000  
50%        6.000000     19.000000     22.000000  
75%       12.000000     40.000000     28.000000  
max     2376.000000   1113.000000    224.000000  
複製代碼

這裏,使用了 data.describe() 方法對數值型變量進行統計分析。從上面能夠簡要得出如下幾個結論:

  • 讀者的評論和收藏熱情都不算過高,大部分文章(75 %)的評論數量爲十幾條,收藏數量不過幾十個。這和一些微信大 V 公衆號動輒百萬級閱讀、數萬級評論和收藏量相比,虎嗅網的確相對小衆一些。不過也正是由於小衆,也才深得部分人的喜歡。
  • 評論數最多的文章有 2376 條,收藏數最多的文章有 1113 個收藏量,說明仍是有一些潛在的比較火或者質量比較好的文章。
  • 最長的文章標題長達 224 個字,大部分文章標題長度在 20 來個字左右,因此標題最好不要太長或太短。

對於非數值型變量(name、write_time),使用 describe() 方法會產生另一種彙總統計。

print(data['name'].describe())
print(data['write_time'].describe())
# 結果:
count     49994
unique     3162
top          虎嗅
freq      10513
Name: name, dtype: object
count                   49994
unique                   2397
top       2014-07-10 00:00:00
freq                      274
first     2012-04-03 00:00:00
last      2018-10-31 00:00:00
複製代碼

unique 表示惟一值數量,top 表示出現次數最多的變量,freq 表示該變量出現的次數,因此能夠簡單得出如下幾個結論:

  • 在文章來源方面,3162 個做者貢獻了這 5 萬篇文章,其中自家官網「虎嗅」寫的數量最多,超過了 1 萬篇,這也很天然。
  • 在文章發表時間方面,最先的一篇文章來自於 2012年 4 月 3 日。 6 年多時間,發文數最多的 1 天 是 2014 年 7 月 10 日,一共發了 274 篇文章。

4.2. 不一樣時期文章發佈的數量變化

能夠看到 ,以季度爲時間尺度的6 年間,前幾年發文數量比較穩定,大概在1750 篇左右,個別季度數量激增到 2000 篇以上。2016 年以後文章開始增長到 2000 篇以上,可能跟網站知名度提高有關。首尾兩個季度日期不全,因此數量比較少。

具體代碼實現以下:

def analysis1(data):
    # # 彙總統計
    # print(data.describe())
    # print(data['name'].describe())
    # print(data['write_time'].describe())
    
    data.set_index(data['write_time'],inplace=True)
    data = data.resample('Q').count()['name']  # 以季度彙總
    data = data.to_period('Q')
    # 建立x,y軸標籤
    x = np.arange(0,len(data),1)
    ax1.plot(x,data.values, #x、y座標
        color = color_line , #折線圖顏色爲紅色
        marker = 'o',markersize = 4 #標記形狀、大小設置
        )
    ax1.set_xticks(x) # 設置x軸標籤爲天然數序列
    ax1.set_xticklabels(data.index) # 更改x軸標籤值爲年份
    plt.xticks(rotation=90) # 旋轉90度,不至太擁擠

    for x,y in zip(x,data.values):
        plt.text(x,y + 10,'%.0f' %y,ha = 'center',color = colors,fontsize=fontsize_text )
        # '%.0f' %y 設置標籤格式不帶小數
    # 設置標題及橫縱座標軸標題
    plt.title('虎嗅網文章數量發佈變化(2012-2018)',color = colors,fontsize=fontsize_title)
    plt.xlabel('時期')
    plt.ylabel('文章(篇)')
    plt.tight_layout()  # 自動控制空白邊緣
    plt.savefig('虎嗅網文章數量發佈變化.png',dpi=200)
    plt.show()
複製代碼

4.3. 文章收藏量 TOP 10

接下來,到了咱們比較關心的問題:幾萬篇文章裏,到底哪些文章寫得比較好或者比較火?

序號 title favorites comment
1 讀完這10本書,你就能站在智商鄙視鏈的頂端了 1113 13
2 京東打臉央視:你所謂的翻新iPhone均爲正品,咱們保留向警方報案的權利 867 10
3 離職創業?先讀完這22本書再說 860 9
4 貨幣如水,覆水難收 784 39
5 自殺經濟學 778 119
6 2016年已經起飛的5只黑天鵝,都在羅振宇這份跨年演講全文裏 774 39
7 真正強大的商業分析能力是怎樣煉成的? 746 18
8 騰訊沒有夢想 705 32
9 段永平連答53問,核心是「不爲清單」 703 27
10 王健林的滑鐵盧 701 92

此處選取了「favorites」(收藏數量)做爲衡量標準。畢竟,通常好的文章,咱們都會有收藏的習慣。

第一名「讀完這10本書,你就能站在智商鄙視鏈的頂端了 」以 1113 次收藏位居第一,而且遙遙領先於後者,看來你們都懷有「想早日攀上人生巔峯,一覽衆人小」的想法啊。打開這篇文章的連接,文中提到了這幾本書:《思考,快與慢》、《思考的技術》、《麥肯錫入職第一課:讓職場新人一輩子受用的邏輯思考力》等。一本都沒看過,看來這輩子是很難登上人生巔峯了。

發現兩個有意思的地方。

第一,文章標題都比較短小精煉。

第二,文章收藏量雖然比較高,但評論數都很少,猜想這是由於 你們都喜歡作伸手黨

4.4. 歷年文章收藏量 TOP3

在瞭解文章的整體排名以後,咱們來看看歷年的文章排名是怎樣的。這裏,每一年選取了收藏量最多的 3 篇文章。

year title favorites
2012 產品的思路——來自騰訊張小龍的分享(全版) 187
Fab CEO:創辦四家公司教給個人90件事 163
張小龍:微信背後的產品觀 162
2013 創業者手記:我所犯的那些入門錯誤 473
馬化騰三小時講話實錄:千億美金這個線,其實很恐怖 391
雕爺親身談:白手起家的我如何在30歲以前賺到1000萬。讀《MBA教不了的創富課》 354
2014 85後,突變的一代 528
雕爺自述:什麼是我作餐飲時琢磨、而大部分「外人」沒法涉獵的思考? 521
聽說這40張PPT是螞蟻金服的內部培訓資料…… 485
2015 讀完這10本書,你就能站在智商鄙視鏈的頂端了 1113
京東打臉央視:你所謂的翻新iPhone均爲正品,咱們保留向警方報案的權利 867
離職創業?先讀完這22本書再說 860
2016 蝗蟲般的刷客大軍:手握千萬手機號,分秒間薅幹一家平臺 554
準CEO必讀的這20本書,你讀過幾本? 548
運營簡史:一文讀懂互聯網運營的20年發展與演變 503
2017 2016年已經起飛的5只黑天鵝,都在羅振宇這份跨年演講全文裏 774
真正強大的商業分析能力是怎樣煉成的? 746
王健林的滑鐵盧 701
2018 貨幣如水,覆水難收 784
自殺經濟學 778
騰訊沒有夢想 705

能夠看到,文章收藏量基本是逐年遞增的,但 2015 年的 3 篇文章的收藏量倒是最高的,包攬了總排名的前 3 名,不知道這一年的文章有什麼特別之處。

以上只羅列了一小部分文章的標題,能夠看到標題起地都蠻有水準的。關於標題的重要性,有這樣通俗的說法:「一篇好文章,標題佔一半」,一個好的標題能夠大大加強文章的傳播力和吸引力。文章標題雖只有短短數十字,但要想起好,裏面也是頗有不少技巧的。

好在,這裏提供了 5 萬個標題能夠參考。如需,能夠在公衆號後臺回覆「虎嗅」獲得這份 CSV 文件。

代碼實現以下:

def analysis2(data):
    # # 總收藏排名
    # top = data.sort_values(['favorites'],ascending = False)
    # # 收藏前10
    # top.index = (range(1,len(top.index)+1)) # 重置index,並從1開始編號
    # print(top[:10][['title','favorites','comment']])

    # 按年份排名
    # # 增長一列年份列
    # data['year'] = data['write_time'].dt.year
    def topn(data):
        top = data.sort_values('favorites',ascending=False)
        return top[:3]
    data = data.groupby(by=['year']).apply(topn)
    print(data[['title','favorites']])
    # 增長每一年top123列,列依次值爲一、二、3
    data['add'] = 1 # 輔助
    data['top'] = data.groupby(by='year')['add'].cumsum()
    data_reshape = data.pivot_table(index='year',columns='top',values='favorites').reset_index()
    # print(data_reshape) # ok
    data_reshape.plot(
        # x='year',
        y=[1,2,3],
        kind='bar',
        width=0.3,
        color=['#1362A3','#3297EA','#8EC6F5']  # 設置不一樣的顏色
        # title='虎嗅網歷年收藏數最多的3篇文章'
        )
    plt.xlabel('Year')
    plt.ylabel('文章收藏數量')
    plt.title('歷年 TOP3 文章收藏量比較',color = colors,fontsize=fontsize_title)
    plt.tight_layout()  # 自動控制空白邊緣,以所有顯示x軸名稱
    # plt.savefig('歷年 Top3 文章收藏量比較.png',dpi=200)
    plt.show()
複製代碼

4.4.1. 最高產做者 TOP20

上面,咱們從收藏量指標進行了分析,下面,咱們關注一下發布文章的做者(我的/媒體)。前面提到發文最多的是虎嗅官方,有一萬多篇文章,這裏咱們篩除官媒,看看還有哪些比較高產的做者。

能夠看到,前 20 名做者的發文量差距都不太大。發文比較多的有「娛樂資本論」、「Eastland」、「發條橙子」這類媒體號;也有虎嗅官網團隊的做者:發條橙子、周超臣、張博文等;還有部分獨立做者:僞裝FBI、孫永傑等。能夠嘗試關注一下這些高產做者。

代碼實現以下:

def analysis3(data):
    data = data.groupby(data['name'])['title'].count()
    data = data.sort_values(ascending=False)
    # pandas 直接繪製,.invert_yaxis()顛倒順序
    data[1:21].plot(kind='barh',color=color_line).invert_yaxis()
    for y,x in enumerate(list(data[1:21].values)):
        plt.text(x+12,y+0.2,'%s' %round(x,1),ha='center',color=colors)
    plt.xlabel('文章數量')
    plt.ylabel('做者')
    plt.title('發文數量最多的 TOP20 做者',color = colors,fontsize=fontsize_title)
    plt.tight_layout()
    plt.savefig('發文數量最多的TOP20做者.png',dpi=200)
    plt.show()
複製代碼

4.4.2. 平均文章收藏量最多做者 TOP 10

咱們關注一個做者除了是由於文章高產之外,可能更看重的是其文章水準。這裏咱們選擇「文章平均收藏量」(總收藏量/文章數)這個指標,來看看文章水準比較高的做者是哪些人。

這裏,爲了不出現「某做者只寫了一篇高收藏率的文章」這種不能表明其真實水準的狀況,咱們將篩選範圍定在至少發佈過 5 篇文章的做者們。

name total_favorites ariticls_num avg_favorites
重讀 1947 6 324
樓臺 2302 8 287
彭縈 2487 9 276
曹山石 1187 5 237
飯統戴老闆 7870 36 218
筆記俠 1586 8 198
辯手李慕陽 11989 62 193
李錄 2370 13 182
高曉鬆 889 5 177
寧南山 2827 16 176

能夠看到,前 10 名做者包括:遙遙領先的 重讀、兩位高產又有質量的 辯手李慕陽飯統戴老闆 ,還有大衆比較熟悉的 高曉鬆、**寧南山 **等。

若是你將這份名單和上面那份高產做者名單進行對比,會發現他們沒有出如今這個名單中。相比於數量,質量可能更重要吧。

下面,咱們就來看看排名第一的 重讀 都寫了哪些高收藏量文章。

order title favorites write_time
1 我採訪出200多萬字素材,還原了阿里系崛起前傳 231 2018/10/31
2 阿里史上最強人事地震回顧:中供鐵軍何以被生生解體 494 2018/4/9
3 馬雲「斬」衛哲:復原阿里史上最震撼的人事地震 578 2018/3/15
4 重讀一場馬雲發起、針對衛哲的批鬥會 269 2017/8/31
5 阿里「中供系」前世此生:馬雲麾下最神祕的子弟兵 203 2017/5/10
6 揭祕馬雲麾下最神祕的子弟兵:阿里「中供系」的前世此生 172 2017/4/26

竟然寫的都是清一色關於馬老闆家的文章。

瞭解了前十名做者以後,咱們順便也看看那些處於最後十名的都是哪些做者。

name total_favorites ariticls_num avg_favorites
于斌 25 11 2
朝克圖 33 23 1
東風日產 24 13 1
董曉常 14 8 1
蔡鈺 31 16 1
馬繼華 12 11 1
angeljie 7 5 1
薛開元 6 6 1
pookylee 15 24 0
Yang Yemeng 0 7 0

一對比,就能看到他們的文章收藏量就比較寒磣了。尤爲好奇最後一位做者 Yang Yemeng ,他寫了 7 篇文章,居然一個收藏都沒有。

來看看他究竟寫了些什麼文章。

原來寫的全都是英文文章,看來你們並不太鐘意閱讀英文類的文章啊。

具體實現代碼:

def analysis4(data):
    data = pd.pivot_table(data,values=['favorites'],index='name',aggfunc=[np.sum,np.size])
    data['avg'] = data[('sum','favorites')]/data[('size','favorites')]
    # 平均收藏數取整
    # data['avg'] = data['avg'].round(decimals=1)
    data['avg'] = data['avg'].astype('int')
    # flatten 平鋪列
    data.columns = data.columns.get_level_values(0)
    data.columns = ['total_favorites','ariticls_num','avg_favorites']
    # 篩選出文章數至少5篇的
    data=data.query('ariticls_num > 4')
    data = data.sort_values(by=['avg_favorites'],ascending=False)
    # # 查看平均收藏率第一名詳情
    # data = data.query('name == "重讀"')
    # # 查看平均收藏率倒數第一名詳情
    # data = data.query('name == "Yang Yemeng"')
    # print(data[['title','favorites','write_time']])
    print(data[:10]) 	# 前10名
    print(data[-10:])	# 後10名
複製代碼

4.5. 文章評論數最多 TOP10

說完了收藏量。下面,咱們再來看看評論數量最多的文章是哪些。

order title comment favorites
1 喜瓜2.0—明星社交應用的中國式引進與創新 2376 3
2 百度,請給「兒子們」好好起個名字 1297 9
3 三星S5爲何對鳳凰新聞客戶端下注? 1157 1
4 三星Tab S:馬是什麼樣的馬?鞍又是什麼樣的鞍? 951 0
5 三星,正在重塑你的營銷觀 914 1
6 馬化騰,你就把微信賣給運營商得了! 743 20
7 【文字直播】羅永浩 VS 王自如 網絡公開辯論 711 33
8 看三星Hub如何推進數字內容消費變革 684 1
9 三星要從新定義軟件與內容商店新模式,SO? 670 0
10 三星Hub——數字內容交互新模式 611 0

基本上都是和 三星 有關的文章,這些文章大多來自 2014 年,那幾年 三星 好像是挺火的,不過這兩年國內基本上都見不到三星的影子了,世界變化真快。

發現了兩個有意思的現象。

第一,上面關於 三星 和前面 阿里 的這些批量文章,它們「霸佔」了評論和收藏榜,結合知乎上曾經的一篇關於介紹虎嗅這個網站的文章:虎嗅網實際上是這樣的 ,貌似能發現些微妙的事情。

第二,這些文章評論數和收藏數兩個指標幾乎呈極端趨勢,評論量多的文章收藏量卻不多,評論量少的文章收藏量卻不少。

咱們進一步觀察下這兩個參數的關係。

能夠看到,大多數點都位於左下角,意味着這些文章收藏量和評論數都比較低。但也存在少部分位於上方和右側的異常值,代表這些文章呈現 「多評論、少收藏」或者「少評論、多收藏」的特色。

4.6. 文章標題長度

下面,咱們再來看看文章標題的長度和收藏量之間有沒有什麼關係。

大體能夠看出兩點現象:

第一,收藏量高的文章,他們的標題都比較短(右側的部分散點)。

第二,標題很長的文章,它們的收藏量都很是低(左邊造成了一條垂直線)。

看來,文章起標題時最好不要起太長的。

實現代碼以下:

def analysis5(data):
    plt.scatter(
        x=data['favorites'],
        y =data['comment'],
        s=data['title_length']/2,
        )
    plt.xlabel('文章收藏量')
    plt.ylabel('文章評論數')
    plt.title('文章標題長度與收藏量和評論數之間的關係',color = colors,fontsize=fontsize_title)
    plt.tight_layout() 
    plt.show()
複製代碼

文章標題形式

下面,咱們看看做者在起文章標題的時候,在標點符號方面有沒有什麼偏好。

能夠看到,五萬篇文章中,大多數文章的標題是陳述性標題。三分之一(34.8%) 的文章標題使用了問號「?」,而僅有 5% 的文章用了歎號「!」。一般,問號會讓人們產生好奇,從而想去點開文章;而歎號則會帶來一種緊張或者壓迫感,令人不太想去點開。因此,能夠嘗試多用問號而少用歎號。

4.7. 文本分析

最後,咱們從這 5 萬篇文章中的標題和摘要中,來看看虎嗅網的文章主要關注的都是哪些主題領域。

這裏首先運用了 jieba 分詞包對標題進行了分詞,而後用 WordCloud 作成了詞雲圖,因虎嗅網含有「虎」字,故選取了一張老虎頭像。(關於 jieba 和 WordCloud 兩個包,以後再詳細介紹)

能夠看到文章的主題內容側重於:互聯網、知名公司、電商、投資這些領域。這和網站自己對外宣傳的核心內容,即「關注互聯網與移動互聯網一系列明星公司的起落軌跡、產業潮汐的動力與趨勢,以及互聯網與移動互聯網如何改造傳統產業」大體相符合。

實現代碼以下:

def analysis6(data):
    text=''
    for i in data['title'].values:
        symbol_to_replace = '[!"#$%&\'()*+,-./:;<=>?@,。?★、…【】《》?「」‘’![\\]^_`{|}~]+'
        i = re.sub(symbol_to_replace,'',i)
        text+=' '.join(jieba.cut(i,cut_all=False))
    d = path.dirname(__file__) if "__file__" in locals() else os.getcwd()

    background_Image = np.array(Image.open(path.join(d, "tiger.png")))
    font_path = 'C:\Windows\Fonts\SourceHanSansCN-Regular.otf'  # 思源黑字體

    # 添加stopswords
    stopwords = set()
    # 先運行對text進行詞頻統計再排序,再選擇要增長的停用詞
    stopwords.update(['如何','怎麼','一個','什麼','爲何','仍是','咱們','爲什麼','可能','不是','沒有','哪些','成爲','能夠','背後','到底','就是','這麼','不要','怎樣','爲了','可否','大家','還有','這樣','這個','真的','那些'])
    wc = WordCloud(
        background_color = 'black',
        font_path = font_path,
        mask = background_Image,
        stopwords = stopwords,
        max_words = 2000,
        margin =2,
        max_font_size = 100,
        random_state = 42,
        scale = 2,
    )
    wc.generate_from_text(text)
    process_word = WordCloud.process_text(wc, text)
    # 下面是字典排序
    sort = sorted(process_word.items(),key=lambda e:e[1],reverse=True) # sort爲list
    print(sort[:50])  # 輸出前詞頻最高的前50個,而後篩選出不須要的stopwords,添加到前面的stopwords.update()方法中
    img_colors = ImageColorGenerator(background_Image)
    wc.recolor(color_func=img_colors)  # 顏色跟隨圖片顏色
    plt.imshow(wc,interpolation='bilinear')
    plt.axis('off')
    plt.tight_layout()  # 自動控制空白邊緣
    plt.savefig('huxiu20.png',dpi=200)
    plt.show()
複製代碼

上面的關鍵詞是這幾年整體的概況,而科技互聯網行業每一年的發展都是不一樣的,因此,咱們再來看看歷年的一些關鍵詞,透過這些關鍵詞看看這幾年互聯網行業、科技熱點、知名公司都有些什麼不一樣變化。

能夠看到每一年的關鍵詞都有一些相同之處,但也不一樣的地方:

  • 中國互聯網、公司、蘋果、騰訊、阿里等這些熱門關鍵詞一直都是熱門,這幾家公司真是穩地一批啊。
  • 每一年會有新熱點涌現:好比 2013 年的微信(剛開始火)、2016 年的直播(各大直播平臺如雨後春筍般出現)、2017年的 iPhone(上市十週年)、2018年的小米(上市)。
  • 不斷有新的熱門技術出現:2013 - 2015 年的 O2O、2016 年的 VR、2017 年的 AI 、2018 年的「區塊鏈」。這些科技前沿技術也是這幾年你們口耳相傳的熱門詞彙。

經過這一幅圖,就看出了這幾年科技互聯網行業、明星公司、熱點信息的風雲變化。

5. 小結

  • 本文簡要分析了虎嗅網 5 萬篇文章信息,大體瞭解了近些年科技互聯網的變幻無窮。
  • 發掘了那些優秀的文章和做者,可以節省寶貴的時間成本。
  • 一篇文章要想傳播普遍,文章自己的質量和標題各佔一半,文中的5 萬個標題相信可以帶來一些靈感。
  • 本文還沒有作深刻的文本挖掘,而文本挖掘可能比數據挖掘涵蓋的信息量更大,更有價值。進行這些分析須要機器學習和深度學習的知識,待後期學習後再來補充。

本文完。

文中的完整代碼和素材能夠在公衆號後臺回覆「虎嗅」 或者在下面的連接中獲取:

github.com/makcyun/eas…


推薦閱讀:

作 PPT 沒靈感?澎湃網 1500 期信息圖送給你

據說你想創業找投資?國內創業公司的信息都在這裏了

歡迎掃一掃識別關注個人公衆號
相關文章
相關標籤/搜索