2023-Python实现烯牛数据采集

news2024/11/24 17:17:17

文章目录

  • 👉1、目标网址
  • 👉2、接口分析
  • 👉3、代码实现

【JS 逆向百例】 1/100

学习记录:哈喽~ 前面我们接触了一些JS逆向的数据获取,如果前面的百度,有道翻译和正方教务系统的登录加密你已掌握,说明我们已经入门啦。征程万里风正劲,重任千钧再出发。后面还有很长的路要走,让我们一起努力吧!今天的学习记录是关于烯牛数据网站的数据采集,这是一个很综合的例子, 它的返回数据和请求体都进行了加密。 这篇将详细记录调试步骤。

👉1、目标网址

主页:https://www.xiniudata.com/industry/newest?from=data
接口:https://www.xiniudata.com/api/search3/company/search_company_for_lib
接口:https://www.xiniudata.com/api2/service/x_service/person_company4_list/list_companies4_list_by_codes

👉2、接口分析

数据接口:
在这里插入图片描述
分析:
查看其各个参数,直接上搜索大法查找。先查看密文数据的解密。找合适的字符进行搜索定位,在这个接口里,我们尝试用返回的数据或请求体中的参数的关键字进行搜索大法时,发现都不好进行JS定位。对于此,我们可以搜索常用的关键字:decryptencryptJSON.parse搜索该接口的路径参数,还可以在Network 选项卡下,该请求的 启动器(Initiator) 列里看到它的调用栈,其调用顺序为由上而下:
在这里插入图片描述
鼠标悬停在上面可以看到这个接口调用栈的情况,并且可以找到触发的位置。一般情况下,我们直接双击就会自动的跳转到【源码 / Sources】面板并显示对应JS代码 (点击最上面的JS效果一样)。
进入后ctr + f 进行搜索,多试了几次,在用JSON.parse进行搜素时,发现了可疑代码。如下:
图1:
在这里插入图片描述
图2:
在这里插入图片描述
两处都很可疑,我们打上断点进行调试:
在这里插入图片描述
如上图:从左向右

  • Pause/Resume script execution:暂停/恢复脚本执行(程序执行到**下一断点**停止)。
  • Step over nextfunction call:执行到下一步的函数调用(跳到下一行)。
  • Step into next functioncall:进入当前函数
  • Step out of current function:跳出当前执行函数
  • Step: 一步步执行代码,遇到有函数调用,则进入函数。
  • Deactive/Activeall breakpoints:关闭/开启所有断点(不会取消)。
  • Pause on exceptions:异常情况自动断点设置。

调试发现,图1 为我们的目标JS:
在这里插入图片描述再对上面变量进行打印测试:
在这里插入图片描述
这里好像就是拿到密文后再对其解密的操作,所以我们继续跟下去:
在这里插入图片描述
在这里插入图片描述
分别跟进去:有d1,d2两个函数。到这里先分别打上断点进行调试观察:这里扣下JS,补齐参数进行数据测试:
在这里插入图片描述
我们将在右侧复制的d的值放进去测试时:数据是成功解密了,但他只有一条,emm~,难道我们找错啦?
观察前面几个接口返回的数据格式发现都如下图;
在这里插入图片描述
相当于这里的几个接口都是走的我们扣出的JS进行密文解密,那就直接测试:退出断点,观察我们要的公司数据接口解密是不是走的这里,如下图:
在这里插入图片描述
OK~复制进去测试:
在这里插入图片描述
发现没问题~到这里数据的解密已OK,那就去看看接口的参数有没有什么要处理的:
在这里插入图片描述
继续搜索大法:
发现还是在上面那个JS中找到可疑代码:2处
图1:
在这里插入图片描述
图2:
在这里插入图片描述
其实看到图2 的条件就知道它是不会执行的,但为了保险还是分别打上断点去调试:
调试后锁定图1:跟进发现这里的参数加密与密文解密一样也是走的一处,参数格式上也相似,所以我们像上面密文解密一样,退出掉其他的接口,让断点加载到我们的目标接口让他去生成加密参数:我们退出时不要点快了,看着右边的t,它是接口路径参数,等它到目标接口时就不要退出断点了,我们继续调试即可:
在这里插入图片描述
在此时,我们直接执行到下一步的函数调用进行观察:如果进入的循环太多,直接退出就OK。

