活学活用Python02:实时爬取NBA比赛分数,并显示在一个小窗口中

[TOC]

一、为什么要写这个小程序?

喜欢篮球,关注NBA的分数,但是又不想花时间精力一直盯着,为了偷懒,又想起Python了,这个家伙任劳任怨,就摆脱你帮我搞定吧

二、整体思路

要做的事情简单说来有两件:

  1. 爬取比赛的分数
  2. 把分数显示出来
  3. 要能够实时获取,不断更新显示

三、梳理细节

两件事都有一些细节,我整理一下:

1.爬取比赛分数

1.1 要知道直播间地址
1.2 爬取网页内容
1.3 筛选出我们要的比赛信息:主、客队名,比分,以及比赛进程

2.把分数显示出来

2.1 生成一个窗口显示文本信息
2.2 显示内容替换成为前面获取的比赛信息

3.实时更新

3.1 显示在一个窗口
3.2 追加显示文本
3.2 设置一个循环,设置间隔时间后追加显示新的信息

四、各个击破

在知道自己要做什么事情以后,就是动手去做,不会的就用百度搜索一下
我这里用到的关键词有:

  • wap 新浪 NBA直播
  • Python 爬虫 获取网页
  • 爬虫 筛选 标签
  • Python 悬浮窗 文本
  • tkinter 实时显示 文本 text
  • tkinter 获取输入

我觉得百度没有传说中的差,一般都可以满足我的要求,把搜出的前几个链接打开看看,就可以找到答案了。

具体过程如下
4.1 获取直播间地址

2017-4-26雷霆VS火箭的地址是
http://lives.sina.cn/live/live?livetype=nba&vt=4&match_id=2017042610

4.2 获取网页内容

用到了requests.get(url)

import requests
url = '''http://lives.sina.cn/live/live?livetype=nba&vt=4&match_id=2017042610'''
source_code = requests.get(url)
plain_text = source_code.text

这样就得到了网页的全部信息,是html的源码,这里截取了我们感兴趣的部分,用markdown显示出来如下:

