Python crawler simple js caso inverso
Dado que la tarea de aprendizaje requiere rastreadores para obtener datos, aprendí los conceptos básicos de los rastreadores de Python.
Pero cuando comencé a escribir el programa rastreador, había un problema y la solución se registra de la siguiente manera.
breve introducción
Requisitos: rastrear los datos de un sitio web de blockchain financiero https://www.oklink.com/btc/tx-list .
Hay un problema: los datos de rastreo primero deben enviar una solicitud para obtener los datos de respuesta. A través del análisis de la página web, sabemos que los datos que deben obtenerse provienen de la carga dinámica de ajax, por lo que elijo obtener los datos de respuesta enviando una solicitud a la URL de ajax. El parámetro en el encabezado de la solicitud de la solicitud es el problema principal que debe resolverse. Sin embargo, el encabezado de solicitud ajax de la solicitud a los datos contiene parámetros encriptados y que cambian dinámicamente similares a los siguientes
xapiKey:LWIzMWUtNDU0Ny05Mjk5LWI2ZDA3Yjc2MzFhYmEyYzkwM2NjfDI3MTk0ODY0MDUwNzA2Mjk=
Solución: Analice los archivos js relacionados solicitados por el navegador para obtener la función de generación x-apiKey y vuelva a escribirlo con python (no es necesario que vuelva a escribir, también puede ejecutar el código js llamando a la biblioteca js relevante en python).
1. Busque el paquete de datos ajax que contiene los datos necesarios
-
Abra el sitio web, abra la herramienta del navegador con la tecla de acceso directo Ctrl + shift + I, seleccione Red-> XHR, actualice la página web, puede ver que solo hay un paquete de solicitud:
-
Después de abrir, puede encontrar la URL solicitada:
https://www.oklink.com/api/explorer/v1/btc/transactionsNoRestrict?t=1608475589424&limit=20&offset=0
-
Explicación de los parámetros en la URL de ajax:
1. get请求 2. t=1608475589424 为 时间戳 3. limit=20 为每页的交易数量 4. offset=0 为每页的起始交易位置
-
Los parámetros contenidos en el encabezado de la solicitud se pueden encontrar a continuación:
-
X-apiKey es el parámetro encriptado en el encabezado de la solicitud y cambia cada vez que se actualiza.
x-apiKey: LWIzMWUtNDU0Ny05Mjk5LWI2ZDA3Yjc2MzFhYmEyYzkwM2NjfDI3MTk1ODY3MDA1MzExODU=
2. Posicionamiento de palabras clave a través de herramientas de navegador
- Busque Buscar en la parte superior derecha:
- Entrada: x-apiKey, se encuentran tres resultados, como se muestra en la figura
- Puede ver que el encabezado se incluye después del tercer archivo js, ábralo.
Aquí puede hacer clic en el siguiente {} para formatear el código:
- Presione la tecla de método abreviado Ctrl + F para encontrar la x-apiKey en el archivo js nuevamente y
ubique la x-apiKey, luego saque el segmento de código asociado:
function(t, e, n) {
"use strict";
n(115),
n(57),
n(20),
n(60);
function r(t, e) {
for (var n = 0; n < e.length; n++) {
var r = e[n];
r.enumerable = r.enumerable || !1,
r.configurable = !0,
"value"in r && (r.writable = !0),
Object.defineProperty(t, r.key, r)
}
}
var o = new (function() {
function t() {
!function(t, e) {
if (!(t instanceof e))
throw new TypeError("Cannot call a class as a function")
}(this, t),
this.API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab"
}
return function(t, e, n) {
e && r(t.prototype, e),
n && r(t, n)
}(t, [{
key: "encryptApiKey",
value: function() {
var t = this.API_KEY
, e = t.split("")
, n = e.splice(0, 8);
return t = e.concat(n).join("")
}
}, {
key: "encryptTime",
value: function(t) {
var e = (1 * t + 1111111111111).toString().split("")
, n = parseInt(10 * Math.random(), 10)
, r = parseInt(10 * Math.random(), 10)
, o = parseInt(10 * Math.random(), 10);
return e.concat([n, r, o]).join("")
}
}, {
key: "comb",
value: function(t, e) {
var n = "".concat(t, "|").concat(e);
return window.btoa(n)
}
}, {
key: "getApiKey",
value: function() {
var t = (new Date).getTime()
, e = this.encryptApiKey();
return t = this.encryptTime(t),
this.comb(e, t)
}
}]),
t
}())
, i = window.utils.ont
, c = Object.assign({
}, i);
c.interceptors.request.use(function(t) {
return t.url.indexOf("api/explorer/v1") > -1 && (t.headers.common["x-apiKey"] = o.getApiKey()),
t
});
e.a = c
}
3. Analice los archivos js relacionados para averiguar la implementación específica
Obviamente, x-apiKey es la variable o obtenida llamando a la función getApiKey ()
t.headers.common["x-apiKey"] = o.getApiKey()
1. función getApiKey ()
Encuentra la definición de la función:
key: "getApiKey",
value: function() {
var t = (new Date).getTime()
, e = this.encryptApiKey();
return t = this.encryptTime(t),
this.comb(e, t)
}
- La variable t es la hora actual y la variable e se obtiene llamando a encryptApiKey ();
- Después de pasar la variable t como parámetro a la función encryptTime (), se obtiene una nueva variable t;
- Finalmente, la variable ty la variable e se pasan como parámetros a la función comb () para obtener el valor de retorno final x-apiKey.
2. La función encryptApiKey ()
key: "encryptApiKey",
value: function() {
var t = this.API_KEY
, e = t.split("")
, n = e.splice(0, 8);
return t = e.concat(n).join("")
}
-
La variable t es una cadena fija, que se puede encontrar arriba
this.API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab"
-
La variable e es cortar la variable t para obtener cada carácter en t, y la variable n obtiene los primeros 8 caracteres en e, a saber:
"a", "2", "c", "9", "0", "3", "c", "c"
-
La variable final t es eliminar la n parte de e y agregarle n para obtener el nuevo valor de retorno de cadena
"-b31e-4547-9299-b6d07b7631aba2c903cc"
Este valor es el parámetro e de la función comb () en la función getApiKey ().
3. La función encryptTime ()
key: "encryptTime",
value: function(t) {
var e = (1 * t + 1111111111111).toString().split("")
, n = parseInt(10 * Math.random(), 10)
, r = parseInt(10 * Math.random(), 10)
, o = parseInt(10 * Math.random(), 10);
return e.concat([n, r, o]).join("")
}
-
t es la hora actual entrante (marca de tiempo de 13 bits), que se pasa ae después del procesamiento de la cadena;
-
Las variables n, r, o se generan números enteros aleatorios de 0 a 10, combinados con e para generar una nueva cadena sobre el tiempo actual y 3 números aleatorios, como
"2", "7", "1", "9", "4", "9", "2", "4", "3", "8", "8", "9", "9"]
Este valor es el parámetro t de la función comb () en la función getApiKey ().
4. Función peine ()
key: "comb",
value: function(t, e) {
var n = "".concat(t, "|").concat(e);
return window.btoa(n)
}
-
La variable n son los parámetros entrantes ty e después del procesamiento
2719492921233667|-b31e-4547-9299-b6d07b7631aba2c903cc
-
window.btoa (n) es la función de cifrado base64, obtenga el n cifrado
MjcxOTQ5MzI5ODc0MjA2NXwtYjMxZS00NTQ3LTkyOTktYjZkMDdiNzYzMWFiYTJjOTAzY2M=
-
Compare la x-apiKey en el encabezado de la solicitud del navegador
LWIzMWUtNDU0Ny05Mjk5LWI2ZDA3Yjc2MzFhYmEyYzkwM2NjfDI3MTk0ODc1Mzk0ODMwOTE=
Se puede ver que existen inconsistencias más obvias.
5. Encuentre la causa de la inconsistencia
-
Decodifica la x-apiKey obtenida en el navegador a través de base64
-b31e-4547-9299-b6d07b7631aba2c903cc|2719487539483091
-
Y la cadena antes del cifrado obtenida mediante el proceso anterior es
2719492921233667|-b31e-4547-9299-b6d07b7631aba2c903cc
-
Se puede observar fácilmente que la diferencia entre los datos antes del cifrado y los datos correctos generados por nosotros mismos es el orden de las cadenas antes y después de "|";
-
Después de modificar la secuencia, se obtiene el resultado correcto.
6. Vuelva a escribir el código js anterior en código Python
# 获取动态变化且加密的x-apiKey
def get_x_apikey():
# API_KEY固定字符串
API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab"
Key1 = API_KEY[0:8]
Key2 = API_KEY[8:]
# 交换API_KEY部分内容
new_Key = Key2 + Key1
# 获取当前时间,毫秒级
cur_time = round(time.time() * 1000)
# 处理获得的时间
new_time = str(1 * cur_time + 1111111111111)
# 生成三个0-9的随机整数
random1 = str(random.randint(0, 9))
random2 = str(random.randint(0, 9))
random3 = str(random.randint(0, 9))
# 再次处理时间字符串
cur_time = new_time + random1 + random2 + random3
# 将包含API_KEY和时间串的内容合并
this_Key = new_Key + '|' + cur_time
# 转码
n_k = this_Key.encode('utf-8')
# base64加秘
x_apiKey = base64.b64encode(n_k)
# 将加密后的x_apiKey返回
return str(x_apiKey, encoding='utf8')
Hasta ahora, este trabajo inverso de js se ha resuelto con éxito.