今日頭條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

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM