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

2017-07-22 18:20:17 +08:00
 ieiayaobb

炉石吧

前言

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

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

上图: 手机上的效果图:

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

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

基础介绍

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

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

功能说明

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

技术选型

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

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/

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

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

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

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>

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

页面处理与采集

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

命中主播信息节点

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

简单的说明一下代码:

response.content.decode('utf8')

解析代码

采集 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

接口设计

/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#部署 这里为了方便直接在页面上进行配置

后言

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

5778 次点击
所在节点    Python
3 条回复
nazor
2017-07-22 19:56:06 +08:00
我以为你把斗鱼 flash 的协议分析了,原来是这个。
expy
2017-07-22 20:02:15 +08:00
F12 找出视频链接,然后拿 Livestreamer 喂给播放器。链接一般几天才变一次。好处是没广告、资源占用低,坏处是看不见聊天、估计也不会给主播提供收入。
wanglaihuai
2017-07-25 02:00:28 +08:00
大佬厉害了,一时半会儿还消化不了…

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/377239

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX