如何获取和展示视频网站内容的截图

互联网视频网站已经成为大家娱乐不可缺少的一部分,博客、微博、SNS都在大量的转发视频链接,如何在用户粘贴的视频网站链接后面增加对应视频的截图显示呢?这里提供我的解决思路和片段PHP代码。

1、如何在文本中获得URL?
获得诸如“http://www.xxx.com/.....”的URL地址,这个可以使用正则式来解决,执行后$urls就是输入$text字符串中找到的全部URL组成的一维数组:
[quote] preg_match_all("/(http:\/\/[a-z0-9:;&#@=_~%\?\/\.\,\+\-]+)/i", $text, $matches);
$urls = $matches[0];[/quote]

2、如何还原短链接?
在转发中,很多链接都被转换成了短链接,例如视频地址http://www.tudou.com/programs/view/K2xBz5JFBdY/在在转发中被转换成了短地址http://t.cn/hghgjz,一般主要是为了微博节省文字的长度。常见的方法是调用对应短地址的API,还原得到长地址,但是各个短地址提供的方法不一样。短地址实际就是在访问过程中,使用了HTTP 301跳转(Permanently Moved),会在返回的HTTP头中带上真实的地址,使得浏览器可以跳转,这样的话,我们就可以模拟浏览器获得原始地址即可。

片段代码如下,其中$s_url是短地址,$l_url是还原的原始长地址:
[quote]$SHORT_URL = array (
"t.cn",
"url.cn",
"tinyurl.com",
"goo.gl",
......
);

//检查是否是短地址
$found = false;
foreach ($SHORT_URL as $v)
{
$pattern = "/{$v}/i";
if (preg_match($pattern, $s_url, $ret) == 1)
{
$found = true;
break;
}
}

if (!$found)
{
//不是短地址,直接返回
$l_url = $s_url;
}
else
{

//模拟HTTP访问,还原短地址
$u = parse_url($s_url);
$host_ip = gethostbyname($u["host"]);
$host_port = 80;

$request_header = "";
$request_header .= "GET {$u['path']} HTTP/1.1\r\n";
$request_header .= "Host:{$u['host']}\r\n";
$request_header .= "User-Agent: Mozilla/5.0\r\n";
$request_header .= "Accept: */*\r\n";
$request_header .= "Cache-Control: no-cache\r\n";
$request_header .= "Connection: Close\r\n";
$request_header .= "\r\n";
$request_header .= "\r\n";

$fh = fsockopen($host_ip, $host_port);
fputs($fh, $request_header);
$response = "";
while(!feof($fh))
{
$response .= fread($fh, 1);
}
fclose($fh);

if (preg_match("/Location:(.*?)\r\n/i", $response, $ret) != 0)
{
$l_url = rtrim(ltrim($ret[1]));
}

}[/quote]

3、如何获取原始视频链接对应视频的截图?
常见的视频网站在视频播放页面的源码中都会有对应截图的URL地址,我们只需要打开视频地址,分析源码获取即可,这个就没有统一的方法来实现,例如土豆tudou的视频播放页面源码中看到类似“,thumbnail = 'http://i3.tdimg.com/080/946/236/p.jpg'”的这样一行,这个就是视频对应的截图地址。

片段代码如下,其中$url是视频网站地址,$img_url是对应截图URL地址:
[quote]//构建各个视频网站的截图地址分析正则式,这个需要根据不同网站的情况设定
$VIDEO_SITE = array (
"youku.com" => "/\+0800\|(.*?)\|\">/i",
"ku6.com" => "/<span class=\"s_pic\">(.*?)<\/span>/i",
"tudou.com" => "/thumbnail = '(.*?)'/i",
"56.com" => "/\"img\":\"(.*?)\"/i",
"video.sina.com.cn" => "/pic: '(.*?)'/i",
......
);

//检查是否是视频网站地址
$pattern_img = "";
foreach ($VIDEO_SITE as $k => $v)
{
$pattern_site = "/{$k}/i";
if (preg_match($pattern_site, $url, $ret) == 1)
{
$pattern_img = $v;
break;
}
}

//获得网页源码,分析截图URL
$content = file_get_contents($url);
preg_match($pattern_img, $content, $ret);
$img_url = $ret[1];[/quote]


最后,由于我们需要连接获取的数据的短地址和视频网站可能访问速度不快,如果有大量重复的URL要处理(例如“我的微博”,展现的是最新20条,所以在一定时间内反复访问的也就是这20条中的URL),所以可以考虑自己做本地缓存,我是采用将短地址和长地址、视频地址和截图地址的对应关系作为二维数组保存,然后serialize保存到缓冲文件,同时考虑了缓冲过期(我设定为7天)删除的刷法,以免累计的旧数据太多,这里就不详细写了。