在这里插入图片描述
发现它参数居然没变 !去多几次请求测试几次发现:网站数据是下拉分页加载数据,对于每一页的请求参数它是不变的,虽然它不变,但它不是我们所要的理想定值,因为不同的数据有不同的定值,那他就不可行,所以,我们还是要去进行加密分析的。
老办法,分别跟进JS进行调试:
在这里插入图片描述
边看边扣出JS进行调试:扣出来稍微改写一下(保证能调用能运行):先run ,梭一把,看看有什么反应:
在这里插入图片描述
不怕他报错,就怕它什么反应都不给你。看报错说: l is not defined ,这个就是差什么补什么,确认不是代码格式等问题后,就到对应的 JS 代码部分下进行调试:
在这里插入图片描述
OK~复制出来,补到我们扣下来的JS中去就好。

在这里插入图片描述
继续跟下去,发现有一个MD5加密:
JS实现MD5 :
安装:npm install crypto-js
导入:const crypto = require(“crypto”);
在这里插入图片描述
JS代码:

const  crypto = require("crypto");
function md5(res) {
    return crypto.createHash('md5').update(res).digest('hex')
}

到这里我们的请求体参数和解密已经分析的差不多啦,是可以进行数据的采集了,但是,这个网站的数据是下拉分页加载的,在调试它的分页请求数据时,下拉不了无法在请求数据。结束断点。正常下拉观察接口:开始我是去看它的page分页是怎么控制的,但没什么
在这里插入图片描述
每次下拉一页,就会更新两个接口。再回到断点:
在这里插入图片描述
发现一个参数:limit,看到它就要注意一下,一般是请求数据的限制,而他的值还为10,那更应该去看一下了。最后发现规律:https://www.xiniudata.com/api/search3/company/search_company_for_lib
这个接口请求加载出公司的编号,后面的详情接口https://www.xiniudata.com/api2/service/x_service/person_company4_list/list_companies4_list_by_codes依据前面的limt的值而返回多少条数据。多调试就OK,在调试的时候自己改变加载公司编号的接口limit的值,观察 n 的变化,再继续调试走到公司详情接口,会发现limt的值不同,返回的数据也不同。

👉3、代码实现

JS:
decrypt.js

const crypto = require("crypto");


var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="

var _p = "W5D80NFZHAYB8EUI2T649RT2MNRMVE2O"

// 参数加密
function ret(n) {
    var s = JSON.stringify(n)
        , l = JSON.parse(s);

    var r = 1
    var f = e1(e2(JSON.stringify(l.payload)))
        , p = sig(f);
    l.payload = f
    l.sig = p
    l.v = Number(r)


    return l


}

function e1(e) {
    if (null == e)
        return null;
    for (var t, n, r, o, i, a, c, u = "", s = 0; s < e.length;)
        o = (t = e.charCodeAt(s++)) >> 2,
            i = (3 & t) << 4 | (n = e.charCodeAt(s++)) >> 4,
            a = (15 & n) << 2 | (r = e.charCodeAt(s++)) >> 6,
            c = 63 & r,
            isNaN(n) ? a = c = 64 : isNaN(r) && (c = 64),
            u = u + _keyStr.charAt(o) + _keyStr.charAt(i) + _keyStr.charAt(a) + _keyStr.charAt(c);
    return u
}

function e2(e) {
    if (null == (e = _u_e(e)))
        return null;
    for (var t = "", n = 0; n < e.length; n++) {
        var r = _p.charCodeAt(n % _p.length);
        t += String.fromCharCode(e.charCodeAt(n) ^ r)
    }
    return t
}

function sig(e) {
    return md5(e + _p).toUpperCase()
}

function md5(res) {
    return crypto.createHash('md5').update(res).digest('hex')
}

