目錄
- 一、主頁面設計
- 1.1 Tkinter基本介紹
- 1.2 設計布局
- 二、查詢功能實作
- 2.1 磁區字典構建
- 2.2 輸入日期處理
- 2.3 書寫爬蟲函式
- 三、全部代碼
- 思考與優化
之前,我們系統地介紹了兩種爬取B站熱門視頻的方法,今天,就來分享一下如何組合Tkinter實作一鍵即可查詢B站各區最火視頻,首先,來看看最終的效果圖吧:

一、主頁面設計
1.1 Tkinter基本介紹
Tkinter是一款Python自帶的GUI可視化界面庫,對于新手來說還是易于上手的,本文使用的基本控制元件主要有Label、Entry、Text、Button、Cavas,其基本作用如下表所示:
| 控制元件 | 描述 |
|---|---|
| Label (標簽) | 用于顯示文本和位圖 |
| Entry (輸入) | 用于顯示簡單的文本內容 |
| Button(按鈕) | 在程式中顯示按鈕 |
| Text(文本) | 用于顯示多行文本 |
| Cavas(畫布) | 顯示圖形元素如線潭訓文本 |
從之前的爬蟲API介面爬取B站熱門視頻資訊可知,用戶想要查詢B站熱門視頻資訊,需要提前確定兩個引數:磁區ID和查詢熱門視頻時間范圍,因此,我們設計的主要想法為:將磁區名稱和日期設定為兩個Entry控制元件,便于接受用戶所輸入的資訊,然后通過Button控制元件組合這兩個資訊交給相應的爬蟲函式,最終由爬蟲函式獲取到的視頻資訊再交給Text控制元件呈現,
1.2 設計布局
首先,我們先來設計整個頁面布局,各個控制元件基本使用方法詳細可參照菜鳥教程Tkinter入門,在此不再詳細說明,該部分的代碼如下
import tkinter as tk
from PIL import Image, ImageTk
def get_image(file_name, width, height): #讀取圖片
im = Image.open(file_name).resize((width, height))
return ImageTk.PhotoImage(im)
window = tk.Tk(className='bilibili熱門視頻查詢') #創建視窗,并對其命名
window.geometry('700x450') # 視窗大小設定
# 背景畫布設定,讀取桌面的2233娘的照片
canvas = tk.Canvas(window, width=700, height=450)
img = get_image('C:/Users/dell/Desktop/2233.jpg', 700, 450)
canvas.create_image(350, 225, image=img)
canvas.pack()
# 標簽
L1 = tk.Label(window, bg='Beige', text='日期:', font=('華文行楷', 15))
L2 = tk.Label(window, bg='Beige', text='磁區:', font=('華文行楷', 15))
L1.place(x=250, y=80)
L2.place(x=250, y=120)
# 輸入文本
E1 = tk.Entry(window, font=("華文行楷", 15), show=None, width=18)
E2 = tk.Entry(window, font=("華文行楷", 15), show=None, width=18)
E1.place(x=350, y=80)
E2.place(x=350, y=120)
# 顯示多行文本
t = tk.Text(window, width=25, height=6, font=("微軟雅黑", 15), selectforeground='red')
t.place(x=225, y=280)
# 查詢按鈕
button = tk.Button(window, bg='SkyBlue', text="查詢", font=('華文行楷', 15), width=15, height=2
)
button.place(x=300, y=180)
window.mainloop()
最終得到的頁面圖如下:

此時的查詢只是一個空的按鈕,無法通過用戶輸入的日期與磁區名稱進行查詢的,因此,我們要寫一個爬蟲函式,整合輸入的資訊,傳入Button控制元件中的command引數來賦予其查詢功能,
二、查詢功能實作
在這篇博客API介面爬取B站熱門視頻資訊中,我們知道實作B站熱門視頻資訊爬蟲主要依賴于以下四個重要引數:card_id(磁區ID)、page(爬取頁數)、time_from(最早視頻發布時間)、time_to(最晚視頻發布時間),由于本次實作GUI可視化只需要播放量最高的視頻資訊,故引數page不用考慮,設定為1即可,只需關注card_id和time_from、time_to即可,
2.1 磁區字典構建
首先,我們需要將用戶輸入的磁區名稱與各磁區的ID一一對應,因此我們需要先構建一個磁區字典,由于B站每個大磁區下還有若干子區(例如:生活區下有搞笑區、日常區等8個子區),這里僅以各磁區第一個子區代表該磁區,(例如,以搞笑區代表生活區)
最終,構建的字典如下
tagid_dict = {
'影片區': 24,
'音樂區': 28,
'舞蹈區': 20,
'知識區': 201,
'生活區': 138,
'時尚區': 157,
'娛樂區': 71,
'游戲區': 17,
'數碼區': 95,
'鬼畜區': 22,
'影視區': 182
}
2.2 輸入日期處理
考慮到不同用戶輸入習慣的差異,本文設計了兩種輸入日期的格式,用于查詢當月最熱視頻資訊,形如2021年2月和2021-2
time_from和time_to引數的基本形式為20210204,其中time_to引數不能出現日期溢位現象,例如:查詢2020年2月時time_to不可以為20200231,查詢2021年2月時time_to不可以為202102014(以今天2021年2月4日為準)
基于此,我們將得到以下判斷日期邏輯:

