基於Python命令列的NBA文字直播小工具
NBA季後賽正在進行中,無奈要上班,不能看視訊直播。而文字直播頁面又有太多廣告之類的東西,所以花半天時間,用Python 3搞一個基於命令列的文字直播,看著清爽,又不容易被領導發現。效果如圖所示:
圖1:程式啟動時,列出當前所有比賽
圖2:輸入比賽ID後,文字直播來了
找了一圈NBA文字直播網站,發現手機版直播吧有現成的介面,直接返回json格式資料。那就是它了,聽我慢慢道來。
首先在電腦瀏覽器開啟手機版直播吧,我用的是chrome瀏覽器,在Network中可以看到,它不停地用GET
方式請求http://bifen4m.qiumibao.com/json/list.htm
,這個地址會返回當前正在進行的所有型別比賽的基本情況,根據其中的type
ID
欄位,之後的所有操作都需要用到。返回的資料如下所示:
{
"code": "2760624",
"second": "10",
"list": [
{
"id": "96233",
"sdate": "2017-04-20",
"time": "10:30",
"url": "/zhibo/nba/2017/042096233.htm",
"type": "basketball",
"start ": "2017-04-20 10:30",
"home_team": "勇士",
"visit_team": "開拓者",
"home_score": "106",
"visit_score": "81",
"period_cn": "第4節\n01:30",
"from": "dc.live",
"code": "373",
"update": "13:13:37",
"big_score_1 ": "",
"big_score_2": ""
},
... # 省略了其它比賽的資訊
]
}
獲得所有正在進行的比賽ID
後,點選某一場比賽,進入文字直播頁面。首先請求http://dingshi4pc.qiumibao.com/livetext/data/cache/max_sid/XXXX/0.htm
頁面,其中XXXX
是上一步獲取的id
,它會返回一個數字,即max_sid
。然後判斷該max_sid
是否大於上次獲取的該值,如果大於,表示有新的直播文字,否則表示沒有。
如果max_sid
大於上一次的值,通過請求http://bifen4pc2.qiumibao.com/json/XXXX/YYYY.htm
(其中XXXX
是今天的日期,格式為2017-04-20
,YYYY
是第一步中獲取的id
),返回這場比賽的基本情況,比如比分,是第幾節等,如下所示:
{
"id": "96233",
"home_team": "勇士",
"visit_team": "開拓者",
"home_score": "110",
"visit_score": "81",
"period_cn": "第4節結束",
...
}
最後,就可以獲取直播的文字了。請求http://dingshi4pc.qiumibao.com/livetext/data/cache/livetext/XXXX/0/lit_page_2/YYYY.htm
(其中XXXX
是比賽id
,YYYY
是max_sid
),它會返回最新的直播文字,其中包括一條或多條直播文字,如下所示:
[
{
"live_id": "8769977",
"live_text": "@仙女最庫阿-:庫里正負值最高32我去!!!!",
"home_score": "110",
"visit_score": "81",
"pid_text": "比賽結束",
...
},
... # 可能有多條直播文字
]
可以看到,該請求返回的資訊中沒有比賽剩餘時間、主隊和客隊等資訊,所以每次獲取直播文字之前,需要多一次請求,獲得比賽的基本資訊。
基本流程就是這樣,非常簡單,一共就四個GET
請求,返回四串json,用requests
庫請求,然後解析搞定。
先定義一個Match
類,表示當前正在進行的每一場比賽。
# match.py
class Match:
def __init__(self, **kwargs):
self.id = kwargs['id']
self.home_team = kwargs['home_team']
self.visit_team = kwargs['visit_team']
self.home_score = kwargs['home_score']
self.visit_score = kwargs['visit_score']
self.period_cn = kwargs['period_cn'].replace('\n', ' ')
def __repr__(self):
return '{self.id} {self.home_team} {self.home_score} - {self.visit_score} {self.visit_team} {self.period_cn}'.format(self=self)
再定義一個TextLiving
類,表示獲取的每一條文字直播。
# text_living.py
class TextLiving:
def __init__(self, match_info, **kwargs):
self.home_team = match_info['home_team']
self.visit_team = match_info['visit_team']
self.period_cn = match_info['period_cn']
self.live_text = kwargs['live_text']
self.home_score = kwargs['home_score']
self.visit_score = kwargs['visit_score']
def __repr__(self):
return '{self.home_team} {self.home_score} - {self.visit_score} {self.visit_team} {self.period_cn}\n{self.live_text}\n{sep}'.format(self=self, sep='*'*60)
接著建立zhibo8_api.py
模組,用於獲取相關資料。
# 當前正在進行的比賽
Living_Matches_Url = 'http://bifen4m.qiumibao.com/json/list.htm'
# 某一場比賽當前的max_sid
Match_Max_Sid_Url = 'http://dingshi4pc.qiumibao.com/livetext/data/cache/max_sid/%s/0.htm'
# 某一場比賽最新文字直播
Match_Living_Text_Url = 'http://dingshi4pc.qiumibao.com/livetext/data/cache/livetext/%s/0/lit_page_2/%d.htm'
# 某一場比賽當前的基本情況
Match_Info_Url = 'http://bifen4pc2.qiumibao.com/json/%s/%s.htm'
def get_living_matches():
response = requests.get(Living_Matches_Url)
result = json.loads(response.text)
matches = [Match(**match) for match in result['list'] if match['type'] == 'basketball' and match['period_cn'] != '完賽']
return matches
def get_match_max_sid(match_id):
response = requests.get(Match_Max_Sid_Url % match_id)
if response.status_code == requests.codes.ok:
return int(response.text)
def get_match_living(match_id, max_sid):
# 先獲取比賽的當前情況,再獲取最新文字直播
match_info = get_match_info(match_id)
response = requests.get(Match_Living_Text_Url % (match_id, max_sid))
texts = []
if response.status_code == requests.codes.ok:
result = json.loads(response.text)
texts = [TextLiving(match_info, **living) for living in result]
return texts
def get_match_info(match_id):
today = datetime.now().strftime('%Y-%m-%d')
response = requests.get(Match_Info_Url % (today, match_id))
match_info = json.loads(response.text)
return match_info
最後,在main.py
模組中啟動程式,開始直播!
def get_living_matches():
matches = zhibo8_api.get_living_matches()
for match in matches:
print(match)
return matches
def get_watch_match(matches):
match_id = input('請輸入比賽ID:')
for match in matches:
if match.id == match_id:
return match
else:
print('輸入的ID不正確')
return None
def main_loop():
matches = get_living_matches()
if len(matches) == 0:
print('當前沒有比賽!!!')
return
match = get_watch_match(matches)
if not match:
print('沒去找到該比賽')
return
current_match_max_sid = -1
while True:
match_max_sid = zhibo8_api.get_match_max_sid(match.id)
if not match_max_sid:
print('沒有直播資料')
return
if current_match_max_sid == match_max_sid:
continue
current_match_max_sid = match_max_sid
text_livings = zhibo8_api.get_match_living(match.id, current_match_max_sid)
for text in text_livings:
print(text)
if __name__ == '__main__':
main_loop()
程式中基本沒做異常處理,還有很多需要改進的地方,歡迎大家指教。如果有朋友需要,我會把程式碼放在GitHub上。