function _u_e(e) {
    if (null == e)
        return null;
    e = e.replace(/\r\n/g, "\n");
    for (var t = "", n = 0; n < e.length; n++) {
        var r = e.charCodeAt(n);
        r < 128 ? t += String.fromCharCode(r) : r > 127 && r < 2048 ? (t += String.fromCharCode(r >> 6 | 192),
            t += String.fromCharCode(63 & r | 128)) : (t += String.fromCharCode(r >> 12 | 224),
            t += String.fromCharCode(r >> 6 & 63 | 128),
            t += String.fromCharCode(63 & r | 128))
    }
    return t
}


// console.log(ret(n))

encrypt.js

//密文解密
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
    , _p = "W5D80NFZHAYB8EUI2T649RT2MNRMVE2O";


function d1(e) {
    var t, n, r, o, i, a, c = "", u = 0;
    for (e = e.replace(/[^A-Za-z0-9\+\/\=]/g, ""); u < e.length;)
        t = _keyStr.indexOf(e.charAt(u++)) << 2 | (o = _keyStr.indexOf(e.charAt(u++))) >> 4,
            n = (15 & o) << 4 | (i = _keyStr.indexOf(e.charAt(u++))) >> 2,
            r = (3 & i) << 6 | (a = _keyStr.indexOf(e.charAt(u++))),
            c += String.fromCharCode(t),
        64 != i && (c += String.fromCharCode(n)),
        64 != a && (c += String.fromCharCode(r));
    return c
}

function d2(e) {
    for (var t = "", n = 0; n < e.length; n++) {
        var r = _p.charCodeAt(n % _p.length);
        t += String.fromCharCode(e.charCodeAt(n) ^ r)
    }
    return t = _u_d(t)
}

function _u_d(e) {
    for (var t = "", n = 0, r = 0, o = 0, i = 0; n < e.length;)
        (r = e.charCodeAt(n)) < 128 ? (t += String.fromCharCode(r),
            n++) : r > 191 && r < 224 ? (o = e.charCodeAt(n + 1),
            t += String.fromCharCode((31 & r) << 6 | 63 & o),
            n += 2) : (o = e.charCodeAt(n + 1),
            i = e.charCodeAt(n + 2),
            t += String.fromCharCode((15 & r) << 12 | (63 & o) << 6 | 63 & i),
            n += 3);
    return t
}

function decrypt(l) {
    var d = d1(l)
        , v = d2(d)
        , y = JSON.parse(v);

    return y
}

// console.log(decrypt(l))

Python

"""
CSDN: 抄代码抄错的小牛马
"""

import execjs
import requests


# 加密 公司的代码编号 的参数 payload  sig
def use_encrypt_JS1():
    # 读取js文件
    with open('./encrypt.js', encoding='utf-8') as f:
        js = f.read()

    # 通过compile命令转成一个js对象
    docjs = execjs.compile(js)
    n1 = {
        "payload": {
            "industry_ids": 921,
            "domestic": True,
            "corporate_locationIds": [],
            "tag_names": [],
            "corporate_rounds": [],
            "sort": 76006,
            "order": -1,
            "start": 0,
            "limit": 30
        }
    }
    print(type(n1))
    company_params = docjs.call('ret', n1)

    print('JS返回的num:', type(company_params))
    print('JS返回的num:', company_params)
    return company_params


# 加密 公司详情 的参数 payload  sig
def use_encrypt_JS2(company_code):
    # 读取js文件
    with open('./encrypt.js', encoding='utf-8') as f:
        js = f.read()

    # 通过compile命令转成一个js对象
    docjs = execjs.compile(js)
    # n1 = {
    #     "payload": {
    #         "codes": [
    #             "ZStack",
    #             "tingyukeji49",
    #             "fnmzhbjkjxgs",
    #             "xuehukeji37",
    #             "ExceedData",
    #             "xinhongpu",
    #             "jidatongxin",
    #             "xinmiershijue",
    #             "BQSJEZR0",
    #             "zhongkehaiwei"
    #         ]
    #     }
    # }
    n2 = {
        "payload": {
            "codes": company_code
        }
    }
    print(type(n2))
    details_params = docjs.call('ret', n2)

    print('JS返回的公司详情参数:', type(details_params))
    print('JS返回的公司详情参数:', details_params)
    return details_params


