Python 动态网页抓取之提取视频源

最近遇到一个需求:根据优酷ios客户端分享来的链接,提取出视频源,并在ios系统播放器播放。在踩了一些坑之后,笔者对视频网站的提取也有了一些经验,在此做个总结,为以后遇到这个问题的同学提供一些经验和方向。

1. 简介

提取网站视频链接分三种情况:

  1. 电脑版网页链接,在查看这类网页源代码时会发现视频源为flash文件,无法获取有效的视频地址,需要使用第三方库You-Get
  2. 遗憾的是You-Get并非支持所有的视频网站,对于不能支持的视频网站,需要设置User-Agent模拟iPhone用户进行提取,或者破解其加密方式
  3. iPhone Safair中的视频源,这个是本文的重点

2. 使用You-Get抓取视频地址

You-Get 实际上是一个视频下载器,用 Python3 编写,运行在命令行环境而不是GUI。它支持很多视频网站,具体可以看Github项目的介绍,并且持续更新中。

安装You-Get

You-Get 运行在 Python3 环境下,不支持Python2.x。所以在开始之前,系统中至少有一个Python3.x版本。

虽然项目介绍中说明可以直接编译源码安装,但是如果没有特殊要求,使用 pip 是最简单的安装方式。
pip 的安装可以查看这篇文章pip installation

使用pip安装You-get

$ [sudo] pip3 install you-get	

检查是否安装成功

$ you-get -V

使用You-Get下载视频

$ you-get http://youtu.be/sGwy8DsUJ4M

显示视频信息

$ you-get -u http://youtu.be/sGwy8DsUJ4M

使用you-get -u $link返回视频信息,然后用正则表达式将视频链接提取出来即可。

一些问题

  1. ios系统播放器只支持mp4和mov等少数几种视频格式。但是在下载的视频中很多是flv格式,无法在系统播放器中播放。
  2. 手机中分享来的视频网址无法使用You-Get提取视频。
  3. You-Get并非支持所有视频网站。

3. 提取手机Safari的视频链接

虽然ios系统不支持flv等视频格式,但是优酷等网站在safari中仍可以播放。所以笔者猜测在手机端视频并非以falsh文件方式播放。通过设置如下 User-Agent 模拟手机浏览器访问视频网站,在源代码中可以得到视频链接。

Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B410 Safari/600.1.4

视频链接 http://v.youku.com/v_show/id_XMTMzMzkxNzgwOA==_ev_1.html?x

image

以及网页源代码

image

图中src就是我们需要的内容。

知道了源码中含有视频链接就好办多了,只要我们获取到源码,然后利用正则表达式提取出视频链接即可。但是,尝试后发现,视频标签部分是动态获取的,破解js比较麻烦,而且并不通用,所以这里采用一种简单粗暴的方案:

在服务器端运行一个虚拟窗口,通过调用浏览器加载网页,并对最终代码做正则提取出视频地址。

运行环境

CentOs系统,使用python3.4版本,1M带宽,FireFox浏览器

使用Splinter调用浏览器

Splinter是一款Python自动化测试工具,可以模拟浏览器的行为。可以运行js,支持鼠标操作等。

安装稳定版

$ [sudo] pip install splinter

或者源码安装

$ git clone git://github.com/cobrateam/splinter.git
$ cd splinter
$ [sudo] python setup.py install

代码示例

browser = Browser()
browser.visit(url)
html = browser.html

browser.quit()

运行虚拟桌面

centos服务器是没有桌面的。为了能在服务器中调用浏览器进行渲染,笔者在centos命令行界面运行一个虚拟的桌面。Xvfb新建一个虚拟的X窗口,配合python的pyvirtualdisplay进行操作。

安装

# 安装Xvfb和pyvirtualdisplay
yum install xorg-x11-server-Xvfb
pip install pyvirtualdisplay

安装firefoxselenium

yum install firefox
pip install selenium

代码

from pyvirtualdisplay import Display
from selenium import webdriver

display = Display(visible=0, size=(800, 600))
display.start()

browser = webdriver.Firefox()
browser.get('http://www.baidu.com')
print browser.title
browser.quit()

display.stop()

Talk is cheap, Show me the fucking code


from splinter import Browser
from selenium.webdriver import PhantomJS, DesiredCapabilities
from splinter.driver.webdriver import (BaseWebDriver, WebDriverElement as BaseWebDriverElement)

from pyvirtualdisplay import Display
from selenium import webdriver

import re
import json


def fetch_info(url):
html = download_html(url)
videoUrl = parse_html(url, html)

resultDic = {'ret' : 0, 'srcUrl' : url, 'title' : url, 'abstract' : url, 'qsvideo' : videoUrl}
print(json.dumps(resultDic))

pass

def download_html(url):
display = Display(visible=0, size=(800, 600))
display.start()

browser = Browser(user_agent="Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B410 Safari/600.1.4")
browser.visit(url)
html = browser.html

browser.quit()
display.stop()
return html
pass

def parse_html(url, html):
matchObj = re.search(r'<div class="tvp_video"><video(.*)src="(.*)"></video>', html)
if matchObj:
videoUrl = matchObj.group(2)
return videoUrl

return ""
pass

if __name__ == '__main__':
url = "http://v.youku.com/v_show/id_XMTMyOTU4NTc4OA==.html"
fetch_info(url)

4. 第二种情况

对于第二种情况,You-Get不能支持的视频网站,需要设置User-Agent伪装为iPhone用户进行提取,或者破解其加密方式。

5. 小结

总的来说,这是一种可行的抓取方案。但是,因为需要浏览器启动加载网页,对于条件比较苛刻的环境中效率相对较低。就笔者而言,在1M的带宽中抓取一个视频链接需要几十秒的时间,这几乎是不能忍受的。因此如何在低带宽中提高速度仍需要挖掘。目前猜测耗时可能是因为加载网页时下载图片导致,具体原因还需要详细调查验证。

参考资料

you-get github
pip
Splinter
linux无界面(headless)使用selenium抓取数据