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

jquery和ajaxhooker在抖音网页的爱恨交加

[复制链接]

该用户从未签到

2

主题

3

回帖

23

积分

助理工程师

积分
23
发表于 2024-6-14 14:58:52 | 显示全部楼层 | 阅读模式
悬赏10油猫币未解决

需求:用ajaxhooker拦截抖音网页视频的xhr请求并且改写responseText实现视频不需要加载,但要不影响 关注、私信、评论、点赞等社交功能的正常使用

代码:有引入 jquery ajaxHooker ElementGetter

环境:最新版油猴、最新版谷歌浏览器

目前解决方案:
在搜索页 https://www.douyin.com/search/%E4%BA%94%E9%87%91?type=user ,脚本run-at document-start 并且引入jquery就会报一个createElement报错,无论是低还是高版本的jquery都会报错,估计是与抖音这个搜索页有不兼容的地方,但为了拦截其他页面的视频不加载就必须要document-start + ajaxHooker 才可以实现,目前做了两个一样的脚本,只不过搜索页就是普通运行,其他页面就是document-start,已经实现批量打开视频页都不加载视频

image.png
image.png

// ==UserScript== // @name demo // @namespace http://tampermonkey.net/ // @version 1.0.0 // @author You // @description demo // @match https://www.douyin.com/user/* // @match https://www.douyin.com/search/*?*type=user* // @include https://www.douyin.com* // @icon https://lf1-cdn-tos.bytegoofy.com/goofy/ies/douyin_web/public/favicon.ico // @require https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.7.1.min.js // @grant unsafeWindow // @run-at document-start // ==/UserScript==

  • TA的每日心情
    慵懒
    4 天前
  • 签到天数: 193 天

    [LV.7]常住居民III

    710

    主题

    5881

    回帖

    6704

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6704

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2024-6-14 15:44:20 | 显示全部楼层

    这个属于jquery的问题
    根据调试确定了
    在document.createElement( "fieldset" );找不到document

    function assert( fn ) {
        var el = document.createElement( "fieldset" );
    
        try {
            return !!fn( el );
        } catch ( e ) {
            return false;
        } finally {
    
            // Remove from its parent by def

    相关github可以找到https://github.com/jquery/jquery/issues/4308
    索引到了https://github.com/jquery/jquery/issues/3333
    但是官方并不认为这个属于一个问题

    根据我个人的调试
    这里的document读取的是window.document
    document的处理逻辑在

        function setDocument( node ) {
            var subWindow,
                doc = node ? node.ownerDocument || node : preferredDoc;
    
            // Return early if doc is invalid or already selected
            // Support: IE 11+, Edge 17 - 18+
            // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
            // two documents; shallow comparisons work.
            // eslint-disable-next-line eqeqeq
            if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {
                return document;
            }
    
            // Update global variables
            document = doc;
            documentElement = document.documentElement;
            documentIsHTML = !jQuery.isXMLDoc( document );
    
            // Support: iOS 7 only, IE 9 - 11+
            // Older browsers didn't support unprefixed `matches`.
            matches = documentElement.matches ||
                documentElement.webkitMatchesSelector ||
                documentElement.msMatchesSelector;
    
            // Support: IE 9 - 11+, Edge 12 - 18+
            // Accessing iframe documents after unload throws "permission denied" errors
            // (see trac-13936).
            // Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`,
            // all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well.
            if ( documentElement.msMatchesSelector &&
    
                // Support: IE 11+, Edge 17 - 18+
                // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
                // two documents; shallow comparisons work.
                // eslint-disable-next-line eqeqeq
                preferredDoc != document &&
                ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {
    
                // Support: IE 9 - 11+, Edge 12 - 18+
                subWindow.addEventListener( "unload", unloadHandler );
            }
    
            // Support: IE <10
            // Check if getElementById returns elements by name
            // The broken getElementById methods don't pick up programmatically-set names,
            // so use a roundabout getElementsByName test
            support.getById = assert( function( el ) {
                documentElement.appendChild( el ).id = jQuery.expando;
                return !document.getElementsByName ||
                    !document.getElementsByName( jQuery.expando ).length;
            } );
    
            // Support: IE 9 only
            // Check to see if it's possible to do matchesSelector
            // on a disconnected node.
            support.disconnectedMatch = assert( function( el ) {
                return matches.call( el, "*" );
            } );
    
            // Support: IE 9 - 11+, Edge 12 - 18+
            // IE/Edge don't support the :scope pseudo-class.
            support.scope = assert( function() {
                return document.querySelectorAll( ":scope" );
            } );
    
            // Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only
            // Make sure the `:has()` argument is parsed unforgivingly.
            // We include `*` in the test to detect buggy implementations that are
            // _selectively_ forgiving (specifically when the list includes at least
            // one valid selector).
            // Note that we treat complete lack of support for `:has()` as if it were
            // spec-compliant support, which is fine because use of `:has()` in such
            // environments will fail in the qSA path and fall back to jQuery traversal
            // anyway.
            support.cssHas = assert( function() {
                try {
                    document.querySelector( ":has(*,:jqfake)" );
                    return false;
                } catch ( e ) {
                    return true;
                }
            } );
    
            // ID filter and find
            if ( support.getById ) {
                Expr.filter.ID = function( id ) {
                    var attrId = id.replace( runescape, funescape );
                    return function( elem ) {
                        return elem.getAttribute( "id" ) === attrId;
                    };
                };
                Expr.find.ID = function( id, context ) {
                    if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
                        var elem = context.getElementById( id );
                        return elem ? [ elem ] : [];
                    }
                };
            } else {
                Expr.filter.ID =  function( id ) {
                    var attrId = id.replace( runescape, funescape );
                    return function( elem ) {
                        var node = typeof elem.getAttributeNode !== "undefined" &&
                            elem.getAttributeNode( "id" );
                        return node && node.value === attrId;
                    };
                };
    
                // Support: IE 6 - 7 only
                // getElementById is not reliable as a find shortcut
                Expr.find.ID = function( id, context ) {
                    if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
                        var node, i, elems,
                            elem = context.getElementById( id );
    
                        if ( elem ) {
    
                            // Verify the id attribute
                            node = elem.getAttributeNode( "id" );
                            if ( node && node.value === id ) {
                                return [ elem ];
                            }
    
                            // Fall back on getElementsByName
                            elems = context.getElementsByName( id );
                            i = 0;
                            while ( ( elem = elems[ i++ ] ) ) {
                                node = elem.getAttributeNode( "id" );
                                if ( node && node.value === id ) {
                                    return [ elem ];
                                }
                            }
                        }
    
                        return [];
                    }
                };
            }
    
            // Tag
            Expr.find.TAG = function( tag, context ) {
                if ( typeof context.getElementsByTagName !== "undefined" ) {
                    return context.getElementsByTagName( tag );
    
                // DocumentFragment nodes don't have gEBTN
                } else {
                    return context.querySelectorAll( tag );
                }
            };
    
            // Class
            Expr.find.CLASS = function( className, context ) {
                if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
                    return context.getElementsByClassName( className );
                }
            };
    
            /* QSA/matchesSelector
            ---------------------------------------------------------------------- */
    
            // QSA and matchesSelector support
    
            rbuggyQSA = [];
    
            // Build QSA regex
            // Regex strategy adopted from Diego Perini
            assert( function( el ) {
    
                var input;
    
                documentElement.appendChild( el ).innerHTML =
                    "<a id='" + expando + "' href='' disabled='disabled'></a>" +
                    "<select id='" + expando + "-\r\\' disabled='disabled'>" +
                    "<option selected=''></option></select>";
    
                // Support: iOS <=7 - 8 only
                // Boolean attributes and "value" are not treated correctly in some XML documents
                if ( !el.querySelectorAll( "[selected]" ).length ) {
                    rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
                }
    
                // Support: iOS <=7 - 8 only
                if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
                    rbuggyQSA.push( "~=" );
                }
    
                // Support: iOS 8 only
                // https://bugs.webkit.org/show_bug.cgi?id=136851
                // In-page `selector#id sibling-combinator selector` fails
                if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
                    rbuggyQSA.push( ".#.+[+~]" );
                }
    
                // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+
                // In some of the document kinds, these selectors wouldn't work natively.
                // This is probably OK but for backwards compatibility we want to maintain
                // handling them through jQuery traversal in jQuery 3.x.
                if ( !el.querySelectorAll( ":checked" ).length ) {
                    rbuggyQSA.push( ":checked" );
                }
    
                // Support: Windows 8 Native Apps
                // The type and name attributes are restricted during .innerHTML assignment
                input = document.createElement( "input" );
                input.setAttribute( "type", "hidden" );
                el.appendChild( input ).setAttribute( "name", "D" );
    
                // Support: IE 9 - 11+
                // IE's :disabled selector does not pick up the children of disabled fieldsets
                // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+
                // In some of the document kinds, these selectors wouldn't work natively.
                // This is probably OK but for backwards compatibility we want to maintain
                // handling them through jQuery traversal in jQuery 3.x.
                documentElement.appendChild( el ).disabled = true;
                if ( el.querySelectorAll( ":disabled" ).length !== 2 ) {
                    rbuggyQSA.push( ":enabled", ":disabled" );
                }
    
                // Support: IE 11+, Edge 15 - 18+
                // IE 11/Edge don't find elements on a `[name='']` query in some cases.
                // Adding a temporary attribute to the document before the selection works
                // around the issue.
                // Interestingly, IE 10 & older don't seem to have the issue.
                input = document.createElement( "input" );
                input.setAttribute( "name", "" );
                el.appendChild( input );
                if ( !el.querySelectorAll( "[name='']" ).length ) {
                    rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" +
                        whitespace + "*(?:''|\"\")" );
                }
            } );
    
            if ( !support.cssHas ) {
    
                // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+
                // Our regular `try-catch` mechanism fails to detect natively-unsupported
                // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`)
                // in browsers that parse the `:has()` argument as a forgiving selector list.
                // https://drafts.csswg.org/selectors/#relational now requires the argument
                // to be parsed unforgivingly, but browsers have not yet fully adjusted.
                rbuggyQSA.push( ":has" );
            }
    
            rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) );
    
            /* Sorting
            ---------------------------------------------------------------------- */
    
            // Document order sorting
            sortOrder = function( a, b ) {
    
                // Flag for duplicate removal
                if ( a === b ) {
                    hasDuplicate = true;
                    return 0;
                }
    
                // Sort on method existence if only one input has compareDocumentPosition
                var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
                if ( compare ) {
                    return compare;
                }
    
                // Calculate position if both inputs belong to the same document
                // Support: IE 11+, Edge 17 - 18+
                // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
                // two documents; shallow comparisons work.
                // eslint-disable-next-line eqeqeq
                compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?
                    a.compareDocumentPosition( b ) :
    
                    // Otherwise we know they are disconnected
                    1;
    
                // Disconnected nodes
                if ( compare & 1 ||
                    ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {
    
                    // Choose the first element that is related to our preferred document
                    // Support: IE 11+, Edge 17 - 18+
                    // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
                    // two documents; shallow comparisons work.
                    // eslint-disable-next-line eqeqeq
                    if ( a === document || a.ownerDocument == preferredDoc &&
                        find.contains( preferredDoc, a ) ) {
                        return -1;
                    }
    
                    // Support: IE 11+, Edge 17 - 18+
                    // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
                    // two documents; shallow comparisons work.
                    // eslint-disable-next-line eqeqeq
                    if ( b === document || b.ownerDocument == preferredDoc &&
                        find.contains( preferredDoc, b ) ) {
                        return 1;
                    }
    
                    // Maintain original order
                    return sortInput ?
                        ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
                        0;
                }
    
                return compare & 4 ? -1 : 1;
            };
    
            return document;
        }

    根据我的测试可以使

    // @require      data:application/javascript,with%20(%7Bwindow%3A%7Bdocument%3A%7BdocumentElement%3Atrue%2CnodeType%3A9%7D%7D%7D)%20%7B
    // @require      https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.7.1.js
    // @require      data:application/javascript,%7D

    控制document的修改读数

    可以在此基础上通过proxy代理document并劫持nodeType以及documentElement属性应该即可解决这个问题

    因为编写的代码太多就跳过了

    还是更简易直接原生

    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    半小时前
  • 签到天数: 347 天

    [LV.8]以坛为家I

    7

    主题

    30

    回帖

    239

    积分

    高级工程师

    积分
    239

    挑战者 lv2

    发表于 2024-6-14 21:42:39 | 显示全部楼层
    自己写个hook xhr不就解决了?
    我给我常用的你参考一下。
    1. unsafeWindow.XMLHttpRequest = class extends unsafeWindow.XMLHttpRequest {
    2.     get xhrResponseValue() {
    3.         const xhr = this;
    4.         if (xhr.readyState === unsafeWindow.XMLHttpRequest.DONE && xhr.status === 200) {
    5.             const url = xhr.responseURL;
    6.             // 匹配url
    7.             if (url.includes('xxxx.com')) {
    8.                 try {
    9.                     //获取返回的值
    10.                     let response_text = super.response;
    11.                     //  处理 response_text 返回处理后结果
    12.                     //  return 处理后的字符串
    13.                     return response_text;
    14.                 } catch (error) {
    15.                     console.log('处理失败!', error);
    16.                 }
    17.         
    18.             }
    19.         }
    20.         return super.response;
    21.     }
    22.     get responseText() {
    23.         return this.xhrResponseValue;
    24.     }
    25.     get response() {
    26.         return this.xhrResponseValue;
    27.     }
    28. };
    复制代码
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    881

    回帖

    1379

    积分

    荣誉开发者

    积分
    1379

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2024-6-14 23:24:33 | 显示全部楼层
    嗯。。。ajaxHooker也不是非得在document-start引入,之前发生过网页劫持与库劫持相互争夺主权的问题,所以我刻意弱化了库对执行时机的依赖,以你这种情况来说,在document-body阶段引入应该也没有问题,只要目标请求没那么快发生就行。
    回复

    使用道具 举报

    发表回复

    本版积分规则

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