OK,打完,收工~~~!

增加“我的微博”

微博大道而行,我也得跟上:

1、顶部栏目新增“我的微博”,自动采集最新20条,来源有我的新浪微博和腾讯微博,抓取的缓冲时间为300秒;腾讯微博抓取偶尔有“check sign error”错误,略不稳定,不知是腾讯接口问题,还是偶对oauth_signature的算法实现有问题,待观察
2、左侧栏目增加微博入口


鉴于微博口水较多,暂不加入RSS输出,酱紫~~~

写这个页面的时候,粗略看了“腾讯微博开放平台”和“新浪微博开放平台”API文档中OAuth和timeline的一些描述、范例和接口说明,前者的文档需要努力呀,大小写错误、描述不清晰等问题较多。

---------------以下 2011年5月5日补充------------------
“腾讯微博抓取偶尔有“check sign error”错误”,这个问题找到了,是由于生成的oauth_signature拼装到url的时候,没有做urlencode,当其中包含+字符的时候,参数传递就会出现问题;其他参数也忘记了,一并加上。

附:以调用腾讯“broadcast_timeline 我发表时间线”为例的PHP片段代码,主要为了说明oauth_signature的生成和url的拼装,其中考虑有同名参数时需再按value排序(If two or more parameters share the same name, they are sorted by their value):
[quote]$QQ_APP_KEY = "xxx";
$QQ_APP_SECRET = "xxx";
$QQ_AUTH_TOKEN = "xxx"; //Request Token
$QQ_TOKEN_SECRET = "xxx"; //Request Token Secret
$QQ_BROADCAST_TIMELINE_URL = "http://open.t.qq.com/api/statuses/broadcast_timeline";
$QQ_HTTP_METHOD = "GET";
$QQ_DEFAULT_COUNT_NUMBER = 20;

$QQ_BROADCAST_TIMELINE_PARAMS = array (
 "format" => "json",
 "oauth_consumer_key" => $QQ_APP_KEY,
 "oauth_signature_method" => "HMAC-SHA1",
 "oauth_token" => $QQ_AUTH_TOKEN,
 "oauth_version" => "1.0",
 "pageflag" => 0,
 "pagetime" => 0,
 "reqnum" => $QQ_DEFAULT_COUNT_NUMBER,
 "oauth_timestamp" => "",
 "oauth_nonce" => ""
);

//init variable params
$QQ_BROADCAST_TIMELINE_PARAMS["oauth_timestamp"] = time();
$QQ_BROADCAST_TIMELINE_PARAMS["oauth_nonce"] = md5(uniqid(rand()));

//sort params: If two or more parameters share the same name, they are sorted by their value
ksort($QQ_BROADCAST_TIMELINE_PARAMS);
foreach ($QQ_BROADCAST_TIMELINE_PARAMS as $k => $v)
{
 if (is_array($v))
 {
  sort($v);
  $QQ_BROADCAST_TIMELINE_PARAMS[$k] = $v;
 }
}

$params = "";
foreach ($QQ_BROADCAST_TIMELINE_PARAMS as $k => $v)
{
 if (is_array($v))
 {
  foreach ($v as $k2 => $v2)
  {
   $params .= urlencode($k)."%3D".urlencode($v2)."%26";
  }
 }
 else
 {
  $params .= urlencode($k)."%3D".urlencode($v)."%26";
 }
}
$params = substr($params, 0, strlen($params) - 3);

//generate signature base string, key and oauth signature
$signature_base = $QQ_HTTP_METHOD."&".urlencode(strtolower($QQ_BROADCAST_TIMELINE_URL))."&".$params;
$signature_key = $QQ_APP_SECRET."&".$QQ_TOKEN_SECRET;
$oauth_signature = base64_encode(hash_hmac("sha1", $signature_base, $signature_key, true));

//generate full request url
$url = $QQ_BROADCAST_TIMELINE_URL."?";
foreach ($QQ_BROADCAST_TIMELINE_PARAMS as $k => $v)
{
 if (is_array($v))
 {
  foreach ($v as $k2 => $v2)
  {
   $url .= urlencode($k)."=".urlencode($v2)."&";
  }
 }
 else
 {
  $url .= urlencode($k)."=".urlencode($v)."&";
 }
}
$url .= "oauth_signature=".urlencode($oauth_signature);

//get remote data by url
...

[/quote]