美文网首页python
活学活用Python02:实时爬取NBA比赛分数,并显示在一个小

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

作者: 三思而后学 | 来源:发表于2017-04-27 17:53 被阅读590次

    [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:https://img.haomeiwen.com/i5135746/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:https://img.haomeiwen.com/i5135746/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)函数当计数器

    相关文章

      网友评论

        本文标题:活学活用Python02:实时爬取NBA比赛分数,并显示在一个小

        本文链接:https://www.haomeiwen.com/subject/garnzttx.html