V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
ieiayaobb
V2EX  ›  Python

一步一步教你如何搭建自己的视频聚合站

  •  
  •   ieiayaobb ·
    ieiayaobb · 2017-07-22 18:20:17 +08:00 · 5953 次点击
    这是一个创建于 2686 天前的主题,其中的信息可能已经有所发展或是发生改变。

    炉石吧

    前言

    作为一个炉石传说玩家,经常有事没事开着直播网站看看大神们的精彩表演。不过因为各个平台互相挖人的关系,导致关注的一些主播分散到了各个直播平台,来回切换有点麻烦,所以萌生了做一个视频聚合站的想法。

    我主要去采集斗鱼、熊猫等的炉石区的主播信息。虽然各个站点的人气信息有水分,但还是做了个简单的排名。

    上图: 手机上的效果图:

    话不多说,上网站: http://lushi8.leanapp.cn/

    项目部输在了 leancloud 上,比较省心,但有一定的免费额度(如果显示超出限制,需要晚一些来访问,毕竟免费的,每天 6 个小时限制) 源码地址: https://github.com/ieiayaobb/lushi8, 欢迎 Star

    • master 分支是 redis 方式存储实现
    • lean 分支是基于 lean cloud 的实现

    基础介绍

    聚合站的思路就是采集目标站点的相关信息,通过数据处理将想要的信息做提取,整理入库,然后通过 web 展示。因为直播平台数据实时在变,所以考虑将存储的数据放在缓存中( redis ),因为部署在了 lean cloud 上,所以示例就直接存储在了 lean cloud 的存储上。

    为了方便讲解,我们以斗鱼为目标采集的网站,介绍解析和存储部分的内容,其他网站的处理大同小异。

    功能说明

    整体项目就分为数据采集解析、数据存储、web 展现三大功能。后续我们会对这三个部分的功能做逐一展开说明。

    技术选型

    • 语言( Python )

    轻量级的项目,直接就是用了 Python 来做,Python 在爬虫、web 方面都有着不错的库支持,而且 lean cloud 也支持 Python 部署,所以毫不犹豫的就采用了 Python 来做

    • 数据采集( requests )

    requests 的特点就是轻量,且简单易用。虽然这是个爬虫项目,但实在规模太小,所以没必要上 scrapy 了 requests 的介绍地址: http://docs.python-requests.org/zh_CN/latest/index.html

    请求模拟

    url = 'http://www.douyu.com/directory/game/How'
    session = requests.Session()
    response = session.get(url, verify=False)
    

    数据解析

    解析部分主要有两种:正则,BeautifulSoup 这里为了通用,直接使用了正则来解析。 正则处理要求比较高,但是几乎能应对所有的情况,属于大杀器。 BeautifulSoup4 的详细介绍: https://www.crummy.com/software/BeautifulSoup/bs4/doc/

    • web 框架( Django )

    Django 是 Python 比较重量级的框架,Django 自带了 orm 的框架,可惜这个项目中用不到。但是我们会使用 Django 的模板引擎,Django 的模板引擎也是很方便的一个特性。Django 还提供了 django-rest-framework,方便开发 RESTful 的接口,这个项目后续做了个配搭的 React Native 的 mobile 应用,所以引入了 django-rest-framework。 详细介绍在此: https://www.djangoproject.com/

    • 存储( lean cloud 的数据存储)

    既然用了 lean cloud,存储就直接用了 lean 提供的存储功能。 详细的介绍在这里: https://leancloud.cn/docs/leanstorage_guide-python.html

    • 部署(用了 lean cloud 的引擎)

    参考了 lean cloud 官方的项目骨架: https://github.com/leancloud/django-getting-started

    • 前端展示( pureCSS )

    pureCss 还是为了简单,支持响应式,并且提供了基础的 UI 组件 详细介绍在这里: https://purecss.io/

    环境准备

    Python 的开发环境网上比较多,主要是 virtualenv 的准备,可以看廖老师的博客了解具体信息: https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432712108300322c61f256c74803b43bfd65c6f8d0d0000 requirments.txt 内容如下:

    Django==1.9.7
    requests==2.10.0
    wheel==0.24.0
    gunicorn
    leancloud-sdk>=1.0.9
    

    分析与采集

    视频站内容解析

    • 斗鱼炉石区 目标是采集炉石区所有主播的链接地址和人气情况

    页面内容(单个主播的信息)

    <a class="play-list-link" data-rid='48699' data-tid='2' data-sid='167' data-rpos="0" data-sub_rt="0" href="/yechui" title="衣锦夜行:狂野 登顶登顶"
      target="_blank">
      <span class="imgbox">
          <span class="imgbox-corner-mark"></span>
          <b></b>
          <i class="black"></i>
          ![]( http://upload-images.jianshu.io/upload_images/2485846-20d3cbfd6e33df69.gif?imageMogr2/auto-orient/strip)
      </span>
      <div class="mes">
          <div class="mes-tit">
              <h3 class="ellipsis">衣锦夜行:狂野 登顶登顶</h3>
              <span class="tag ellipsis">炉石传说</span>
          </div>
          <p>
              <span class="dy-name ellipsis fl">衣锦夜行</span>
              <span class="dy-num fr"  >8.1 万</span>
          </p>
      </div>
    </a>
    

    我们需要采集的有几部分内容:

    • 直播间 url (节点里的 href,/yechui )
    • 直播间的标题(节点里的 title,衣锦夜行:狂野 登顶登顶)
    • 直播间的截图(节点里的 img 标签的 src,https://rpic.douyucdn.cn/a1707/22/16/48699_170722164951.jp
    • 直播间的人气( 8.1 万)(这里有个注意的地方,斗鱼的人气可能是 X 万,需要把这个万转化成数值方便排序)
    • 主播名称(衣锦夜行)

    页面处理与采集

    所有完整的直播站处理代码在 fetch.py

    命中主播信息节点

    re.finditer('<a class="play-list-link" .*?>([\s\S]*?)<\/a>', response.content.decode('utf8')):
    

    简单的说明一下代码:

    response.content.decode('utf8')
    
    • 主要是讲 requests 请求的页面以 utf8 编码返回
    • 正则部分就是命中上述的主播节点的内容,截取整个 a 标签

    解析代码

    采集 href 信息(主播房间链接)

    href = re.search('href=".*?"', group).group().lstrip('href="').rstrip('"')
    

    采集标题信息

    title = re.search('title=".*?"', group).group().lstrip('title="').rstrip('"')
    

    采集截图信息

    img = re.search('data-original=".*?"', group).group().lstrip('data-original="').rstrip('"')
    

    采集主播名称

    name = re.search('<span class="dy-name ellipsis fl">.*?</span>', group).group().lstrip('<span class="dy-name ellipsis fl">').rstrip('</span>')
    

    采集人气数量信息

    num = re.search('<span class="dy-num fr.*?</span>', group).group().lstrip('<span class="dy-num fr">').rstrip('</span>')
    

    处理‘万’字

    int(round(float(num.replace('万', '').replace('\r', '').replace('\n', '')) * 10000))
    

    存储与刷新

    采集到的信息需要存储到 lean cloud 的存储中,会调用 lean cloud 所提供的 API

    字段设计

    Chairman

    • id 直播间的唯一 id
    • name 直播间主播名称
    • title 直播间的标题
    • href 直播间的页面地址
    • num 直播间的人气
    • img 直播间的截图

    接口设计

    /fetch

    Fetch 的接口包含了清空、采集、解析、存储所有的更新逻辑,设计这个接口的目的主要是方便后面使用云函数进行定时调用,以更新数据,调用逻辑如下( lean cloud 不支持全部遍历,所以用了 while 循环来遍历所有,先清空,再采集):

    leancloud.init(LEAN_CLOUD_ID, LEAN_CLOUD_SECRET)
    query = leancloud.Query('Chairman')
    allDataCompleted = False
    batch = 0
    limit = 1000
    while not allDataCompleted:
        query.limit(limit)
        query.skip(batch * limit)
        query.add_ascending('createdAt')
        resultList = query.find()
        if len(resultList) < limit:
            allDataCompleted = True
            leancloud.Object.destroy_all(resultList)
        batch += 1
    
    fetcher = Fetcher()
    fetcher.fetch_douyu()
    

    /chairmans ( redis 版本才支持)

    Django-rest-framework 提供,可以通过分页的方式展现当前库中的信息

    /chairman/{id}( redis 版本才支持)

    Django-rest-framework 提供,可以根据指定 id 获取某一个主播的信息

    刷新机制

    lean cloud 提供了一种云函数的概念,并且可以像配置 cron 一样,定期的去触发某一个请求,为了能够定期的更新排行榜,我们会通过配置这个云函数,实现定期的数据刷新 云函数是一个 cloud.py 文件,内容如下

    engine = Engine(get_wsgi_application())
    
    @engine.define
    def fetch(**params):
        leancloud.init(LEAN_CLOUD_ID, LEAN_CLOUD_SECRET)
        # fetch 逻辑
    

    在 lean cloud 中配置定时执行

    页面展示

    页面部分比较简单,以一个列表的形式,展现了主播的排行榜信息,点击某一个主播,直接跳转到对应直播网站的目标直播间。因为考虑到在手机上的显示,所以做了自适应

    列表页

    列表页的渲染使用了 Django 的模板引擎 由于 lean cloud 的存储和 Django 的 orm 不一样,所以这里需要将 attributes 放到列表中,页面上才能用模板语法进行访问 view 部分代码:

    def get_index(request):
        leancloud.init(LEAN_CLOUD_ID, LEAN_CLOUD_SECRET)
    
        query = leancloud.Query('Chairman')
        chairmans = []
    
        for chairman in query.add_descending('num').find():
            chairmans.append(chairman.attributes)
    
        return render_to_response('index.html', locals(),
                                  context_instance=RequestContext(request))
    

    页面部分代码:

    {% for chairman in chairmans %}
        <a href="{{ chairman.href }}" class="chairman-wrapper">
            <div class="pure-g chairman">
                <div class="pure-u-1-5">
                    ![]({{ chairman.img }})
                </div>
                <div class="pure-u-2-5">
                    <div class="name">{{ chairman.name }}</div>
                    <div class="title">{{ chairman.title }}</div>
                </div>
                <div class="pure-u-1-5">
                    <span class="type {{ chairman.type }}"></span>
                </div>
                <div class="pure-u-1-5">
                    <div class="num">{{ chairman.num }}人</div>
                </div>
            </div>
        </a>
    {% endfor %}
    

    项目部署

    因为部署在了 lean cloud 上,可以直接使用提供的 lean-cli 进行部署, lean-cli 的详细介绍在这里: https://www.leancloud.cn/docs/leanengine_cli.html#部署 这里为了方便直接在页面上进行配置

    • 配置 git 库

    • 配置 Deploy Key

    • 设置域名

    • 部署

    • 配置定时任务

    后言

    整个项目比较简单,目的是为了练手。如有疑问,欢迎在 github 上面发 issue。

    第 1 条附言  ·  2017-07-23 12:06:02 +08:00
    3 条回复    2017-07-25 02:00:28 +08:00
    nazor
        1
    nazor  
       2017-07-22 19:56:06 +08:00
    我以为你把斗鱼 flash 的协议分析了,原来是这个。
    expy
        2
    expy  
       2017-07-22 20:02:15 +08:00
    F12 找出视频链接,然后拿 Livestreamer 喂给播放器。链接一般几天才变一次。好处是没广告、资源占用低,坏处是看不见聊天、估计也不会给主播提供收入。
    wanglaihuai
        3
    wanglaihuai  
       2017-07-25 02:00:28 +08:00 via Android
    大佬厉害了,一时半会儿还消化不了…
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5433 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 07:44 · PVG 15:44 · LAX 23:44 · JFK 02:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.