該部分代碼如下
from datetime import datetime
def get_full_date(year, month): # 回傳除2月外起始日期樣式,類似20200504
month_31 = [1, 3, 5, 7, 8, 10, 12]
time_from = year + '%02d' % int(month) + '01'
if int(month) in month_31:
time_to = year + '%02d' % int(month) + '31'
else:
time_to = year + '%02d' % int(month) + '30'
return time_from, time_to
def time_from_to(year, month):
now_year = datetime.now().year
now_month = datetime.now().month
now_day = datetime.now().day
if (int(month) == now_month) & (int(year) == now_year): # 判斷是否為今年本月,若是time_to最大只能為當前日期
time_from = str(now_year) + '%02d' % now_month + \
'01' # 十位數以下數字以0補全可用%02d
time_to = str(now_year)+'%02d' % now_month + '%02d' % now_day
else:
if int(year) % 4 == 0: #判斷是否閏年
if int(month) == 2: #判斷是否為二月,若輸入2020年,則time_from和time_to為20200201、20200229
time_from = year + '0201'
time_to = year + '0229'
else:
time_from, time_to = get_full_date(year, month) #非二月份時間處理
else:
if int(month) == 2: #非閏年,對二月單獨處理
time_from = year + '0201'
time_to = year + '0228'
else:
time_from, time_to = get_full_date(year, month) #非二月份時間處理
return time_from, time_to
2.3 書寫爬蟲函式
經過以上兩部分的處理,我們再寫爬蟲函式就很簡單啦,只需要將該兩部分的資訊,傳給相應位置的引數即可,基本代碼如下:
import re
import requests
import json
def crawl_hot_video():
tagid_dict = {
'影片區': 24,
'音樂區': 28,
'舞蹈區': 20,
'知識區': 201,
'生活區': 138,
'時尚區': 157,
'娛樂區': 71,
'游戲區': 17,
'數碼區': 95,
'鬼畜區': 22,
'影視區': 182
}
date = E1.get() #獲取用戶輸入的日期
tag_name = E2.get() #獲取用戶輸入的磁區名稱
tag_id = tagid_dict[tag_name] #將磁區名稱轉為ID
if '-' in date:
year = date.split('-')[0]
month = date.split('-')[1]
time_from, time_to = time_from_to(year, month)
else:
year = re.findall('\d+', date)[0]
month = re.findall('\d+', date)[1]
time_from, time_to = time_from_to(year, month)
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.0; rv:2.0) Gecko/20100101 Firefox/4.0 Opera 12.14',
'refer': 'https://www.bilibili.com/'
}
url = 'https://s.search.bilibili.com/cate/search?'
params = {
'main_ver': 'v3',
'search_type': 'video',
'view_type': 'hot_rank',
'order': 'click',
'copy_right': -1,
'cate_id': tag_id, #傳入ID
'page': 1,
'pagesize': 20,
'jsonp': 'jsonp',
'time_from': time_from, #傳入查詢視頻初始時間
'time_to': time_to #傳入查詢視頻結束時間
}
try:
r = requests.get(url, headers=headers, params=params)
data = json.loads(r.text)
inf_list = data['result']
author = data['result'][0]['author']
title = data['result'][0]['title']
pubdate = data['result'][0]['pubdate']
play = str(int(data['result'][0]['play'])/10000)+'萬'
df = [author, title, pubdate, play]
column = ['UP主: ', '標題名: ', '發布時間: ', '播放量: ']
data1 = [i + j for i, j in zip(column, df)]
content = '\n'.join(data1)
t.insert('insert', ' 查詢結果如下 \n')
t.insert('insert', content)
except Exception as result:
print(result)
三、全部代碼
組合Tkinter部分及爬蟲部分,最終代碼如下:
import tkinter as tk
from datetime import datetime
import re
import requests
import json
from PIL import Image, ImageTk
def get_full_date(year, month): # 回傳除2月外起始日期樣式,類似20200504
month_31 = [1, 3, 5, 7, 8, 10, 12]
time_from = year + '%02d' % int(month) + '01'
if int(month) in month_31:
time_to = year + '%02d' % int(month) + '31'
else:
time_to = year + '%02d' % int(month) + '30'
return time_from, time_to
def time_from_to(year, month): #考慮年份因素,回傳日期樣式
now_year = datetime.now().year
now_month = datetime.now().month
now_day = datetime.now().day
if (int(month) == now_month) & (int(year) == now_year): # 判斷是否為今年本月,若是time_to最大只能為當前日期
time_from = str(now_year) + '%02d' % now_month + \
'01' # 十位數以下數字以0補全可用%02d
time_to = str(now_year)+'%02d' % now_month + '%02d' % now_day
else:
if int(year) % 4 == 0: #判斷是否閏年
if int(month) == 2: #判斷是否為二月,若輸入2020年,則time_from和time_to為20200201、20200229
time_from = year + '0201'
time_to = year + '0229'
else:
time_from, time_to = get_full_date(year, month) #非二月份時間處理
else:
if int(month) == 2: #非閏年,對二月單獨處理
time_from = year + '0201'
time_to = year + '0228'
else:
time_from, time_to = get_full_date(year, month) #非二月份時間處理
return time_from, time_to
def crawl_hot_video():
tagid_dict = {
'影片區': 24,
'音樂區': 28,
'舞蹈區': 20,
'知識區': 201,
'生活區': 138,
'時尚區': 157,
'娛樂區': 71,
'游戲區': 17,
'數碼區': 95,
'鬼畜區': 22,
'影視區': 182
}
date = E1.get()
tag_name = E2.get()
tag_id = tagid_dict[tag_name]
if '-' in date:
year = date.split('-')[0]
month = date.split('-')[1]
time_from, time_to = time_from_to(year, month)
else:
year = re.findall('\d+', date)[0]
month = re.findall('\d+', date)[1]
time_from, time_to = time_from_to(year, month)
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.0; rv:2.0) Gecko/20100101 Firefox/4.0 Opera 12.14',
'refer': 'https://www.bilibili.com/'
}
url = 'https://s.search.bilibili.com/cate/search?'
params = {
'main_ver': 'v3',
'search_type': 'video',
'view_type': 'hot_rank',
'order': 'click',
'copy_right': -1,
'cate_id': tag_id,
'page': 1,
'pagesize': 20,
'jsonp': 'jsonp',
'time_from': time_from,
'time_to': time_to
}
try:
r = requests.get(url, headers=headers, params=params)
data = json.loads(r.text)
inf_list = data['result']
author = data['result'][0]['author']
title = data['result'][0]['title']
pubdate = data['result'][0]['pubdate']
play = str(int(data['result'][0]['play'])/10000)+'萬'
df = [author, title, pubdate, play]
column = ['UP主: ', '標題名: ', '發布時間: ', '播放量: ']
data1 = [i + j for i, j in zip(column, df)]
content = '\n'.join(data1)
t.insert('insert', ' 查詢結果如下 \n')
t.insert('insert', content)
except Exception as result:
print(result)
def get_image(file_name, width, height):
im = Image.open(file_name).resize((width, height))
return ImageTk.PhotoImage(im)
window = tk.Tk(className='bilibili熱門視頻查詢')
window.geometry('700x450') # 視窗大小設定
# 背景畫布設定
canvas = tk.Canvas(window, width=700, height=450)
img = get_image('C:/Users/dell/Desktop/2233.jpg', 700, 450)
canvas.create_image(350, 225, image=img)
canvas.pack()
# 標簽
L1 = tk.Label(window, bg='Beige', text='日期:', font=('華文行楷', 15))
L2 = tk.Label(window, bg='Beige', text='磁區:', font=('華文行楷', 15))
L1.place(x=250, y=80)
L2.place(x=250, y=120)
# 輸入文本
E1 = tk.Entry(window, font=("華文行楷", 15), show=None, width=18)
E2 = tk.Entry(window, font=("華文行楷", 15), show=None, width=18)
E1.place(x=350, y=80)
E2.place(x=350, y=120)
t = tk.Text(window, width=25, height=6, font=(
"微軟雅黑", 15), selectforeground='red') # 顯示多行文本
t.place(x=225, y=280)
# 查詢按鈕
button = tk.Button(window, bg='SkyBlue', text="查詢", font=('華文行楷', 15), width=15, height=2,
command=crawl_hot_video)
button.place(x=300, y=180)
window.mainloop()
思考與優化
1、本次爬取的視頻其實是按照播放量的高低進行降序排列的(URL中對應的引數為search_type),后續在Tkinter中設定個下拉選單,然后根據評論數、彈幕數、點贊數等欄位進行排序,然后爬取,
2、每次點擊查詢按鈕后,應該可以設定一個清空上次查詢的內容的功能,有時間再來優化,
以上就是本次分享的全部內容~
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/256805.html
標籤:python
上一篇:Python基礎(第七章)
下一篇:Python 學生資訊管理系統
