zoukankan      html  css  js  c++  java
  • 今日头条sign-node环境

    爬取目标

    今日头条首页内容推荐内容(也就是下面红线的部分)

    也有爬取个人空间与头条新闻的实现,见末尾。

    相关接口

    可以观察到今日头条首页的第一页请求与之后的请求的url是不大一样的。

    第一次请求

    https://www.toutiao.com/api/pc/feed/?min_behot_time=0&category=__all__&utm_source=toutiao&widen=1&tadrequire=true&as=A1D52F17E1F6715&cp=5F71C6D781553E1&_signature=_signature
    // 为了方便观察,已经缩短了_signature参数的长度。

    第二次请求及以后的请求

    https://www.toutiao.com/api/pc/feed/?max_behot_time=1601263428&category=__all__&utm_source=toutiao&widen=1&tadrequire=true&as=A1254F17E13671F&cp=5F715637211FEE1&_signature=_signature
    // 为了方便观察,已经缩短了_signature参数的长度。

    变动的query参数有max_behot_time,as,cp以及signature。

    关于参数逆向

    一: max_behot_time

    max_behot_time很容易观察出来,这个参数来自与上一次请求的数据中的max_behot_time。

    如果是第一次请求的话,这个参数就变成了min_behot_time, 并且其值是定值。

    好了,这个就这么搞定了 

    二: signature

    第二个便是看signature是怎么生成的了。

     

    我们通过发起者(initator)找到一个调用函数(如下所示,Reqwest是随机选择的 )

     在此函数的内部下一个断点,然后页面向下滑动下。

     很显然,这个页面要生成的参数到这里都已经生成好了。这时候我们需要通过call stack看看这个函数的调用者们

     

    很快就发现了生成_signature参数的地方了

    653行的o便是生成的_signature参数了。

    就也是如下面的代码所示。

    var  url = "https://www.toutiao.com/toutiao/api/pc/feed/?max_behot_time=1601241738&category=__all__&utm_source=toutiao&widen=1&tadrequire=true&as=A1E57F277116DED&cp=5F71169DAE7D3E1";
    var signature = window.byted_acrawler.sign({url: url});

    貌似我们只要把 window.byted_acrawler.sign 的算法弄下来,就可以生成对应的_signature参数了。

     

     

    我们进入window.byted_acrawler.sign内部看一看

     明显的代码混淆。逆向并不是要将他的代码都读懂,如果你想这么做的话,那么你就中了他的圈套了。

     

    正确的做法应该是是拷贝相关的代码,先尝试在浏览器上运行,如果没有报错,那么说明这个代码没有明显的环境依赖。

    如果报错了,就要尝试补环境了,缺哪补哪。

    如果浏览器上运行正常,可以拿到node环境进行运行了,node环境要尽量模拟浏览器环境即可。

     

     

    首先我们复制下acrawler.js的所有的代码。

    开一个新的标签页。(建议地址栏输入 about:blank, 这样便可以得到完全的空白页了。这样就不会受其他网页的干扰了)

    粘贴下之前复制的acrawler的js代码到console中并执行,执行完毕后并没有报错,并且window.byted_acrawler.sign已经有了

    做个试验,看看生成的_signature对不对。

    var  url = "https://www.toutiao.com/toutiao/api/pc/feed/?max_behot_time=1601241738&category=__all__&utm_source=toutiao&widen=1&tadrequire=true&as=A1E57F277116DED&cp=5F71169DAE7D3E1";
    var signature = window.byted_acrawler.sign({url: url});

    生成倒是生成了,倒是长度有些短。长度短的原因是因为没有cookie的缘故。

    可以在本地开一个服务器,然后通过document.cookie 获取到今日头条网页的cookie。

    使用

    "你复制到的cookie".forEach((ele)=>{document.cookie = ele});

    便可以将今日头条下所有的cookie复制到本地的网页中了。

    这时候生成的_signature参数便是正常的长度了。

    浏览器试验完成,现在如果这个js可以在node环境运行的话,那就完美了。

    如何在node环境中运行呢?首先这个js是肯定会检测浏览器环境的,包括检测canvas,创建元素啥的。

    自己一个个写?太麻烦了。

    这里要用到的一个第三方库,那便是jsdom。这是一个利用来模拟浏览器环境的node第三方库。

    const jsdom = require("jsdom");
    const { JSDOM } = jsdom;
    // 
    //  
    // node_modules/jsdom@16.4.0/api.js
    // 
    const options = {
        url: "https://www.toutiao.com/",
        // to config userAgent, source code must be altered 
        // "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"
    
    }
    const { window } = new JSDOM("", options);
    var glb;
    // window.glb = glb;
    // var global = undefined;
    var process = undefined;
    var module = undefined;
    var exports = undefined;
    var { StyleSheet, MediaList, CSSStyleSheet, CSSRule, CSSStyleRule, CSSMediaRule, CSSImportRule, CSSStyleDeclaration, XPathException, XPathExpression, XPathResult, XPathEvaluator, onafterprint, onbeforeprint, onbeforeunload, onhashchange, onlanguagechange, onmessage, onmessageerror, onoffline, ononline, onpagehide, onpageshow, onpopstate, onrejectionhandled, onstorage, onunhandledrejection, onunload, onblur, onerror, onfocus, onload, onresize, onscroll, onabort, onautocomplete, onautocompleteerror, oncancel, oncanplay, oncanplaythrough, onchange, onclick, onclose, oncontextmenu, oncuechange, ondblclick, ondrag, ondragend, ondragenter, ondragexit, ondragleave, ondragover, ondragstart, ondrop, ondurationchange, onemptied, onended, oninput, oninvalid, onkeydown, onkeypress, onkeyup, onloadeddata, onloadedmetadata, onloadstart, onmousedown, onmouseenter, onmouseleave, onmousemove, onmouseout, onmouseover, onmouseup, onwheel, onpause, onplay, onplaying, onprogress, onratechange, onreset, onsecuritypolicyviolation, onseeked, onseeking, onselect, onsort, onstalled, onsubmit, onsuspend, ontimeupdate, ontoggle, onvolumechange, onwaiting, _registeredHandlers, _eventHandlers, _globalObject, _resourceLoader, _globalProxy, _document, _origin, _sessionHistory, _virtualConsole, _runScripts, _top, _parent, _frameElement, _length, _pretendToBeVisual, _storageQuota, _commonForOrigin, _currentOriginData, _localStorage, _sessionStorage, _selection, getSelection, length, frameElement, frames, self, parent, top, document, external, location, history, navigator, locationbar, menubar, personalbar, scrollbars, statusbar, toolbar, performance, screen, origin, localStorage, sessionStorage, customElements, setTimeout, setInterval, clearTimeout, clearInterval, postMessage, atob, btoa, stop, close, getComputedStyle, captureEvents, releaseEvents, console, name, status, devicePixelRatio, innerWidth, innerHeight, outerWidth, outerHeight, pageXOffset, pageYOffset, screenX, screenLeft, screenY, screenTop, scrollX, scrollY, alert, blur, confirm, focus, moveBy, moveTo, open, print, prompt, resizeBy, resizeTo, scroll, scrollBy, scrollTo, glb } = window;
    

    上面的写法骗过今日头条还是挺容易的。

    三:as cp参数的生成。

    可以看到as cp参数其实是变化的

    as cp生成的位置与_signature参数的位置还是挺近的(648行)

    this._setParams方法除了对max_behot_time参数的设置,还有对as,cp参数的更新

    上面的a函数便可以生成as,cp参数,粘贴到编辑器上,缺啥补啥即可。(约200行,就不粘贴到这里)

    四:JSDOM如何修改user-agent?

    首先说说为什么要修改user-agent?

    这是因为_signature中会使用user-agent,在发送请求时,headers中的user-agent要与_signature中的保持一致。

    const jsdom = require("jsdom");
    const {JSDOM} = jsdom;
    const resourceLoader = new jsdom.ResourceLoader({
        strictSSL: false,
        userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36",
      });
    const { window } = new JSDOM(``, { 
        resources: resourceLoader, 
        url: "https://www.toutiao.com/"
    });
    console.log(window.navigator.userAgent);
    console.log(window.location.href);
    

      

    相关源码

    首页

    链接:https://pan.baidu.com/s/1WVnGF8UntdYkLvz37dw5EQ
    提取码:04qr

    个人空间(run.py)与特定url(run2.py)

     链接:https://pan.baidu.com/s/17pswj3IcLn9qhDK8x-9DCA
     提取码:xyai

  • 相关阅读:
    二分练习题4 查找最接近的元素 题解
    二分练习题5 二分法求函数的零点 题解
    二分练习题3 查找小于x的最大元素 题解
    二分练习题2 查找大于等于x的最小元素 题解
    二分练习题1 查找元素 题解
    code forces 1176 D. Recover it!
    code forces 1173 B. Nauuo and Chess
    code forces 1173 C. Nauuo and Cards
    吴恩达深度学习课程笔记-15
    吴恩达深度学习课程笔记-14
  • 原文地址:https://www.cnblogs.com/re-is-good/p/13744733.html
Copyright © 2011-2022 走看看