李恒道 发表于 2021-8-20 21:32:48

[油猴脚本开发指南]实战抖音短视频无水印下载

# FBI WARNING

具体脚本可以参考

https://bbs.tampermonkey.net.cn/thread-872-1-1.html

# 前言

之前我们已经学习了xhr劫持的姿势

现在我们来实战一下,通过xhr劫持直接拿到返回的内容

通常通过xhr劫持可以达成两种效果,一个是在xhr发送数据之前对数据进行获取和篡改,一个则是在xhr返回数据之后进行获取

我们可以在https://www.douyin.com/user/MS4wLjABAAAAeq80JKa1oaIFOCOFjkw8o5STIHIsAnBQxVPxVJ4C7RZ5Hn8f1d_zNsMKaa8EOlCw?enter_method=video_title&author_id=3395719513245832&group_id=6976849455186185505&log_pb=%7B%22impr_id%22%3A%22021629423215634fdbddc0100fff0030a1217e00000001a54c1a3%22%7D&enter_from=undefined

通过f12进行抓包

大概查看一下数据,发现在`https://www.douyin.com/aweme/v1/web/aweme/post/?device_platform=webapp&aid=6383&channel=channel_pc_web&sec_user_id=MS4wLjABAAAAeq80JKa1oaIFOCOFjkw8o5STIHIsAnBQxVPxVJ4C7RZ5Hn8f1d_zNsMKaa8EOlCw&max_cursor=1624424355000&count=10&publish_video_strategy_type=2&version_code=160100&version_name=16.1.0&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Mozilla&browser_version=5.0+(Windows+NT+10.0%3B+Win64%3B+x64)+AppleWebKit%2F537.36+(KHTML,+like+Gecko)+Chrome%2F92.0.4515.159+Safari%2F537.36&browser_online=true&_signature=_02B4Z6wo00d01gP1vzgAAIDCg.dFeeve9RYD9buAAOHw7d`中的awemelist疑似是获取到的链接,这种乱七八糟一堆东西,我们想要做到解密是极其麻烦的,所以我们在这里可以直接打出一个xhr劫持获取返回内容

![图片.png](data/attachment/forum/202108/20/212559yeizyou15d7i2y1u.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

在这个网页里我们通过获取video的视频链接可以得到是v26开头的前缀,所以我们找一个json在线格式化的工具,贴入数据并解析,搜索v26

https://www.sojson.com/

发现很多地方都是存在v26链接的,挑几个进行测试,我最后找到了video.play_addr.url_list是无水印的链接

![图片.png](data/attachment/forum/202108/20/213109olblcgbsf6gztlgu.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

所以这里就打出了一个xhr劫持

```
    function addXMLRequestCallback(callback){
      var oldSend, i;
      if( XMLHttpRequest.callbacks ) {
            // we've already overridden send() so just add the callback
            XMLHttpRequest.callbacks.push( callback );
      } else {
            // create a callback queue
            XMLHttpRequest.callbacks = ;
            // store the native send()
            oldSend = XMLHttpRequest.prototype.send;
            // override the native send()
            XMLHttpRequest.prototype.send = function(){
                // process the callback queue
                // the xhr instance is passed into each callback but seems pretty useless
                // you can't tell what its destination is or call abort() without an error
                // so only really good for logging that a request has happened
                // I could be wrong, I hope so...
                // EDIT: I suppose you could override the onreadystatechange handler though
                for( i = 0; i < XMLHttpRequest.callbacks.length; i++ ) {
                  XMLHttpRequest.callbacks( this );
                }
                // call the native send()
                oldSend.apply(this, arguments);
            }
      }
    }

    // e.g.
    addXMLRequestCallback( function( xhr ) {
      xhr.addEventListener("load", function(){
            if ( xhr.readyState == 4 && xhr.status == 200 ) {
                if(xhr.responseURL.indexOf('/web/aweme/post')!==-1){
                  console.log('触发了加载')
                  let list=JSON.parse(xhr.response)
                  if(list.aweme_list!==undefined){
                        for(let index=0;index<list.aweme_list.length;index++){
                            let item=list.aweme_list.video.play_addr.url_list
                            if(item.length!==0){
                              videolist.push('https://'+item.replace('https://','').replace('http://','').replace('//',''))
                            }else{
                            alert('888')}

                        }

                  }

                }
            }
      });

    });
```

由于他是一个数组,所以这里判断了是否不为0再进行传入

('https://'+item.replace('https://','').replace('http://','').replace('//',''))

因为一些存在前缀,一些不存在http前缀,一些前缀是//,所以我这里直接全部过滤为空加入了https

那这里我们的抖音视频解析就完成了一半了,大家如果测试会发现

刚进入页面是没有进行这个post的

这个是为什么呢?

因为很多网页在加载过程中,会把一些用户数据或者页面数据直接放入网页中,在加载的过程中直接渲染

所以我才会推荐大家没思路的时候看看网页源代码进行分析

这里我们搜索v26看到了存在一个script标签,里面有一大坨乱七八糟的数据

![图片.png](data/attachment/forum/202108/20/213506qm5wvm8r8zhzmg8l.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

看到`%22%3A%221579877069082637%22%2C%22hashtagName%22%3A%22%E4%B8%`这种乱七八糟的%字符串,通常是url编码,我们需要进行解码

let unrender=JSON.parse(decodeURIComponent(document.querySelector('#RENDER_DATA').innerText))

编码与解码的方式通常存在三种

escape 和 unescape

encodeURI 和 decodeURI

encodeURIComponent 和 decodeURIComponent

通常我们使用decodeURIComponent就可以了

在解码之后成了一个文本,我们通过json.parse进行解码,因为他是一个对象进行字符化的文本

![图片.png](data/attachment/forum/202108/20/213920vrrrle9r74klwtsh.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

我们平时通过json对对象进行文本化以及将文本化转换成对象

言归正传

解析成对象的unrender存在三个键值,其中只有一个是存在视频列表的,所以我们使用Object.keys(unrender)获取他的所有键值

并且用for进行遍历

```
for(let index=0;index<keys.length;index++){
if(unrender].post!==undefined){
GetRenderTextVideo(videolist,unrender].post.data)
}
}
```


如果对应的对象的键值内存在post属性,就调用GetRenderTextVideo函数

```
function GetRenderTextVideo(MergeArray,VideoList){
    for(let index=0;index<VideoList.length;index++){
      let item=VideoList.video.playAddr
      if(item.length!==0){
            MergeArray.push('https://'+item.src.replace('//',''))
      }else{
            alert('8887')}


    }

}
```

这里的对象与我们通过xhr获取的对象不太一致,但是如何找到免水印的字符串的方法基本一致

到这里我们就完成了xhr的获取实战,下节课我们学习如果修改xhr参数!

# 结语

撒花~

wjy0 发表于 2021-8-21 02:18:22

ggnb!!

Ne-21 发表于 2021-8-21 08:55:07

撒花~~~~~~·

fai1988 发表于 2021-8-21 11:33:48

谢谢分享

水凛子 发表于 2021-8-21 14:08:48

ggnb!!

mtzmtz 发表于 2021-11-2 16:38:47

你真是个小可爱

李恒道 发表于 2021-11-2 20:36:19

mtzmtz 发表于 2021-11-2 16:38
你真是个小可爱

谢谢哥哥

mtzmtz 发表于 2021-11-14 10:22:55

多来点实战

李恒道 发表于 2021-11-15 00:05:36

mtzmtz 发表于 2021-11-14 10:22
多来点实战

主要有些理论我都有一点找不到例子....
只能说让大家都学学
以后碰到研究可以更方便一点

rubinTime 发表于 2021-12-2 23:06:14

哥哥现在v26的网址好像失效了,访问都403的forbidden状态码,哥哥是怎么判断数据是xhr返回渲染还是直接服务端渲染的,这个脚本获取资源是靠xhr劫持还是靠的抓取script标签里的数据
页: [1] 2
查看完整版本: [油猴脚本开发指南]实战抖音短视频无水印下载