【爬虫】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)
posted @ 2021-12-10 22:53  SnowPhoenix  阅读(1785)  评论(0编辑  收藏  举报