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

2019-03-08 03:45:01 +08:00
 pidan

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

4901 次点击
所在节点    互联网
12 条回复
whileFalse
2019-03-08 06:27:46 +08:00
熊猫 tv 吗?
NeMeQuittePas
2019-03-08 08:19:03 +08:00
用抓包软件或者插件试试
7654
2019-03-08 08:32:49 +08:00
开 F12,m3u8 在控制台有输出的
pandas
2019-03-08 08:44:29 +08:00
不止熊猫关服务器,还有某易的相册,某某宝,某度小视频...dengdengduang
zhttty
2019-03-08 08:49:39 +08:00
某王凉了?
muyi
2019-03-08 08:50:37 +08:00
@zhttty #5 他早退股撤资了
celeron533
2019-03-08 10:09:24 +08:00
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
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
2019-03-08 16:18:34 +08:00
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
2019-03-11 02:58:17 +08:00
@leeeboo 谢谢我研究下
pidan
2019-03-11 03:12:22 +08:00
@leeeboo 尴尬可能我学艺不精并不能看懂,甚至用都不会用,但是万分感谢兄弟。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/542338

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX