李恒道 发表于 2021-8-30 14:23:27

[油猴脚本开发指南]实战fetch劫持知乎去广告

# FBI WARNING

上节课在实战的时候我发现存在严重错误,根据cxxjackie的提示和帮助下进一步完善了代码,相对来说还是较重的,下节课会介绍另一种方法。

上节课的主要错误在于,部分网页对于fetch存在一个喜欢写入自定义数据和读入自定义数据的问题。

由于我创建了一层多余的空对象,网页过掉了porxy,直接在空对象写入数据,导致出现错误。

以下代码仅经过了少量的测试,不代表真的不存在问题,如果存在问题可以反馈给我。

```javascript
let oldfetch=fetch
function newobj(){}
function fuckfetch(...bianliang){
    return new Promise(function(resolve, reject){
      oldfetch(...bianliang).then(function(response) {
            let handler = {
                get: function(target, prop, receiver) {
                  if(typeof Reflect.get(target,prop)==='function')
                  {
                        if(Reflect.get(target,prop+'proxy')===undefined)
                        {
                            target=(...funcargs)=> {
                              let result=target.call(target,...funcargs)
                              //书写劫持的函数代码
                              console.log('fetchfunction',bianliang,prop,funcargs,result)
                              return result
                            }

                        }
                        return Reflect.get(target,prop+'proxy')
                  }

                  return Reflect.get(target, prop);
                },

                set(target, prop, value) {
                  return Reflect.set(target, prop, value);
                },
            };
            let proxy=new Proxy(response, handler)
            resolve(proxy)
      })

    });
}

window.fetch=fuckfetch
```

然后我们通过抓包可以看到

```javascript
https://www.zhihu.com/api/v3/feed/topstory/recommend?
```

是获取刷新列表的fetch api

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

运行脚本,可以发现这个api调用的json进行的返回对象的json化,所有我们开写代码了!

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

首先判断变量的长度,以及url,如果都没问题,再判断调用的函数名是否是json,如果满足的话

说明我们需要进行劫持了!

观察result返回的内容,json返回的是一个Promise

所以我们也需要返回一个Promise

```javascript
if(bianliang.length!==0&&bianliang.indexOf('/api/v3/feed/topstory/recommend')!==-1&&prop==='json'){

return new Promise(function(resolve, reject){})

}
```

我们在promise内先获取result的结果,然后进行处理,再resolve结束我们创建的这个promise

所以这里的完整代码就是

```javascript
                              if(bianliang.length!==0&&bianliang.indexOf('/api/v3/feed/topstory/recommend')!==-1&&prop==='json'){
                                    return new Promise(function(resolve, reject){
                                        result.then(
                                          function(data){

                                                console.log('bianliang',bianliang)
                                                let retobj={
                                                    data:[],
                                                    fresh_text:data.fresh_text,
                                                    paging:data.paging,
                                                }
                                                for(let index=0;index<data.data.length;index++){
                                                    if(data.data.ad===undefined){
                                                      retobj.data.push(data.data)
                                                    }
                                                }
                                                resolve(retobj)
                                          }
                                        )
                                    })
                              }
```

我在result.then上挂载了一个函数,并执行相应的处理,最后在resolve回去数据,

返回的数据创建了三个属性,fresh_text以及paging都原封不动的传递,data,需要我们进行处理,这里我们可以使用ES6特性解包直接完成,但是代码相对更骚一点,很多人看不懂,暂时先忽略掉。

紧接着对result返回的data数据的data属性做一个便利,如果不存在ad属性就push进retobj的data数组上。

那目前为止我们已经解决大部分问题了,最后还有一个问题就是页面最初载入的时候也有一个广告,我们应该如何处理呢?

这里由于不属于教程返回,就简单粗暴处理了一下。

```javascript
window.onload=function(){
document.querySelector('.Pc-feedAd-container').parentElement.style.display='none'
}
```

具体脚本可以参考

https://bbs.tampermonkey.net.cn/forum.php?mod=viewthread&tid=911

# 结语

感谢cxxjackie对于fetch部分的帮助

撒花~

rubinTime 发表于 2021-12-7 22:10:36

let retobj={
                                                    data:[],
                                                    fresh_text:data.fresh_text,
                                                    paging:data.paging,
                                                }
这些参数是什么

李恒道 发表于 2021-12-8 09:21:34

rubinTime 发表于 2021-12-7 22:10
let retobj={
                                                    data:[],
                           ...

知乎的参数,原封不动拷贝了下

rubinTime 发表于 2021-12-8 10:18:08

哥哥为什么我一个ad属性都没看,data里面的每个item基本都是15对键值对,很少有16对,多出的那一对键值对键值也不是ad
https://s4.ax1x.com/2021/12/08/o2M0de.png

李恒道 发表于 2021-12-8 10:31:33

rubinTime 发表于 2021-12-8 10:18
哥哥为什么我一个ad属性都没看,data里面的每个item基本都是15对键值对,很少有16对,多出的那一对键值对键 ...

有ad的时候才会有ad属性
具体还是要根据页面调试
不过我之前写的脚本到现在都好使

rubinTime 发表于 2021-12-8 11:03:58

李恒道 发表于 2021-12-8 10:31
有ad的时候才会有ad属性
具体还是要根据页面调试
不过我之前写的脚本到现在都好使 ...

哥哥我试了你的脚本确实可以,但是我下来刷新等待fetch请求,明明途中看到广告但在返回的json属性的data子项中确实找不到ad

李恒道 发表于 2021-12-8 11:23:43

rubinTime 发表于 2021-12-8 11:03
哥哥我试了你的脚本确实可以,但是我下来刷新等待fetch请求,明明途中看到广告但在返回的json属性的data ...

![图片.png](data/attachment/forum/202112/08/112342s1vzn1ipp3lq1z3l.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/300 "图片.png")

李恒道 发表于 2021-12-8 11:23:56

rubinTime 发表于 2021-12-8 11:03
哥哥我试了你的脚本确实可以,但是我下来刷新等待fetch请求,明明途中看到广告但在返回的json属性的data ...

确实有ad属性的,哥哥可能找错了?

rubinTime 发表于 2021-12-8 21:03:32

gege我火狐浏览器找到ad属性了,但是chorme翻了好几条fetch就是找不到
页: [1]
查看完整版本: [油猴脚本开发指南]实战fetch劫持知乎去广告