分享一段可以直接下载新浪微博视频的小程序

昨天看微博发现一个有趣的视频。
视频

然后看了很感动,想下载下来收藏。所以点微博视频进去看了一下,就到了http://video.weibo.com/show?fid=1034:0e906d53094c5d231bf09028af8ba9b1这个链接,打开网页源代码看了一下:

<!doctype html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta id="viewport" name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,minimal-ui"><link class="style" rel="stylesheet" href="http://img.t.sinajs.cn/t4/appstyle/photo/css/pages/miaopai.css?v2"><title>视频</title></head><body><div style="margin:0 auto;text-align:center"><embed type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="transparent" quality="high" pluginspage="http://get.adobe.com/cn/flashplayer/" height="480" width="480" src="http://js.t.sinajs.cn/t5/album/static/swf/video/player.swf?_v122326477820508684050" flashvars="list=http%3A%2F%2Fus.sinaimg.cn%2F003BqToKjx06PK8lOidW0104010000220k01.m3u8%3FKID%3Dunistore%2Cvideo%26Expires%3D1423376348%26ssig%3Dvuz2N%252FMVtm" /></div></body></html>

发现播放的是flashvars="list=http%3A%2F%2Fus.sinaimg.cn%2F003BqToKjx06PK8lOidW0104010000220k01.m3u8%3FKID%3Dunistore%2Cvideo%26Expires%3D1423376348%26ssig%3Dvuz2N%252FMVtm"这样一个m3u8文件,不说了,先把m3u8列表下载下来看看,不看不知道,一看吓一跳,原来是个完整的mp4文件。注意上面的链接需要urldecode一下,得到:http://us.sinaimg.cn/003BqToKjx06PK8lOidW0104010000220k01.m3u8?KID=unistore,video&Expires=1423376348&ssig=vuz2N%2FMVtm

#EXTM3U#EXT-X-VERSION:3#EXT-X-TARGETDURATION:207#EXTINF:206.640000,000KDKzUjx06PK8lMcpx01040100JzGp0k01.mp4#EXT-X-ENDLIST

那就好办了,直接下载http://us.sinaimg.cn/000KDKzUjx06PK8lMcpx01040100JzGp0k01.mp4就好了。

为了方便下载同类型的视频,小写了一个代码。https://gist.github.com/jemygraw/412a4fd557d875fd3037

package main 
//Usage: vsina http://video.weibo.com/show?fid=1034:0e906d53094c5d231bf09028af8ba9b1import (
    "bufio"
    "fmt"
    "github.com/astaxie/beego/httplib"
    "io"
    "io/ioutil"
    "net/url"
    "os"
    "regexp"
    "strings"
    "time")
 func help() {
    fmt.Println("Usage: vsina <VideoUrl>")}
 func fetch(videoUrl string) {
    req := httplib.Get(videoUrl)
    resp, err := req.Response()
    if err != nil {
        fmt.Println("fetch video url error,", err)
        return
    }
    defer resp.Body.Close()
    respData, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("read video url content error,", err)
        return
    }
    pattern := `flashvars="list=.*"`
    regx := regexp.MustCompile(pattern)
    flashVars := regx.FindString(string(respData))
    if flashVars != "" {
        size := len(flashVars)
        m3u8Url, err := url.QueryUnescape(flashVars[16 : size-1])
        if err != nil {
            fmt.Println(err)
        } else {
            fetchMovie(m3u8Url)
        }
    } else {
        fmt.Println("m3u8 playlist not found")
    }}
 func fetchMovie(m3u8Url string) {
    req := httplib.Get(m3u8Url)
    resp, respErr := req.Response()
    if respErr != nil {
        fmt.Println("fetch m3u8 playlist error,", respErr)
        return
    }
    defer resp.Body.Close()
    respData, readErr := ioutil.ReadAll(resp.Body)
    if readErr != nil {
        fmt.Println("read m3u8 playlist content error,", readErr)
        return
    }
    videoFolder := fmt.Sprintf("video_%d", time.Now().Unix())
    mkdErr := os.Mkdir(videoFolder, 0775)
    if mkdErr != nil {
        fmt.Println("mkdir for m3u8 playlist failed,", mkdErr)
        return
    }
    m3u8Uri, _ := url.Parse(m3u8Url)
 
    sReader := strings.NewReader(string(respData))
    bReader := bufio.NewScanner(sReader)
    bReader.Split(bufio.ScanLines)
    for bReader.Scan() {
        line := bReader.Text()
        if !strings.HasPrefix(line, "#") {
            tsFileName := line
            tsLocalFileName := fmt.Sprintf("%s/%s", videoFolder, line)
            tsFileUrl := fmt.Sprintf("%s://%s/%s", m3u8Uri.Scheme, m3u8Uri.Host, tsFileName)
            downloadTS(tsFileUrl, tsLocalFileName)
        }
    }
    fmt.Println()
    fmt.Println("Result:", videoFolder)}
 func downloadTS(tsFileUrl string, tsLocalFileName string) {
    fmt.Println("downloading", tsFileUrl)
    req := httplib.Get(tsFileUrl)
    resp, respErr := req.Response()
    if respErr != nil {
        fmt.Println("download ts ", tsFileUrl, "failed,", respErr)
        return
    }
    defer resp.Body.Close()
    tsFp, openErr := os.OpenFile(tsLocalFileName, os.O_CREATE|os.O_WRONLY, 0775)
    if openErr != nil {
        fmt.Println("open local file", tsLocalFileName, "failed,", openErr)
        return
    }
    defer tsFp.Close()
    _, copyErr := io.Copy(tsFp, resp.Body)
    if copyErr != nil {
        fmt.Println("download ts", tsFileUrl, " failed,", copyErr)
    }}
 func main() {
    argv := os.Args
    argc := len(argv)
    if argc != 2 {
        help()
        return
    }
 
    videoUrl := argv[1]
    fetch(videoUrl)}

你可能感兴趣的:(分享一段可以直接下载新浪微博视频的小程序)