V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
pidan
V2EX  ›  互联网

熊猫关服务器了,想下载喜欢的主播的高能视频

  •  
  •   pidan · 2019-03-08 03:45:01 +08:00 · 5121 次点击
    这是一个创建于 2089 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一直非常喜欢托马斯,所以想下载托马斯的所有高能视频,但是 m3u8 这个后缀的文件的地址一直找不到,请教一下大神。 我是想用 python 来爬。

    12 条回复    2019-03-11 03:12:22 +08:00
    whileFalse
        1
    whileFalse  
       2019-03-08 06:27:46 +08:00 via iPhone
    熊猫 tv 吗?
    NeMeQuittePas
        2
    NeMeQuittePas  
       2019-03-08 08:19:03 +08:00 via Android
    用抓包软件或者插件试试
    7654
        3
    7654  
       2019-03-08 08:32:49 +08:00
    开 F12,m3u8 在控制台有输出的
    pandas
        4
    pandas  
       2019-03-08 08:44:29 +08:00
    不止熊猫关服务器,还有某易的相册,某某宝,某度小视频...dengdengduang
    zhttty
        5
    zhttty  
       2019-03-08 08:49:39 +08:00
    某王凉了?
    muyi
        6
    muyi  
       2019-03-08 08:50:37 +08:00
    @zhttty #5 他早退股撤资了
    leeeboo
        8
    leeeboo  
       2019-03-08 15:40:04 +08:00
    例如:
    https://v.panda.tv/video/70466

    关键是这个:
    https://vod.gate.panda.tv/api/singlevideo?__plat=pc_web&_=1552030554705&videoid=70468
    1552030554705 是时间戳
    70468 这个是 video 的 id
    这个接口会返回一个字段:v_url
    例如: https://pl-vod28.live.panda.tv/transcode/20641/2019-03-01/c1a47ce176593250334a9c6ab7a2d831/index.m3u8
    这个就是 m3u8

    我也想弄,但这两天特别忙,兄弟费心了 @pidan
    leeeboo
        9
    leeeboo  
       2019-03-08 15:42:59 +08:00
    https://vod.gate.panda.tv/api/hostvideos?token=XXX&hostid=3169412&pageno=1&pagenum=12&__plat=pc_web&_=1552030867202

    这个是获取高能列表的 api,其中 pageno 和 pagenum 就是分页,token 我不能给你我的,你自己登陆看看吧就是在 https://www.panda.tv/20641 这个页面开 chrome 的 console 看 network,过滤只看 xhr 就能找到这个请求
    leeeboo
        10
    leeeboo  
       2019-03-08 16:18:34 +08:00   ❤️ 1
    package main

    import (
    "crypto/tls"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "os/exec"
    "strings"
    )

    type Video struct {
    Vurl string `json:"v_url"`
    Title string `json:"title"`
    }

    type Data struct {
    Total int `json:"total"`
    Items []Video `json:"items"`
    }

    type Resp struct {
    ErrNo int `json:"errno"`
    ErrMsg string `json:"errmsg"`
    Data Data
    }

    var success int
    var fail int

    func init() {
    success = 0
    fail = 0
    }

    func main() {

    page := 1
    count := 20

    for {

    api := fmt.Sprintf("https://vod.gate.panda.tv/api/hostvideos?token=efcc794d06d7718d674306c6ee1b8096&hostid=3169412&pageno=%d&pagenum=%d&__plat=pc_web&_=1552030867202", page, count)

    body, err := httpGet(api, nil)

    if err != nil {
    panic(err)
    }

    var resp Resp

    err = json.Unmarshal(body, &resp)

    if err != nil {
    panic(err)
    }

    if resp.ErrNo != 0 {
    fmt.Errorf("%s\n", resp.ErrMsg)
    break
    }

    if len(resp.Data.Items) <= 0 {
    fmt.Println("完成了!")
    break
    }

    for _, video := range resp.Data.Items {
    fmt.Println("Starting...", video.Title, video.Vurl)

    download(video.Vurl, video.Title)
    }

    page++
    }

    select {}
    }

    func download(u string, title string) {

    c := fmt.Sprintf("./m3u8.sh %s ./video/%s", u, title)
    cmd := exec.Command("sh", "-c", c)
    _, err := cmd.Output()

    if err != nil {
    fmt.Println(err.Error(), title, "失败")
    success++
    } else {
    fmt.Println(title, "成功")
    fail++
    }
    }

    func httpGet(api string, param map[string]interface{}) ([]byte, error) {

    queryStr, err := build(param)

    if err != nil {
    return nil, err
    }

    apiInfo, err := url.Parse(api)

    if err != nil {
    return nil, err
    }

    if apiInfo.RawQuery == "" {
    api = fmt.Sprintf("%s?%s", api, queryStr)
    } else {
    api = fmt.Sprintf("%s&%s", api, queryStr)
    }

    http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}

    resp, err := http.Get(api)

    if err != nil {
    return nil, err
    }

    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)

    return body, err
    }

    func build(raw map[string]interface{}) (string, error) {

    p := make(map[string]string, 0)

    for k, v := range raw {

    switch vv := v.(type) {
    case []interface{}:

    parseNormal(p, vv, []string{k})

    break
    case map[string]interface{}:

    parseKeyValue(p, vv, []string{k})

    break
    default:

    p[k] = fmt.Sprintf("%s", vv)

    break
    }
    }

    data := url.Values{}

    for k, v := range p {
    data.Add(k, v)
    }

    return data.Encode(), nil
    }

    func parseKeyValue(p map[string]string, raw map[string]interface{}, keys []string) {

    for k, v := range raw {
    switch vv := v.(type) {
    case []interface{}:

    tmpKeys := append(keys, k)

    parseNormal(p, vv, tmpKeys)

    break
    case map[string]interface{}:

    tmpKeys := append(keys, k)

    parseKeyValue(p, vv, tmpKeys)

    break
    default:

    //keys = append(keys, k)

    var tmp []string

    for m, n := range keys {
    if m > 0 {
    n = fmt.Sprintf("[%s]", n)
    }

    tmp = append(tmp, n)
    }

    kStr := strings.Join(tmp, "")

    p[fmt.Sprintf("%s[%s]", kStr, k)] = fmt.Sprintf("%s", vv)

    break
    }
    }
    }

    func parseNormal(p map[string]string, raw []interface{}, keys []string) {

    for k, v := range raw {
    switch vv := v.(type) {
    case []interface{}:

    tmpKeys := append(keys, fmt.Sprintf("%d", k))

    parseNormal(p, vv, tmpKeys)

    break
    case map[string]interface{}:

    tmpKeys := append(keys, fmt.Sprintf("%d", k))

    parseKeyValue(p, vv, tmpKeys)

    break
    default:

    //keys = append(keys, fmt.Sprintf("%d", k))

    var tmp []string

    for m, n := range keys {
    if m > 0 {
    n = fmt.Sprintf("[%s]", n)
    }

    tmp = append(tmp, n)
    }

    kStr := strings.Join(tmp, "")

    p[fmt.Sprintf("%s[%d]", kStr, k)] = fmt.Sprintf("%s", vv)

    break
    }
    }
    }

    我已经开始下了 @pidan
    pidan
        11
    pidan  
    OP
       2019-03-11 02:58:17 +08:00
    @leeeboo 谢谢我研究下
    pidan
        12
    pidan  
    OP
       2019-03-11 03:12:22 +08:00
    @leeeboo 尴尬可能我学艺不精并不能看懂,甚至用都不会用,但是万分感谢兄弟。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   878 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 21:01 · PVG 05:01 · LAX 13:01 · JFK 16:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.