2022年馬上要結束了,最近突然有個想法,利用微信小程式+部落格園介面做了一個「部落格園年度總結」,統計下自己寫部落格這些年的資料情況,最終效果如下
在開始之前先捋一捋思路,大致要實現以下幾個功能:
1、使用flask提供後端服務,呼叫部落格園介面獲取資料,然後作進一步處理,給微信小程式提供介面;
2、在小程式中通過上劃/下划來切換頁面;
3、在小程式中展示資料圖表(接入echarts);
4、在最後一頁能夠通過點選按鈕進行回看和分享;
本章來寫一下後端處理邏輯
本次需要呼叫部落格園如下介面來獲取相關資料:
1、獲取當前登入使用者資訊,介面檔案:https://api.cnblogs.com/help
這個介面返回你的「部落格名」、「園齡」、「粉絲數」等,如下
{
"UserId": "xxx",
"SpaceUserID": xxx,
"BlogId": xxx,
"DisplayName": "我是冰霜",
"Face": "https://pic.cnblogs.com/face/1158674/20201224122945.png",
"Avatar": "https://pic.cnblogs.com/avatar/1158674/20201224122945.png",
"Seniority": "5年5個月",
"BlogApp": "hanmk",
"FollowingCount": 16,
"FollowerCount": 532
}
2、獲取個人部落格資訊,介面檔案:https://api.cnblogs.com/help
這個介面主要返回你的「部落格數量」、「部落格簽名」等
{
"blogId": xxx,
"title": "我是冰霜",
"subtitle": "I am just a sunflower, waiting for my only sunshine.",
"postCount": 245,
"pageSize": 10,
"enableScript": true
}
3、獲取個人部落格隨筆列表,介面檔案:https://api.cnblogs.com/help
這個介面返回你的部落格隨筆列表
[
{
"Id": 1,
"Title": "sample string 2",
"Url": "sample string 3",
"Description": "sample string 4",
"Author": "sample string 5",
"BlogApp": "sample string 6",
"Avatar": "sample string 7",
"PostDate": "2017-06-25T20:15:30.2514989+08:00",
"ViewCount": 9,
"CommentCount": 10,
"DiggCount": 11
},
{
"Id": 1,
"Title": "sample string 2",
"Url": "sample string 3",
"Description": "sample string 4",
"Author": "sample string 5",
"BlogApp": "sample string 6",
"Avatar": "sample string 7",
"PostDate": "2017-06-25T20:15:30.2514989+08:00",
"ViewCount": 9,
"CommentCount": 10,
"DiggCount": 11
}
]
前2個介面比較簡單,資料拿來後可以直接返給前端去用,但是最後一個「獲取隨筆列表」介面,從部落格園拿到資料後還需要加工一下,達到如下目的
1、獲取當前登入使用者資訊
def get_users(self):
"""獲取當前登入使用者資訊介面"""
url = "https://api.cnblogs.com/api/users"
try:
res = requests.get(url=url, headers=self.headers)
data = res.json()
# print(res.request.headers)
# print(data)
return data
except Exception as e:
raise e
2、獲取個人部落格資訊
def get_blog_info(self, blog_name):
"""獲取個人部落格資訊介面"""
url = "https://api.cnblogs.com/api/blogs/" + blog_name
try:
res = requests.get(url=url, headers=self.headers)
data = res.json()
# print(data)
return data
except Exception as e:
raise e
3、獲取個人部落格隨筆列表
def deal_blogs(blogs):
"""處理從部落格園獲取到的隨筆資料"""
new_data = None
if blogs:
new_data = {
"Title": blogs["Title"], # 標題
"PostDate": blogs["PostDate"].split("T")[0], # 釋出時間(擷取日期部分,如2022-09-07)
"ViewCount": blogs["ViewCount"], # 瀏覽次數
"CommentCount": blogs["CommentCount"], # 評論次數
"DiggCount": blogs["DiggCount"] # 點選次數
}
return new_data
def get_blogs_api(self, blog_name):
"""獲取個人隨筆列表介面"""
flag = True
try:
blogs = []
i = 1
while flag is True:
url = "https://api.cnblogs.com/api/blogs/{}/posts?pageIndex={}".format(blog_name, i)
res = requests.get(url=url, headers=self.headers)
data = res.json()
# print(data)
# print(i)
if data:
blogs += data
i += 1
else:
# print(data)
flag = False
# print(len(blogs))
# print(blogs)
# print("123")
new_blogs = list(map(self.deal_blogs, blogs))
# [{'Title': 'xx', 'PostDate': 'xx-xx-xx', 'ViewCount': xx, 'CommentCount': 0, 'DiggCount': 0}, {}, {}]
# print(new_blogs)
first_blog = new_blogs[-1] # 釋出的第一篇部落格
# {'Title': 'xx', 'PostDate': 'xx-xx-xx', 'ViewCount': xx, 'CommentCount': 0, 'DiggCount': 0}
# print(first_blog)
sort_blogs = sorted(new_blogs, key=lambda item: item["ViewCount"], reverse=True) # 按照ViewCount排序,降序
print(sort_blogs)
view_max_10 = sort_blogs[0:10] # 瀏覽量前10的文章
# print(view_max_10)
"""提取2022年的月度資料並處理"""
blog_date1 = [i["PostDate"][0:7] for i in new_blogs] # 提取每條資料的年月,組成一個列表
# print(blog_date1)
temp = Counter(blog_date1)
month_blog_date = dict(temp)
# print(month_blog_date)
months = ["2022-01", "2022-02", "2022-03", "2022-04", "2022-05", "2022-06",
"2022-07", "2022-08", "2022-09", "2022-10", "2022-11", "2022-12"]
month_result = [] # 2022年每月部落格新增數量
for j in months: # 遍歷日期範圍列表
if j in month_blog_date:
# 如果一個日期在bug列表中,說明這個日期有值,取bug字典中該日期的值賦給bug_num,同時date取當前日期,組合為一個字典
month_result.append({"date": j, "value": month_blog_date[j]})
else:
# 否則這個日期對應的value=0
month_result.append({"date": j, "value": 0})
# print(month_result)
now_year_blog_sum = sum([i["value"] for i in month_result]) # 2022年新增部落格總數
# print(now_year_blog_sum)
"""提取年度資料並處理"""
blog_date2 = [i["PostDate"][0:4] for i in new_blogs] # 提取每條資料的年,組成一個列表
year_blog_date = dict(Counter(blog_date2))
# print(year_blog_date)
begin_year = first_blog["PostDate"][0:4]
# print(begin_year)
end_year = get_now_year()
# print(end_year)
# print(type(begin_year), type(end_year))
date_gap = int(end_year) - int(begin_year) + 1
years = []
for i in range(date_gap):
years.append(str(int(begin_year) + i))
# print(years)
year_result = [] # 每年部落格新增數量
for j in years: # 遍歷日期範圍列表
if j in year_blog_date:
# 如果一個日期在bug列表中,說明這個日期有值,取bug字典中該日期的值賦給bug_num,同時date取當前日期,組合為一個字典
year_result.append({"date": j, "value": year_blog_date[j]})
else:
# 否則這個日期對應的value=0
year_result.append({"date": j, "value": 0})
# print(year_result)
res = {
"first_blog": first_blog, # 釋出的第一篇部落格
"view_max_10": view_max_10, # 瀏覽量前10的文章
"now_year_blog_sum": now_year_blog_sum, # 2022年新增部落格總數
"month_result": month_result, # 2022年每月部落格新增數量
"year_result": year_result # 每年部落格新增數量
}
print(res)
return res
except Exception as e:
raise e
程式碼說明:
1、deal_blogs()
函數
我打算使用python的map函數來處理原始資料,所以這裡先定義一個資料處理常式,
從部落格園介面獲取到的資料格式如下,一個列表包含多個字典
[
{
"Id": 1,
"Title": "sample string 2",
"Url": "sample string 3",
"Description": "sample string 4",
"Author": "sample string 5",
"BlogApp": "sample string 6",
"Avatar": "sample string 7",
"PostDate": "2017-06-25T20:15:30.2514989+08:00",
"ViewCount": 9,
"CommentCount": 10,
"DiggCount": 11
},
...
...
...
]
每個字典中有很多欄位,我只想提取其中一些必要的欄位,只保留Title
、PostDate
、ViewCount
等欄位
def deal_blogs(blogs):
"""處理從部落格園獲取到的隨筆資料"""
new_data = None
if blogs:
new_data = {
"Title": blogs["Title"], # 標題
"PostDate": blogs["PostDate"].split("T")[0], # 釋出時間(擷取日期部分,如2022-09-07)
"ViewCount": blogs["ViewCount"], # 瀏覽次數
"CommentCount": blogs["CommentCount"], # 評論次數
"DiggCount": blogs["DiggCount"] # 點選次數
}
return new_data
2、get_blogs_api()
函數
為了方便,我把資料處理過程都寫到這個函數中了,然後統一返回出去
(1)迴圈分頁呼叫獲取隨筆列表介面
在呼叫部落格園隨筆列表介面時,需要傳入pageIndex
因為我們並不知道一共有多少頁資料,所以這裡我使用了while
迴圈,當介面返回空時說明到了最後一頁
... ...
... ...
flag = True
try:
blogs = []
i = 1
while flag is True:
url = "https://api.cnblogs.com/api/blogs/{}/posts?pageIndex={}".format(blog_name, i)
res = requests.get(url=url, headers=self.headers)
data = res.json()
# print(data)
# print(i)
if data:
# 如果介面有返回資料,就把資料追加到blogs中,同時頁碼+1
blogs += data
i += 1
else:
# 如果介面返回空,說明當前傳入的頁碼已經沒有沒有資料了,結束迴圈
# print(data)
flag = False
new_blogs = list(map(self.deal_blogs, blogs)) # 呼叫map函數處理部落格原始資料
... ...
... ...
(2)提取釋出的的第一篇部落格
因為部落格園隨筆列表介面返回的資料預設是按照倒序排列的,所以最後一條就是釋出的第一篇部落格
first_blog = new_blogs[-1] # 釋出的第一篇部落格
(3)獲取瀏覽量為前10的部落格
需要對資料按照「瀏覽量」進行排序,然後取前10條即可
可以通過sorted()
函數來實現
sort_blogs = sorted(new_blogs, key=lambda item: item["ViewCount"], reverse=True) # 按照ViewCount排序,降序
print(sort_blogs)
view_max_10 = sort_blogs[0:10] # 瀏覽量前10的文章
列印結果
[{'Title': '如何檢視linux伺服器記憶體使用情況', 'PostDate': '2019-03-19', 'ViewCount': 200087, 'CommentCount': 4, 'DiggCount': 0}, {'Title': 'python+selenium基礎之XPATH定位(第一篇)', 'PostDate': '2018-05-06', 'ViewCount': 109768, 'CommentCount': 9, 'DiggCount': 0}, {'Title': 'oracle匯入dmp檔案的2種方法', 'PostDate': '2017-07-26', 'ViewCount': 102784, 'CommentCount': 1, 'DiggCount': 0}, {'Title': 'python爬蟲學習(一):BeautifulSoup庫基礎及一般元素提取方法', 'PostDate': '2018-04-05', 'ViewCount': 100563, 'CommentCount': 9, 'DiggCount': 0}, {'Title': 'python讀取組態檔&&簡單封裝', 'PostDate': '2018-10-24', 'ViewCount': 87415, 'CommentCount': 0, 'DiggCount': 0}, {'Title': 'oracle匯出dmp檔案的2種方法', 'PostDate': '2017-07-26', 'ViewCount': 75031, 'CommentCount': 0, 'DiggCount': 0}, {'Title': '利用拷貝data目錄檔案的方式遷移mysql資料庫', 'PostDate': '2017-12-05', 'ViewCount': 64000, 'CommentCount': 3, 'DiggCount': 0}, {'Title': 'linux下檢視程序id時用到的命令', 'PostDate': '2019-03-18', 'ViewCount': 63239, 'CommentCount': 0, 'DiggCount': 0}, {'Title': '在python中使用正規表示式(一)', 'PostDate': '2018-06-06', 'ViewCount': 58195, 'CommentCount': 2, 'DiggCount': 0}, {'Title': 'postman(十一):新增cookie', 'PostDate': '2019-04-29', 'ViewCount': 54866, 'CommentCount': 0, 'DiggCount': 0}, {'Title': '使用Dockerfile建立一個tomcat映象,並執行一個簡單war包', 'PostDate': '2018-03-10', 'ViewCount': 39556, 'CommentCount': 2, 'DiggCount': 0}, {'Title': 'postman(六):詳解在Pre-request Script中如何執行請求', 'PostDate': '2018-12-30', 'ViewCount': 37908, 'CommentCount': 11, 'DiggCount': 0}, {'Title': '如何在jenkins上新建一個專案及其簡單設定', 'PostDate': '2017-05-04', 'ViewCount': 28941, 'CommentCount': 0, 'DiggCount': 0}, {'Title': 'python紀錄檔模組的使用', 'PostDate': '2019-02-28', 'ViewCount': 28605, 'CommentCount': 1, 'DiggCount': 0}, {'Title': 'nginx反向代理範例', 'PostDate': '2018-07-10', 'ViewCount': 27529, 'CommentCount': 1, 'DiggCount': 0}, {'Title': 'SQL查詢--索引', 'PostDate': '2019-08-31', 'ViewCount': 26935, 'CommentCount': 0, 'DiggCount': 0}, {'Title': 'postman(二):使用postman傳送get or post請求', 'PostDate': '2018-12-20', 'ViewCount': 24487, 'CommentCount': 0, 'DiggCount': 0}, {'Title': 'python基礎:刪除列表中特定元素的幾種方法', 'PostDate': '2020-10-11', 'ViewCount': 23846, 'CommentCount': 0, 'DiggCount': 0}, {'Title': '使用pymysql運算元據庫', 'PostDate': '2018-06-22', 'ViewCount': 23806, 'CommentCount': 0, 'DiggCount': 0}, {'Title': 'python之做一個簡易的翻譯器(一)', 'PostDate': '2019-04-14', 'ViewCount': 17938, 'CommentCount': 1, 'DiggCount': 0}, {'Title': 'python爬蟲學習(三):使用re庫爬取"淘寶商品",並把結果寫進txt檔案', 'PostDate': '2018-04-08', 'ViewCount': 17260, 'CommentCount': 2, 'DiggCount': 0}, {'Title': '在不安裝oracle使用者端的情況下,使用PLSQL', 'PostDate': '2018-11-27', 'ViewCount': 15983, 'CommentCount': 2, 'DiggCount': 0}, {'Title': '使用「rz -be」命令上傳檔案至伺服器;使用「sz 檔名」從伺服器下載檔案到本地', 'PostDate': '2018-07-02', 'ViewCount': 15654, 'CommentCount': 0, 'DiggCount': 0}, {'Title': 'python多執行緒:控制執行緒數量', 'PostDate': '2020-05-30', 'ViewCount': 15577, 'CommentCount': 0, 'DiggCount': 0}, {'Title': '理解css相鄰兄弟選擇器', 'PostDate': '2018-05-19', 'ViewCount': 15303, 'CommentCount': 3, 'DiggCount': 0},... ...]
(4)本次我要做2張柱狀圖圖表:2022年月度新增隨筆趨勢、2017~2022年度新增隨筆趨勢
因為之前有提取jira資料做質量看板的經驗,這次處理起來就駕輕就熟了(傳送門:基於jira資料開發一個質量看板)
下面是月度資料和年度資料的處理邏輯
"""提取2022年的月度資料並處理"""
blog_date1 = [i["PostDate"][0:7] for i in new_blogs] # 提取每條資料的年月,組成一個列表
# print(blog_date1)
temp = Counter(blog_date1)
month_blog_date = dict(temp)
# print(month_blog_date)
months = ["2022-01", "2022-02", "2022-03", "2022-04", "2022-05", "2022-06",
"2022-07", "2022-08", "2022-09", "2022-10", "2022-11", "2022-12"]
month_result = [] # 2022年每月部落格新增數量
for j in months: # 遍歷日期範圍列表
if j in month_blog_date:
# 如果一個日期在bug列表中,說明這個日期有值,取bug字典中該日期的值賦給bug_num,同時date取當前日期,組合為一個字典
month_result.append({"date": j, "value": month_blog_date[j]})
else:
# 否則這個日期對應的value=0
month_result.append({"date": j, "value": 0})
# print(month_result)
now_year_blog_sum = sum([i["value"] for i in month_result]) # 2022年新增部落格總數
"""提取年度資料並處理"""
blog_date2 = [i["PostDate"][0:4] for i in new_blogs] # 提取每條資料的年,組成一個列表
year_blog_date = dict(Counter(blog_date2))
# print(year_blog_date)
begin_year = first_blog["PostDate"][0:4] # 取釋出的第一篇部落格所在的年份,因為這就是部落格起始年份
# print(begin_year)
end_year = get_now_year() # 取當年年份為結束年份
# print(end_year)
# print(type(begin_year), type(end_year))
date_gap = int(end_year) - int(begin_year) + 1 # 計算年份差
years = [] # 定義年份範圍
for i in range(date_gap):
years.append(str(int(begin_year) + i))
# print(years)
year_result = [] # 每年部落格新增數量
for j in years: # 遍歷年份範圍列表
if j in year_blog_date:
# 如果一個日期在bug列表中,說明這個日期有值,取bug字典中該日期的值賦給bug_num,同時date取當前日期,組合為一個字典
year_result.append({"date": j, "value": year_blog_date[j]})
else:
# 否則這個日期對應的value=0
year_result.append({"date": j, "value": 0})
# print(year_result)
最後把這些資料放到一個字典中返回出去即可
res = {
"first_blog": first_blog, # 釋出的第一篇部落格
"view_max_10": view_max_10, # 瀏覽量前10的文章
"now_year_blog_sum": now_year_blog_sum, # 2022年新增部落格總數
"month_result": month_result, # 2022年每月部落格新增數量
"year_result": year_result # 每年部落格新增數量
}