<aside class="j_pk_aside">
    <div class="match_mode basketballbg">
        <div class="match_hometeam j_matchvote" data-url="/aj/live/vote?type=host" data-sudaclick="matchvote_host">
            <h3 class="team_homename">雷霆</h3>
            ![16/17赛季NBA季后赛 雷霆 86-74 火箭_直播间_手机新浪网](http://upload-images.jianshu.io/upload_images/5135746-ab81aa4815d199cf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
            <div class="vote_good team_homenum">13315</div>
            <!-- <em class="vote_animate hide">+1</em> -->
        </div>
        <div class="match_guestteam j_matchvote" data-url="/aj/live/vote?type=away" data-sudaclick="matchvote_away">
            <h3 class="team_guestname">火箭</h3>
            ![16/17赛季NBA季后赛 雷霆 86-74 火箭_直播间_手机新浪网](http://upload-images.jianshu.io/upload_images/5135746-338243810db702d5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
            <div class="vote_good team_guestnum">15020</div>
            <!-- <em class="vote_animate hide">+1</em> -->
        </div>
        <div class="match_mate" id="j_match_state" data-url="/aj/live/score?" data-sudaclick="matchscore">
            <p class="team_mate_status" id="j_online" data-url="/aj/live/online?">2135505人在线
</p>
            <div class="team_mate_score">
                <span class="fl">89</span>
                <span class="op4">:</span>
                <span class="fr">83</span>
            </div>
            
            <!-- nba football -->
            <p class="team_mate_intr">第3节 0:24</p>

        </div>
    </div>
    <dl class="match_mode_line" data-sudaclick="matchvoterate">
        <dt style="width:47%"></dt>
        <dd style="width:53%"></dd>
    </dl>
</aside>
4.3 筛选出我们要的比赛信息
4.3.1 在网页中找到感兴趣的信息

主队、客队的名字在这里

<h3 class="team_homename">雷霆</h3>
<h3 class="team_guestname">火箭</h3>

注意到了比分的标签关键词是:

<div class="team_mate_score">
    <span class="fl">89</span>
    <span class="op4">:</span>
    <span class="fr">83</span>
</div>

还有一个信息是时间:

<p class="team_mate_intr">第3节 0:24</p>

要找到这些内容有窍门的,能够迅速定位,就是利用chrome浏览器的审查功能。用chrome打开网页地址,在网页上找到你感兴趣的内容,用鼠标右键点击它,再点检查,如图:


这时在浏览器右侧直接弹出网页源码并定位到对应的位置上。

4.3.2 获取重要信息的路径

这时要获取该信息的标签路径就很容易了
直接在源码中右键点击你感兴趣的信息,点鼠标右键,Copy→Copy selector
就把路径复制下来了,用个记事本把它保存下来,再重复此过程把所有感兴趣的信息的网页标签路径都保存下来,留着下一步解析使用。
我们这里的路径如下:
主队分数:#j_match_state > div > span.fl
客队分数:#j_match_state > div > span.fr
主队名:body > aside.j_pk_aside > div > div.match_hometeam.j_matchvote > h3
客队名:body > aside.j_pk_aside > div > div.match_guestteam.j_matchvote > h3
比赛进程:#j_match_state > p.team_mate_intr

4.3.3 把重要信息转化成文本等待显示

通过百度查到了一个常用的工具BeautifulSoup

from bs4 import BeautifulSoup

source_code = requests.get(url)
plain_text = source_code.text
#用BeautifulSoup把刚刚获取的完整的网页信息整理成易用的格式,后面的参数目前不用管
soup = BeautifulSoup(plain_text, "html.parser")
#获取左右两个分数
score_lefts = soup.select('#j_match_state > div > span.fl')
score_rights = soup.select('#j_match_state > div > span.fr')
# 获取左右两个队名
name_lefts = soup.select('body > aside.j_pk_aside > div > div.match_hometeam.j_matchvote > h3')
name_rights = soup.select('body > aside.j_pk_aside > div > div.match_guestteam.j_matchvote > h3')
#获取比赛进程
game_processs = soup.select('#j_match_state > p.team_mate_intr')
#获取的信息是list,list里面还是一个BeautifulSoup的格式,提取文本使用get_text()
name_left = name_lefts[0].get_text()
name_right = name_rights[0].get_text()
score_left = score_lefts[0].get_text()
score_right = score_rights[0].get_text()
game_process= game_processs[0].get_text()

于是我们就得到了全部感兴趣的信息,保存在了五个字符串变量中,为了方便使用,把它们组合一下:

string_to_show = '【比分】\n'+name_left+':'+name_right+'\n'+score_left+':'+score_right+'\n【比赛进程】\n'+game_process+'\n--------\n\n'
4.4 生成一个窗口显示刚才的信息

这里参考了python Tkinter Text的简单用法
http://blog.csdn.net/cosmopolitanme/article/details/53495645

1.设置Python Tkinter Text控件文本的方法

text.insert(index,string) index = x.y的形式,x表示行,y表示列
向第一行最左侧插入数据,text.insert(1.0,'hello world')

以及

root = Tk()
# 生成显示结果的文本框
scoreboard = Text(root)
scoreboard.pack()
# 1.0是在第一行插入,如果要在最后插入就改成END
scoreboard.insert(1.0, string_to_show)

这时运行程序,已经能够显示出当前的分数了

4.5 实时显示最新的分数

本来想要使用一个while循环,考虑到有图形界面是容易出问题,没有用,而是使用了一个按钮,点一下这个按钮就刷新一条比赛信息

#生成按钮
goBtn = Button(text="刷新", command=onGo)
goBtn.pack()
root.mainloop()

然后给这个按钮添加功能,这里定义了onGo函数,这里面为了方便把之前获取比赛信息的代码封装到了getScore(url)函数里面了,给getScore一个直播间地址,就返回一条需要显示的信息。那么这个onGo函数响应刚添加的按钮,点一下,就执行一次,显示一条新的信息

def onGo():
    liveNum = var.get()
    liveUrl = '''http://lives.sina.cn/live/live?livetype=nba&vt=4&match_id=2017042610'''
    #计数器
    scoreboard.insert(1.0, getScore(liveUrl))
4.6 添加计数器

点一下显示一条太麻烦了,我就想要点一下显示10条,每一条间隔5秒钟,于是添加了计数器,倒数10个数,间隔设置为5000ms

def onGo():
    liveNum = var.get()
    liveUrl = '''http://lives.sina.cn/live/live?livetype=nba&vt=4&match_id=2017042610'''
    #计数器
    def counter(i):
        if i > 0:
            # 1.0是在第一行插入,如果要在最后插入就改成END
            scoreboard.insert(1.0, getScore(liveUrl))
            #延迟5000毫秒运行
            scoreboard.after(5000, counter, i - 1)
        else:
            goBtn.config(state=NORMAL)

    goBtn.config(state=DISABLED)
    #运行10次
    counter(10)

效果还不错,已经可以实时更新了

4.7 添加输入框,用来接收直播间号码

考虑到每天看不同的直播都要修改程序不太好,就把直播地址中的直播间号采用输入的形式接收吧
这就要添加一个输入框,并且稍微修改一下onGo()函数,点击按钮以后,把输入框中的房间号追加到直播地址中,生成最终的网页地址。
onGo()中添加:

    liveNum = var.get()
    liveUrl = '''http://lives.sina.cn/live/live?livetype=nba&vt=4&match_id=''' + liveNum

主出程序中添加

#生成输入框
var=StringVar()
Entry(root,textvariable=var).pack()

这时就可以自己粘贴直播间号码喽。看一下效果:


至此,我们的小程序就完成了。这次感谢芒果TV吧,O(∩_∩)O哈哈~

完整代码

from tkinter import *
import requests,urllib.request
from bs4 import BeautifulSoup

def getScore(url):
    source_code = requests.get(url)
    plain_text = source_code.text
    soup = BeautifulSoup(plain_text, "html.parser")
    #获取左右两个比分
    score_lefts = soup.select('#j_match_state > div > span.fl')
    score_rights = soup.select('#j_match_state > div > span.fr')
    # 获取左右两个队名
    name_lefts = soup.select('body > aside.j_pk_aside > div > div.match_hometeam.j_matchvote > h3')
    name_rights = soup.select('body > aside.j_pk_aside > div > div.match_guestteam.j_matchvote > h3')
    #获取比赛进程
    game_processs = soup.select('#j_match_state > p.team_mate_intr')
    #将获取的信息(是list)提取文本
    name_left = name_lefts[0].get_text()
    name_right = name_rights[0].get_text()
    score_left = score_lefts[0].get_text()
    score_right = score_rights[0].get_text()
    game_process= game_processs[0].get_text()
    #生成要输出的字符信息
    string_to_show = '【比分】\n'+name_left+':'+name_right+'\n'+score_left+':'+score_right+'\n【比赛进程】\n'+game_process+'\n--------\n\n'
    return string_to_show

#定义相应按钮的函数
def onGo():
    liveNum = var.get()
    liveUrl = '''http://lives.sina.cn/live/live?livetype=nba&vt=4&match_id=''' + liveNum
    #计数器
    def counter(i):
        if i > 0:
            # 1.0是在第一行插入,如果要在最后插入就改成END
            scoreboard.insert(1.0, getScore(liveUrl))
            #延迟10000毫秒运行
            scoreboard.after(10000, counter, i - 1)
        else:
            goBtn.config(state=NORMAL)

    goBtn.config(state=DISABLED)
    #运行10次
    counter(10)

root = Tk()
# 生成显示结果的文本框
scoreboard = Text(root)
scoreboard.pack()
#生成输入框
var=StringVar()
Entry(root,textvariable=var).pack()
#生成按钮
goBtn = Button(text="请在上面的小输入框中输入直播间号码后点击本按钮获取最新比赛分数!", command=onGo)
goBtn.pack()
root.mainloop()

小结

requests.get(网页地址)取网页源代码
BeautifulSoup(网页源代码)解析网页信息
用chrome检查获取重要信息的网页标签路径
soup.select('标签路径')得到对应的信息
get_text()转化成文本
tkinter的Text组件显示文本
tkinter的Button组件添加按钮
tkinter的Entry组件输入文本
自定义一个counter(i)函数当计数器

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容