1.XHR/提取断点用法
当刷新页面时候,有大量请求,并且你无法定位参数信息的时候,或者参数被混淆无法搜到,可以用该方法,该方法是会捕获所有请求连接,然后我们通过连接过滤出自己想要的请求,然后在调用堆栈中去回溯跟踪。(一般都是抓取最后一次请求)
步骤很简单,点击加号,然后把url连接关键词丢进去,触发网络请求,这个时候符合要求的就会被断住。
2.条件断点
右键断点小蓝块,然后点击修改断点
选择条件断点
写上自己的表达式,为true的时候就会被断住,条件表达式更灵活,不局限于网络请求url过滤
3.日志断点
在需要断点的地方,进行日志输出,观测值
4.监听JS代理封装
function getEnv(proxy_array) {
for (let i = 0; i < proxy_array.length; i++) {
handler = `{
get: function(target, property, receiver) {
console.log('方法:get',' 对象:${proxy_array[i]}',' 属性:',property,' 属性类型:',typeof property,' 属性值类型:',typeof target[property]);
return target[property];
},
set: function(target, property, value, receiver){
console.log('方法:set',' 对象:${proxy_array[i]}',' 属性:',property,' 属性类型:',typeof property,' 属性值类型:',typeof target[property]);
return Reflect.set(...arguments);
}
}`;
eval(`
try{
${proxy_array[i]};
${proxy_array[i]} = new Proxy(${proxy_array[i]},${handler});
}catch(e){
${proxy_array[i]}={};
${proxy_array[i]} = new Proxy(${proxy_array[i]},${handler});
}
`);
}
}
//proxy_array = ['window', 'document', 'locaion', 'navigator', 'history', 'screen', 'history']
proxy_array = ['window','document']
getEnv(proxy_array);
一般补环境的时候可以用,但是你也可以直接在html页面中调用JS,浏览器会给你返回错误信息。
5.使用浏览器自动化工具补环境
如果有些环境实在难补,就直接补个浏览器。单例模式运行 也还好,慢2不了多少,就第一次初始化慢点。
from playwright.sync_api import sync_playwright
import os
import json
class BrowserEnv:
_instance = None # 单例模式实例
_browser = None # 浏览器实例
_page = None # 页面实例
def __new__(cls, *args, **kwargs):
# 单例模式实现
if cls._instance is None:
cls._instance = super(BrowserEnv, cls).__new__(cls)
return cls._instance
def __init__(self):
if not hasattr(self, '_initialized'): # 避免重复初始化
self._initialized = True
self._launch_browser()
def _launch_browser(self):
"""静默启动浏览器并初始化页面"""
self._playwright = sync_playwright().start()
self._browser = self._playwright.chromium.launch(headless=True) # 静默启动
self._page = self._browser.new_page()
def open_html_page(self, url):
"""打开指定的HTML页面或URL"""
if not url.startswith(("http://", "https://", "file://")):
# 如果是相对路径,转换为绝对路径并使用 file:// 协议
url = "file://" + os.path.abspath(url)
self._page.goto(url)
def close_browser(self):
"""关闭浏览器"""
if self._browser:
self._browser.close()
self._playwright.stop()
self._browser = None
self._page = None
def get_result(self, function_name, *args):
"""调用页面中的JavaScript函数并返回结果"""
args_with_quotes = [json.dumps(arg) for arg in args] # 自动处理字符串引号
expression = f"{function_name}({','.join(args_with_quotes)})"
result = self._page.evaluate(expression)
#print("JavaScript函数返回值:", result)
return result
def __del__(self):
"""析构函数,确保浏览器被关闭"""
self.close_browser()
调用
from BrowserEnv import BrowserEnv
# 初始化浏览器环境
browser_env = BrowserEnv()
# 打开一个HTML页面或URL
browser_env.open_html_page("./index.html")
sec_user_id ="MS4wLjABAAAAI3kAJk38MPTYlJA7qZxU9vdG3gK86MBqYDpWGO5Et1k";
# 调用页面中的JavaScript函数
result = browser_env.get_result("get_a_bogus", sec_user_id) # 假设页面中有 myFunction(a, b, c)
print(result)
# 关闭浏览器(可选,析构时会自动关闭)
browser_env.close_browser()
优化后的补环境版本plus
function getEnv(proxy_array) {
// 存储已代理的对象,避免重复代理
const proxiedObjects = new WeakMap();
// 创建handler工厂函数,为每个对象生成独立的handler
function createHandler(objName) {
return {
get: function (target, property, receiver) {
// 记录属性访问
const propType = typeof property;
const valueType = typeof target[property];
const valueInfo = target[property] === null ? 'null' : valueType;
console.groupCollapsed(`[GET] ${objName}.${String(property)}`);
console.log('对象:', objName);
console.log('属性:', property);
console.log('属性类型:', propType);
console.log('属性值类型:', valueInfo);
if (valueType === 'function') {
console.log('函数体:', target[property].toString());
}
console.groupEnd();
// 如果属性值是对象且未被代理过,则继续代理
const value = Reflect.get(...arguments);
if (value !== null && typeof value === 'object' && !proxiedObjects.has(value)) {
proxiedObjects.set(value, true);
return new Proxy(value, createHandler(`${objName}.${String(property)}`));
}
return value;
},
set: function (target, property, value, receiver) {
// 记录属性设置
const propType = typeof property;
const oldValueType = typeof target[property];
console.groupCollapsed(`[SET] ${objName}.${String(property)}`);
console.log('对象:', objName);
console.log('属性:', property);
console.log('属性类型:', propType);
console.log('旧值类型:', oldValueType);
console.log('新值类型:', typeof value);
console.log('新值:', value);
console.groupEnd();
return Reflect.set(...arguments);
},
// 添加其他trap以捕获更多操作
has: function (target, property) {
console.log(`[HAS] ${objName}.${String(property)}`);
return Reflect.has(...arguments);
},
deleteProperty: function (target, property) {
console.log(`[DELETE] ${objName}.${String(property)}`);
return Reflect.deleteProperty(...arguments);
}
};
}
for (let i = 0; i < proxy_array.length; i++) {
const objName = proxy_array[i];
try {
// 尝试获取全局对象
let obj;
if (typeof window !== 'undefined' && window[objName]) {
obj = window[objName];
} else {
obj = eval(objName);
}
// 如果对象存在且未被代理过
if (obj && !proxiedObjects.has(obj)) {
proxiedObjects.set(obj, true);
const handler = createHandler(objName);
const proxy = new Proxy(obj, handler);
// 将代理对象重新赋值
if (typeof window !== 'undefined') {
window[objName] = proxy;
} else {
global[objName] = proxy;
}
}
} catch (e) {
// 如果对象不存在,创建一个空对象并代理
const emptyObj = {};
proxiedObjects.set(emptyObj, true);
const handler = createHandler(objName);
const proxy = new Proxy(emptyObj, handler);
if (typeof window !== 'undefined') {
window[objName] = proxy;
} else {
global[objName] = proxy;
}
}
}
}
// 使用示例
proxy_array = ['window', 'document', 'location', 'navigator', 'history', 'screen'];
getEnv(proxy_array);