上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖

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

[复制链接]

123

主题

932

帖子

550

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
550
发表于 2021-8-30 14:23:27 | 显示全部楼层 | 阅读模式

FBI WARNING

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

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

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

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

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[prop+'proxy']=(...funcargs)=> {
                                let result=target[prop].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

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

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

是获取刷新列表的fetch api

图片.png

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

图片.png

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

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

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

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

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

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

}

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

所以这里的完整代码就是

                                if(bianliang.length!==0&&bianliang[0].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[index].ad===undefined){
                                                        retobj.data.push(data.data[index])
                                                    }
                                                }
                                                resolve(retobj)
                                            }
                                        )
                                    })
                                }

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

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

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

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

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

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部分的帮助

撒花~

发表回复

本版积分规则

快速回复 返回顶部 返回列表