接觸博客園有不短的時間了,今天突然想到,我們博客園各位博友,一天中哪個時間段比較活躍?又有多少夜貓子在深更半夜,冒着“聰明絕頂”的風險熬夜碼字看博文?首頁所有博文中,哪個博友發布博文數量最多?又是哪個博友大范圍“收割”閱讀量和評論量?我們的各類排行榜中,誰能獨占鰲頭?
今天,博主就現學現賣,用剛學完基礎知識的 python 爬取下博客園相關數據,給大家分享下咱們博客園那些隱藏的“小秘密”。
方案
想法出現了,怎么實現呢?
第一反應就是想獲取各位博友的登錄信息和訪問記錄。這些數據應該是最准確的統計了。
但是,不幸的是,博主把博客園翻了個“底朝天”,也沒有找到哪些地方能獲取到各位博友的登錄信息和訪問記錄。
想想也是,這些相當於各位博友的私密信息了,怎么會公開呢?咱就不痴心妄想了。
爬不到登錄信息和訪問記錄,還能用哪些數據呢?
博主想了下,咱們在博客園逛游,一般都會先去首頁看下有沒有什么有趣的技術或者人生經驗分享,碰到感興趣的還可以和博主聊聊,緩解下緊綳的神經。
那既然首頁是多人訪問的頁面,我們統計首頁博文的瀏覽量和評論量,應該也能在一定程度上反映出各位博友的活躍時間了。
於是,統計方案就定下來了:
獲取首頁博文的瀏覽量和評論量,按時段進行統計。
實現
目標:
獲取首頁博文的瀏覽量和評論量
爬取數據
這還不簡單,哪怕博主我是剛學完基礎知識,也知道 python 在爬取 html 元素方面是專業的。
一番折騰,終於按小時分段,獲取到了第一頁博文的瀏覽量和評論量:
import requests
import re
import json
import time
CRAWLING_URL = 'https://www.cnblogs.com/'
def downloadPage():
"""獲取頁面內容"""
print('獲取頁面內容用時')
url = CRAWLING_URL
res = requests.get(url).text
html = BeautifulSoup(res, 'lxml')
data = {}
postList = html.find_all(class_='post_item_foot')
for postInfo in postList:
content = postInfo.contents
# 發布時間字符串
timeStr = content[2][11:27]
localTime = time.localtime(time.mktime(
time.strptime(timeStr, '%Y-%m-%d %H:%M')))
# 以2018-11-01 15 格式時間 作為 key
timeIndex = time.strftime("%Y-%m-%d %H", localTime)
viewStr = content[4].contents[0].contents[0]
commontStr = content[3].contents[0].contents[0]
# 瀏覽量
view = int(re.findall("\d+", viewStr)[0])
# 評論量
commont = int(re.findall("\d+", commontStr)[0])
if timeIndex in data:
data[timeIndex]['view'] += view
data[timeIndex]['commont'] += commont
data[timeIndex]['postCount'] += 1
else:
data[timeIndex] = {
'view': view,
'commont': commont,
'postCount': 1
}
return data
第一頁拿到了,離所有數據還遠嗎?
事實證明,真的挺遠的、、、
當博主想拿第二頁的數據時,很明顯的可以看到第二頁的地址是:
於是博主這樣做了
# ...
CRAWLING_URL = 'https://www.cnblogs.com/#p'
def crawlData(page, data):
url = CRAWLING_URL + str(page)
# ...
def main():
pageNum = 11
data = {}
for page in range(1, pageNum):
data = crawlData(page, data)
page += 1
print(data)
看出來了嗎?博主是直接將地址欄里的地址拼接上頁碼,想獲取到對應頁碼的數據。
事實證明,還是太嫩了。運行了好幾次,發現統計數據明顯不對,獲取到的第二頁的數據明顯不是瀏覽器顯示的。
翻到第二頁,看着頁面元素,和第一頁的一樣啊,怎么爬到的數據就不對呢?
作為一個后端開發,馬上就意識到,在后面的頁碼頁,肯定有額外的 ajax 請求,獲取對應數據,展示到頁面。
翻到 network,果不其然。在非第一頁的頁面中,都會請求一個接口,獲取指定頁碼的數據。原因找到了,趕緊修改請求地址和請求方式。
# ...
CRAWLING_URL = 'https://www.cnblogs.com/mvc/AggSite/PostList.aspx'
def crawlData(page, data):
"""獲取頁面內容"""
url = CRAWLING_URL
headers = {
'Content-Type': 'application/json',
}
params = json.dumps({
'CategoryId': 808,
'CategoryType': "SiteHome",
'ItemListActionName': "PostList",
'PageIndex': page,
'ParentCategoryId': 0,
'TotalPostCount': 4000,
})
res = requests.post(url, data=params, headers=headers, verify=False).text
# ...
至此,首頁博文的總瀏覽量、評論量以及發布數量已經按小時為區段進行匯總了。
存儲數據
數據拿到了,下一步就是數據存儲了。這里,我們選用最簡單的 excel 表格存儲,也就是將統計的數據導出到 excel 表格中,以供后續分析統計。
def main():
pageNum = 11
data = {}
# 獲取所有數據
for page in range(1, pageNum):
data = crawlData(page, data)
print('已完成: %s/%s' % (page, pageNum - 1))
page += 1
# excel 表格存儲
col = 2
ws1['A1'] = '日期'
ws1['B1'] = '查看人數'
ws1['C1'] = '評論人數'
ws1['D1'] = '發布數量'
for postCount in data:
col_A = 'A%s' % col
col_B = 'B%s' % col
col_C = 'C%s' % col
col_D = 'D%s' % col
col_E = 'E%s' % col
col_F = 'F%s' % col
ws1[col_A] = postCount
ws1[col_B] = data[postCount]['view']
ws1[col_C] = data[postCount]['commont']
ws1[col_D] = data[postCount]['postCount']
col += 1
wb.save(filename=dest_filename)
print('-------------SUCCESS--------------')
這樣,我們就將數據存儲到 excel 表格中了。
分析數據
下一步就是數據分析。由於個人能力所限,這里先用 excel 表格進行相關的統計。
由於博客園只提供 200 頁的數據量,最后的數據到 8 月 20 日左右,所以 9 月份和 10 月份的數據是比較完整的。但是考慮到 10 月份有十一假期的原因,以及當前時間距離十月份較近,所以最終取 9 月份的數據進行相關統計。
周數據
上圖是 8.25-9.30 連續 5 周的數據統計,0 表示 周日。由圖可以比較明顯的看出一些趨勢:
- 每周的前四天是博文發布數量較高的,后三天發布數量明顯減少;
- 查看人數和評論人數的趨勢較為相符,兩者的比例在 208:1 左右,也就是說平均 208 個閱讀里面才會 1 個評論。
這里博主比較不解的是,為什么會在每周一有一個閱讀高峰期?難道剛休息完,周一的時候會更有動力看博文補補課?
天統計
上圖是 9.3 - 9.6 按小時分段統計數據。可以看出:
- 博文發布一般集中在上午 8-10 點,下午的 16-18 點以及晚上的 20-22 點
看來各位博友晚上即使不加班的也會努力碼字啊,抓住下班后的兩小時,很棒的習慣誒,博主也要更加努力向各位博友看齊了。
最后,就是我們的重磅戲,各類排行榜。這里需要將時間分組修改為發布作者名稱分組。
各類排行榜
以上排行榜數據時間段: 2018-08-21 09:24 至 2018-11-07 09:27 。
好了,園子的小秘密就分享到這里。有興趣的博友可以發掘下其他的小秘密。注意不要惡意攻擊噢!