前言
作為一個爐石傳說玩家,經常有事沒事開著直播網站看看大神們的精彩表演。不過因為各個平臺互相挖人的關係,導致關注的一些主播分散到了各個直播平臺,來回切換有點麻煩,所以萌生了做一個視訊聚合站的想法。
我主要去採集鬥魚、熊貓等的爐石區的主播資訊。雖然各個站點的人氣資訊有水分,但還是做了個簡單的排名。
上圖:
手機上的效果圖:
話不多說,上網站: http://lushiba.leanapp.cn/
專案部輸在了leancloud上,比較省心,但有一定的免費額度(如果顯示超出限制,需要晚一些來訪問,畢竟免費的,每天6個小時限制)
原始碼地址: https://github.com/ieiayaobb/… 歡迎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.o…
請求模擬
1 2 3 |
url = 'http://www.douyu.com/directory/game/How' session = requests.Session() response = session.get(url, verify=False) |
資料解析
解析部分主要有兩種:正則,BeautifulSoup
這裡為了通用,直接使用了正則來解析。
正則處理要求比較高,但是幾乎能應對所有的情況,屬於大殺器。
BeautifulSoup4的詳細介紹: https://www.crummy.com/softwa…
-
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/lea…
-
部署(用了lean cloud的引擎)
參考了lean cloud官方的專案骨架: https://github.com/leancloud/…
-
前端展示(pureCSS)
pureCss還是為了簡單,支援響應式,並且提供了基礎的UI元件
詳細介紹在這裡: https://purecss.io/
環境準備
Python的開發環境網上比較多,主要是virtualenv的準備,可以看廖老師的部落格瞭解具體資訊:
https://www.liaoxuefeng.com/w…
requirments.txt內容如下:
1 2 3 4 5 |
Django==1.9.7 requests==2.10.0 wheel==0.24.0 gunicorn leancloud-sdk>=1.0.9 |
分析與採集
視訊站內容解析
- 鬥魚爐石區
目標是採集爐石區所有主播的連結地址和人氣情況
#### 頁面內容(單個主播的資訊)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<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> |
衣錦夜行:狂野 登頂登頂
爐石傳說
衣錦夜行 8.1萬
我們需要採集的有幾部分內容:
- 直播間url (節點裡的href,/yechui)
- 直播間的標題(節點裡的title,衣錦夜行:狂野 登頂登頂)
- 直播間的截圖(節點裡的img標籤的src,https://rpic.douyucdn.cn/a170…)
- 直播間的人氣(8.1萬)(這裡有個注意的地方,鬥魚的人氣可能是X萬,需要把這個萬轉化成數值方便排序)
- 主播名稱(衣錦夜行)
頁面處理與採集
所有完整的直播站處理程式碼在fetch.py中
#### 命中主播資訊節點
1 |
re.finditer('<a class="play-list-link" .*?>([\s\S]*?)<\/a>', response.content.decode('utf8')): |
簡單的說明一下程式碼:
1 |
response.content.decode('utf8') |
- 主要是講requests請求的頁面以utf8編碼返回
- 正則部分就是命中上述的主播節點的內容,擷取整個a標籤
解析程式碼
採集href資訊(主播房間連結)
1 |
href = re.search('href=".*?"', group).group().lstrip('href="').rstrip('"') |
採集標題資訊
1 |
title = re.search('title=".*?"', group).group().lstrip('title="').rstrip('"') |
採集截圖資訊
1 |
img = re.search('data-original=".*?"', group).group().lstrip('data-original="').rstrip('"') |
採集主播名稱
1 |
name = re.search('<span class="dy-name ellipsis fl">.*?</span>', group).group().lstrip('<span class="dy-name ellipsis fl">').rstrip('</span>') |
採集人氣數量資訊
1 |
num = re.search('<span class="dy-num fr.*?</span>', group).group().lstrip('<span class="dy-num fr">').rstrip('</span>') |
處理‘萬’字
1 |
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迴圈來遍歷所有,先清空,再採集):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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檔案,內容如下
1 2 3 4 5 6 |
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部分程式碼:
1 2 3 4 5 6 7 8 9 10 11 |
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)) |
頁面部分程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{% 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…部署
這裡為了方便直接在頁面上進行配置
- 配置git庫
- 配置Deploy Key
- 設定域名
- 部署
- 配置定時任務
後言
整個專案比較簡單,目的是為了練手。如有疑問,歡迎在github上面發issue。