#  解密 获取的公司的代码编号
def use_decrypt_JS3(encrypt):
    # 读取js文件
    with open('./decrypt.js', encoding='utf-8') as f:
        js = f.read()

    # 通过compile命令转成一个js对象
    docjs = execjs.compile(js)

    # 调用function ==> 调用的方法名, 参数1  参数2
    decrypted = docjs.call('decrypt', encrypt)

    print('----------------------烯牛数据----------------------')
    print('解密后的公司数量数据::')
    # print(decrypted)
    print('要获取公司的数量为:', len(decrypted['data']))
    company_code = [i['company_code'] for i in decrypted['data']]
    print(company_code)
    # for i in decrypted['data']:
    #     print(i['company_code'])

    return company_code
    pass


#  解密 公司详情
def use_decrypt_JS4(details_data):
    # 读取js文件
    with open('./decrypt.js', encoding='utf-8') as f:
        js = f.read()

    # 通过compile命令转成一个js对象
    docjs = execjs.compile(js)

    # 调用function ==> 调用的方法名, 参数1  参数2
    end_data = docjs.call('decrypt', details_data)

    print('----------------------烯牛数据  详情----------------------')
    print('解密后的公司详情数据::')
    print(end_data)

    pass


# 获取请求 公司的代码编号 返回的密文
def get_data1(params):
    list_api1 = 'https://www.xiniudata.com/api/search3/company/search_company_for_lib'
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
        'cookie': 'btoken=LZKRG0M4XQJ6TXVDCZF4GLMBEG3UD3CA; hy_data_2020_id=18764a41e178-0110df9ab084b5-3a716f07-1846428-18764a41e1861f; hy_data_2020_js_sdk={"distinct_id":"18764a41e178-0110df9ab084b5-3a716f07-1846428-18764a41e1861f","site_id":211,"user_company":105,"props":{},"device_id":"18764a41e178-0110df9ab084b5-3a716f07-1846428-18764a41e1861f"}; utoken=QYT58WVGWTVX6IT6RPU3XPLLEKLNF999; username=YOU; export_notice=true; Hm_lvt_42317524c1662a500d12d3784dbea0f8=1681281817,1681350920,1681357499,1681430886; Hm_lpvt_42317524c1662a500d12d3784dbea0f8=1681438188'
    }

    lists = requests.post(url=list_api1, json=params, headers=headers).json()

    print(lists)
    # print(lists['d'])
    return lists['d']
    pass


# 获取请求 公司详情 返回的密文数据
def get_data2(details_params):
    list_api2 = 'https://www.xiniudata.com/api2/service/x_service/person_company4_list/list_companies4_list_by_codes'
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
        'cookie': 'btoken=LZKRG0M4XQJ6TXVDCZF4GLMBEG3UD3CA; hy_data_2020_id=18764a41e178-0110df9ab084b5-3a716f07-1846428-18764a41e1861f; hy_data_2020_js_sdk={"distinct_id":"18764a41e178-0110df9ab084b5-3a716f07-1846428-18764a41e1861f","site_id":211,"user_company":105,"props":{},"device_id":"18764a41e178-0110df9ab084b5-3a716f07-1846428-18764a41e1861f"}; utoken=QYT58WVGWTVX6IT6RPU3XPLLEKLNF999; username=YOU; export_notice=true; Hm_lvt_42317524c1662a500d12d3784dbea0f8=1681281817,1681350920,1681357499,1681430886; Hm_lpvt_42317524c1662a500d12d3784dbea0f8=1681438188'
    }

    lists = requests.post(url=list_api2, json=details_params, headers=headers).json()
    print('----------------------烯牛数据----------------------')
    print('公司详情密文::')
    print(lists)
    # print(lists['d'])
    return lists['d']
    pass


if __name__ == '__main__':
    params = use_encrypt_JS1()
    company_params = get_data1(params)
    company_code = use_decrypt_JS3(company_params)
    details_params = use_encrypt_JS2(company_code)
    details_data = get_data2(details_params)
    use_decrypt_JS4(details_data)

运行截图:
在这里插入图片描述
over~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/424374.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计组2.4——加法器的设计

计组&#xff1a;2.4算术逻辑单元异或门实现奇偶校验的原理串行加法器&&并行加法器并行加法器的优化算术逻辑单元 控制信号&#xff1a; 当M0时表示算术运算 当M1时表示逻辑运算 S0~ S3表示做什么运算&#xff0c;因此ALU可以表示16种算数运算和16种逻辑运算 Ai,Bi代表…

PL-VINS线特征处理部分源码阅读

PL-VINS线特征处理部分源码阅读1 linefeature_tracker2 三角化单目三角化双目三角化3 后端优化线特征状态量重投影误差本文主要阅读PL-VINS中引入线特征的代码实现&#xff0c;包括线特征表示方法&#xff08;Plcker参数化方法、正交表示法&#xff09;、前端线特征提取与匹配、…

遥感、GIS及GPS在土壤空间数据分析、适应性评价、制图及土壤普查中的应用

摸清我国当前土壤质量与完善土壤类型&#xff0c;可以为守住耕地红线、保护生态环境、优化农业生产布局、推进农业高质量发展奠定坚实基础&#xff0c;为此&#xff0c;2022年初国务院印发了《关于开展第三次全国土壤普查的通知》&#xff0c;决定自2022年起开展第三次全国土壤…

微信支付,JSAPI支付,APP支付,H5支付,Native支付,小程序支付功能详情以及回调处理

一.支付相关文档地址支付wiki&#xff1a;https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml支付api: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/index.shtml开发工具包(SDK)下载&#xff1a;https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay6_0.shtm…

靶机精讲之CTF4

主机发现 靶机193 端口扫描 服务扫描 80&#xff0c;25&#xff08;明确版本&#xff09;攻击面更大 web渗透 blog是交互式的程序 发现index可进行手动爆破&#xff08;地址包含&#xff09; http://192.168.10.193/index.html?page../../../../../../../../etc/passwd 无发…

雨水情测报系统+智慧水库大坝安全监测系统

解决方案 雨水情测报系统智慧水库大坝安全监测系统&#xff0c;系统主要由降雨量监测站、水库水位监测站、大坝安全监测中的渗流量、渗流压力和变形监测站及视频和图像监测站等站点组成&#xff0c;同时建立规范、统一的监测平台&#xff0c;集数据传输、信息共享、数据储存于…

Git简单使用~下载、安装、命令行使用、IDEA使用

文章目录一、Git下载二、Git安装三、命令行操作四、IDEA使用gitee4. 查看Gitee仓库一、Git下载 官网下载地址&#xff1a;Git (git-scm.com) 点击"Download for Windows"&#xff0c;跳转至详细下载页面。 以Windows64位安装版为例&#xff0c;点击"64-bit…

代码随想录算法训练营第42天| 416. 分割等和子集

代码随想录算法训练营第42天| 416. 分割等和子集416. 分割等和子集416. 分割等和子集 题目链接&#xff1a;416. 分割等和子集&#xff0c;难度&#xff1a;中等 【实现代码】 class Solution { public:bool canPartition(vector<int>& nums) {int sum 0;for (int…

抢鲜发布:Flutter 3.7更新详解

本文首发自「慕课网」(imooc.com)&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;CrazyCodeBoy|慕课网讲师 新年伊始&#xff0c;由 Flutter 3.7 正式版来「打头阵」&#xff01;我们与整个…

AI时代,重新理解阿里云

如果说&#xff0c;在数字化时代&#xff0c;阿里云给外界的标签是基于算力、数据等要素的基建角色&#xff0c;那么&#xff0c;在如今的智能化时代&#xff0c;基于自身强大的云计算能力和长期以往的AI技术积累&#xff0c;它的这种底座底色显然再一次被夯实、彰显。 作者|皮…

【Python_Scrapy学习笔记(六)】Scrapy框架基本使用流程

