【爬蟲】callback=jQuery+數字在爬蟲中如何模擬


原文鏈接:https://www.cnblogs.com/SnowPhoenix/p/15674155.html

問題描述

從瀏覽器查看請求信息的時候,我們會發現有些請求有這樣的特征:

  1. 包含一個類似於?callback=jQuery17209708769256472376_1639142208410&jsonp=jsonp&_=1639142206313的query;
  2. 返回的JSON數據jQuery17209708769256472376_1639142208410({"code":0,"message":"","data":{"uid":123}}),返回的字符串就是請求時url的callback調用了本身應該返回的數據;
  3. 簡單將這個url復制到Postman請求會失敗;

簡單搜索一下,可以知道這個是jQuery在進行跨域請求的時候利用jsonp進行處理造成的現象。注意幾點:

  1. 需要設置Referer頭,因為這是跨域請求,這也是為什么直接復制到Postman會失效的原因,Postman中加了Referer頭之后也能成功;
  2. _=1639142206313其實就是時間戳,沒什么好說的;
  3. 想要獲得原始的JSON數據,在獲得返回數據后,直接前后的JSONP的padding刪去即可;

但是這里有個問題,我們怎么模擬callbackjQueryxxxxx的生成呢?

參考

替代解決方案

既然我們知道這一套操作是跨域時的問題,那么我們的爬蟲直接不進行跨域請求即可。即

  • 刪去callbackjsonp_(寫時間戳的那個)這三個query;
  • 刪去Referer頭,或者將Referer頭設置為當前請求的url的域名;

當然,這樣的解決方案不是很優雅,雖然我js水平很爛,也沒學過jQuery,但我還是決定看看jQuery來看看這個這個jQueryxxxxx是如何生成的。

jQuery源碼

jsonpcallback來進行搜索,在jquery.js文件里可以看到這樣的代碼:

// Default jsonp settings
jQuery.ajaxSetup( {
	jsonp: "callback",
	jsonpCallback: function() {
		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) );
		this[ callback ] = true;
		return callback;
	}
} );

前面oldCallbacks.pop()應該是一個callback池,如果有空余的就不用產生新的了,不過我們需要關注的是新的是如何產生的:( jQuery.expando + "_" + ( nonce.guid++ ) )

繼續找expando,在jquery.js文件里能夠找到這樣的代碼:

jQuery.extend( {

	// Unique for each copy of jQuery on the page
	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),

	// Assume jQuery is ready without the ready module
	isReady: true,

	error: function( msg ) {
		throw new Error( msg );
	},

這就能夠知道了,再看我們示例的jQuery17209708769256472376_1639142208410,前面172,就應該是版本號1.7.2將非數字刪去的結果,Math.random()產生0-1間的浮點數,然后將小數點刪去,得到了09708769256472376,是十分符合的。

但是我通過多次在瀏覽器刷新,發現示例中的jQuery17209708769256472376_1639142208410結尾1639142208410顯然是個時間戳,而不像是guid++產生的結果。我目前看的源碼是3.x版本的源碼,回去看看1.x的源碼,在jquery1.9.1.js文件中可以看到相對應的代碼:

// Default jsonp settings
jQuery.ajaxSetup( {
	jsonp: "callback",
	jsonpCallback: function() {
		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
		this[ callback ] = true;
		return callback;
	}
} );

這里用的是ajax_nonce++,而往上找,就能找到它的定義:

ajax_nonce = jQuery.now(),

即為當前的時間戳。

python代碼

import time
import random

class Constant:
    jQuery_Version = "1.7.2"

def get_current_timestamp() -> int:
    return int(round(time.time() * 1000))

def jquery_mock_callback() -> str:
    "jQuery" + (Constant.jQuery_Version + str(random.random())).replace(".", "") + "_" + str(get_current_timestamp() - 1000)


免責聲明!

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



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