Scrapy框架基本使用流程 前言 本文中介绍 Scrapy 框架的基本使用流程&#xff0c;并以抓取汽车之家二手车数据为例进行讲解。 正文 1、Scrapy框架基本使用流程 创建爬虫项目&#xff1a;scrapy startprojecct 项目名 cd到项目文件夹&#xff1a;cd 项目名 创建爬虫文件&a…

PCB模块化设计06——HDMI接口PCB布局布线设计规范

目录PCB模块化设计06——HDMI接口PCB布局布线设计规范1、HDMI接口的定义2、HDMI管脚定义&#xff08;A型为例&#xff09;3、HDMI接口PCB布局要求4、HDMI接口布线要求PCB模块化设计06——HDMI接口PCB布局布线设计规范 1、HDMI接口的定义 高清晰度多媒体接口&#xff08;英文&…

Jina AI 创始人肖涵博士:揭秘 Auto-GPT 喧嚣背后的残酷真相

Auto-GPT 究竟是一个开创性的项目&#xff0c;还是一个被过度炒作的 AI 实验&#xff1f;本文为我们揭开了喧嚣背后的真相&#xff0c;并揭示了 Auto-GPT 不适合实际应用的生产局限性。 背景介绍 这两天&#xff0c;Auto-GPT&#xff0c;一款让最强语言模型 GPT-4 能够自主完成…

winform从入门到精通

环境 开发工具 visual studio 2019 16.11 community 基础框架 framework4.8 .net5需要开发工具小版本16.8以上 winform开发入门 windows桌面端应用开发框架 https://github.com/dotnet/winforms c#基础 partial class 创建项目 项目结构 引用&#xff1a;所依赖的系统库 …

编写猫咪相册应用 HTML

文章目录1. 标题元素标签2. p元素用于在网站上创建一段文本3. 注释4. 页面主要部分标识标签5. 通过使用img元素来为你的网站添加图片6. 使用锚点元素(a)链接到另一个页面7. 使用 section 元素将照片内容与未来的内容分开8. 无序列表(ul)元素&#xff0c;列表项(li)元素在列表中…

【C++11】final与override关键字和类的新功能

目录 一、final与override关键字 1.1 final 1.2 override 二、类的新功能 2.1 默认成员函数 2.2 类成员变量初始化 2.3 default关键字 2.4 delete关键字 注意&#xff1a;C专栏的所有测试代码都是在 vs2019 的环境下编译运行的 一、final与override关键字 这两个关键…

C++基础入门

C基础入门1.C认识1.1 第一个C程序1.1.1 创建项目1.1.2 创建文件1.1.3 编写代码1.1.4 运行程序1.3 变量1.4 常量1.5 关键字1.6 标识符命名规则2 数据类型2.1 整型2.2 sizeof关键字2.3 实型&#xff08;浮点型&#xff09;2.4 字符型2.5 转义字符2.6 字符串型2.7 布尔类型 bool2.…

Session、Cookie和Token

Session、Cookie和Token 参考&#xff1a;Session、Cookie、Token 【浅谈三者之间的那点事】 HTTP协议是一种无状态协议&#xff0c;即每次服务端接收到客户端请求时&#xff0c;都是一个全新的请求&#xff0c;服务器并不知道客户端的历史请求记录&#xff1b;Session和Cooki…

统信UOS + Windows双系统安装教程

全文导读&#xff1a;本文主要介绍了AMD架构下&#xff08;Intel/amd/兆芯/海光&#xff09;的机器同时安装Windows系统UOS系统的方法。 准备环境 1、下载好UOS系统镜像&#xff08;AMD64&#xff09;&#xff0c;下载地址&#xff1a;https://www.chinauos.com/resource/down…

第6章 接口、lambda表达式与内部类

文章目录Java与C异Java与C同接口接口概念接口与抽象类静态和私有方法默认方法解决默认方法冲突接口与回调&#xff08;不明白&#xff09;Comparator接口为什么有比较器Comparator接口实现步骤示例问题对象克隆为什么克隆浅拷贝&#xff1a;Object.clone方法的问题深拷贝数组的…