资讯动态

Python网络资产收集实战:从域名发现到服务识别

发布时间:2026/10/20 19:10:34 来源:尧图企业网站定制
1. 从零开始为什么要用 Python 做资产收集先说句实在话很多人一听到“网络安全”“资产收集”这几个字第一反应是“这得先学会渗透测试吧”“没有 Kali 经验是不是玩不了”。真不是这样。资产收集这个方向恰恰是网络安全里最不依赖“攻击思维”的一个环节——它更像“整理房间”先搞清楚自己或客户到底有哪些电脑、哪些域名、哪些对外服务再谈后续的防护。而 Python就是干这件事最好用的工具之一。我在实际项目里见过不少场景某个公司买了几十个域名有的挂在主站名下有的散落在各个项目组手里还有的干脆是历史遗留没人记得。等到要做安全审计或者应急排查光是“这个 IP 到底属于谁”就能查半天。如果手动一个个翻效率极低而且容易漏。把这件事写成脚本自动化几小时就能把全量资产理清楚。这也是“资产收集”这个动作存在的根本意义——先知道“有什么”才知道“护哪里”。这篇内容适合谁三种人完全零基础刚学完 Python 基本语法想找个实战方向练手的人刚转行做安全运维、等保测评、红队支持需要快速上手资产梳理的从业者自己管着一堆服务器和域名想定期自动化盘点“家底”的非安全岗位开发。这篇博文不会教你怎么“攻击”任何系统只聚焦一个合规且日常的刚需用 Python 把分散的网络资产信息收集、清洗、汇总成一份清晰清单。所有技术点都是公开信息获取不需要任何“非授权”动作直接照着做就能落地。为了照顾零基础读者后面每个模块我都会先讲“为什么这么做”再讲“怎么实现”最后给出一段可直接运行的代码示例。你可以跟着抄也可以改造成适合自己的版本。2. 资产收集到底在收集什么先理清目标再动手2.1 核心对象域名、IP、端口、服务“网络资产”这个词听起来抽象拆开无非四类对象域名公司注册的所有域名包括主域名、子域名、甚至长得非常像主域的“仿冒域名”IP 地址域名解析出来的 IPv4/IPv6 地址也可能是独立采购的 IP 段端口某台服务器上开放了哪些 TCP/UDP 端口对应哪些网络服务服务指纹某个端口上跑的是什么软件、什么版本比如 Apache、Nginx、MySQL、Redis。资产收集的全部工作就是把上面四类信息梳理出来、相互关联、去重去噪形成一张“资产关系表”。例如域名子域名解析 IP开放端口服务指纹example.comwww.example.com203.0.113.1080,443Nginx 1.18.0example.comapi.example.com203.0.113.11443,8443Apache Tomcatlegacy.cnold.legacy.cn198.51.100.2322,3306OpenSSH_8.0 / MySQL有了这张表安全人员才能继续做漏洞扫描、暴露面评估、基线核查。没有资产清单的漏洞扫描就是闭着眼开枪——扫了半天也不知道扫的是谁的系统。2.2 收集方式分类主动与被动按数据来源资产收集分两类主动收集客户端主动发起请求比如 DNS 解析、端口探测、HTTP 请求。优点是数据准确缺点是会产生访问流量对目标系统有一定“触碰”。被动收集从搜索引擎、证书透明度日志、公开威胁情报平台拉取数据不在本地发起连接。优点是隐蔽、无打扰适合持续监控缺点是数据有时效延迟可能存在“看到的多是历史记录”。在“零基础快速上手”这个前提下我建议先用主动方式跑通流程因为逻辑简单、反馈即时——你发一个 DNS 请求马上拿到一个 IP这种正反馈对新手很重要。被动方式可以作为进阶扩展后续再接入。2.3 一个可落地的目标从域名到清单零基础入门不贪多把目标限定为输入一个主域名自动完成 子域名发现 → IP 解析 → 端口扫描 → 服务识别 → 结果汇总导出。再给它加一层实用约束所有过程只用公开、合法手段。比如用证书透明度查询子域名因为这是公开数据用 TCP 连接探测端口因为它本质上只等价于“敲一下门看有没有人应答”。这套流程足够覆盖日常 80% 的资产盘点需求。注意千万别把“资产收集”和“漏洞攻击”混在一起。端口扫描和指纹识别在授权范围内是合规的防护行为但对未授权的第三方系统执行同样操作性质就完全不同了。做安全先学“边界感”这是最基本的职业底线。3. 工具选型Python 生态里那些真正能用的库3.1 为什么不用现成扫描器非要写 Python市面上已经有非常成熟的资产收集工具比如各种开源指纹识别工具和漏扫框架。那为什么还要自己写 Python 脚本三条理由定制化现成工具的输出格式基本固定但每个公司的资产台账格式不一样写脚本可以灵活输出成自己需要的表格或 CSV集成能力实际项目里资产清单往往要落到集团 CMDB 或安全运营平台上Python 脚本可以直接调 API 推送数据这是单机工具做不到的学习价值把每个环节自己实现一遍你才能真正理解 DNS、TCP、HTTP 这些基础协议是怎么工作的。知其然也知其所以然遇到问题才有排查思路。3.2 核心库清单与选型理由对零基础读者我推荐一个“够用且不过度”的组合库名用途选型理由requests发送 HTTP 请求语法简单文档丰富适合新手dnspythonDNS 解析支持 A/AAAA/CNAME/MX/TXT 多种记录类型比 socket 更专业python-nmap端口扫描封装了 Nmap功能强但代码量少不用自己实现 TCP 探测细节concurrent.futures并发加速Python 自带不需要额外安装能大幅提升大批量解析速度pandas数据清洗与导出处理制表、去重、排序非常方便输出 Excel/CSV 天然支持有人可能会问为什么不用 Scapy 自己发包做端口探测因为那涉及原始 Socket 和协议头部构造对零基础朋友来说学习曲线太陡。python-nmap 底层虽然还是调 Nmap但至少对外接口友好先跑通流程再深入底层不迟。关于“并发”多说一句Python 的 concurrent.futures 在这种 IO密集型任务DNS 查询、HTTP 请求里效果极好因为大部分时间都在等待网络响应多线程可以显著压缩总耗时。它比 multiprocessing 更适合这个场景因为这里几乎不涉及 CPU 密集计算。3.3 环境准备与安装假设你已经装好 Python 3.9直接执行pip install requests dnspython python-nmap pandas openpyxl这里 openpyxl 是 pandas 导出 Excel 时需要的后端。如果公司内网用离线环境可以提前下载 wheel 文件再pip install xxx.whl离线安装。验证安装是否成功python -c import requests, dns.resolver, nmap, pandas; print(ready)如果能输出ready说明环境没问题可以开始写第一个脚本了。4. 手把手实现第一版资产收集脚本4.1 先搭骨架能跑的代码比完美的代码重要零基础最容易犯的错是想着“一步到位”“把架构设计完美再写”。我的建议完全不同先用 50 行代码跑通一个最简单的流程哪怕它漏洞百出再一步步迭代。这在工程上叫“垂直切片”对学习来说是最有成就感的方式。第一版脚本只做三件事接收输入的主域名通过 DNS 查询解析 A 记录拿到 IP打印结果。代码如下import sys import dns.resolver def resolve_a(domain): 解析域名 A 记录返回 IP 列表 try: answers dns.resolver.resolve(domain, A) return [str(rdata.address) for rdata in answers] except dns.resolver.NXDOMAIN: print(f[!] 域名 {domain} 不存在 (NXDOMAIN)) return [] except dns.resolver.NoAnswer: print(f[!] 域名 {domain} 没有 A 记录) return [] except Exception as e: print(f[!] 解析 {domain} 出错: {e}) return [] if __name__ __main__: if len(sys.argv) 2: print(用法: python asset_collect.py example.com) sys.exit(1) target sys.argv[1] ip_list resolve_a(target) if ip_list: print(f[] 域名 {target} 解析到以下 IP:) for ip in ip_list: print(f - {ip}) else: print([-] 未获取到 IP)这段代码里最值得细看的是dns.resolver.resolve的异常处理。第一次写脚本的人往往会忽略 DNS 查询的失败场景——域名可能不存在、可能没有 A 记录、可能临时解析超时每一种失败都应该有独立处理。这个习惯在安全工具开发里特别重要因为资产收集时你会遇到大量无效域名如果脚本动不动就崩溃那根本没法跑完一个真实规模的资产列表。4.2 子域名发现三种基础方法只有主域名还不够现实中绝大多数资产是散落在子域名上的。比如mail.example.com、vpn.example.com、gitlab.example.com每一个都可能是一台独立服务器。发现子域名有三种零基础可上手的方法字典枚举法根据常见子域名词根生成候选列表然后批量解析。示例词根www、mail、vpn、api、admin、oa、erp、portal、test、dev。这种方法的瓶颈在于字典质量本质上是“用规模换概率”。import dns.resolver def brute_subdomains(domain, wordlist_file): 基于字典枚举子域名 found [] with open(wordlist_file, r, encodingutf-8) as f: for line in f: sub line.strip() if not sub: continue full_domain f{sub}.{domain} try: answers dns.resolver.resolve(full_domain, A) ips [str(rdata.address) for rdata in answers] found.append((full_domain, ips)) except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): pass except dns.resolver.Timeout: pass except Exception: pass return found字典枚举胜在逻辑直观但速度很慢大量 DNS 请求且覆盖率有限。实际项目里我更推荐第二种。证书透明度日志查询法证书透明度Certificate TransparencyCT是公开的日志系统任何机构签发的 SSL/TLS 证书都会被记录在里面。通过查询 CT 日志可以拿到某个域名历史签发过的所有证书而证书里的“备用名称”SAN字段往往就暴露了子域名。这个方法被广泛应用因为它能发现很多字典枚举找不到的长尾子域名。用 Python 调第三方 CT 服务的接口代码非常简单import requests def subdomains_from_crt(domain): 从公开证书透明度日志获取子域名 url fhttps://crt.sh/?q%25.{domain}outputjson try: resp requests.get(url, timeout30) if resp.status_code ! 200: return [] data resp.json() subs set() for item in data: name item.get(name_value, ) for line in name.split(\n): line line.strip().strip(*.) if line.endswith(domain): subs.add(line) return list(subs) except Exception as e: print(f[!] CT 查询失败: {e}) return []注意strip(*.)这行证书里的域名经常以*.example.com形式出现泛解析记录不能算作具体子域名所以要把星号去掉只保留真实可用的子域部分。搜索引擎与威胁情报平台收集法通过搜索语法比如site:example.com或公开的 Passive DNS 数据库查询历史解析记录。这类方法通常需要 API key而且不同平台数据重合度很高作为补充手段即可零基础阶段可以先跳过。4.3 批量解析与并发加速如何从几分钟缩到几秒假设通过 CT 查询拿到了 1000 个子域名逐个串行解析 A 记录就算每个解析只要 0.1 秒总耗时也要 100 秒体感上明显卡顿。而且真实场景下还可能遇到网络抖动导致单次解析超时串行执行的短板会被无限放大。处理办法是引入线程池from concurrent.futures import ThreadPoolExecutor, as_completed def resolve_batch(domains, max_workers20): 批量并发解析域名返回 {域名: [IP列表]} results {} def _resolve(domain): return domain, resolve_a(domain) with ThreadPoolExecutor(max_workersmax_workers) as executor: future_map {executor.submit(_resolve, d): d for d in domains} for future in as_completed(future_map): domain future_map[future] try: domain_name, ips future.result() if ips: results[domain_name] ips except Exception as e: print(f[!] 处理 {domain} 时异常: {e}) return resultsmax_workers20是在“速度”和“可靠性”之间的一个平衡值。开太多线程比如 200会瞬间发出大量并发 DNS 请求有可能被 DNS 服务器限流反而产生超时。开太少又体现不出并发效果。实际使用中20 到 50 是我常用的范围。DNS 解析是 IO 密集型任务线程池在这里非常合适。如果是 CPU 密集型任务比如大规模数据加密解密那就应该考虑 multiprocessing 进程池但这里完全不需要。4.4 把解析结果数据化pandas 做去重和清洗拿到一堆域名和 IP 后直接打印出来看没什么问题但要落到正式台账上就不行了。真实场景里同一个 IP 可能被多个域名解析到同一个域名可能有多条 IP轮询负载均衡还可能混入一些无法解析的过期域名。清洗逻辑一定要有否则台账就是脏数据。用 pandas 处理非常直观import pandas as pd def build_asset_frame(domain_ip_map): 将域名-IP映射转换为 DataFrame 并去重排序 rows [] for domain, ips in domain_ip_map.items(): for ip in ips: rows.append({domain: domain, ip: ip}) df pd.DataFrame(rows, columns[domain, ip]) # 去重同一个域名IP的组合只保留一次 df df.drop_duplicates().reset_index(dropTrue) # 按 IP 排序方便后续与端口扫描结果关联 df df.sort_values([ip, domain]).reset_index(dropTrue) return dfsort 之后再输出 Excel你会发现清单的可读性大幅度提升同一个 IP 下的所有域名会排在一起一眼就能看出这台服务器上挂了哪些站点。导出 Exceldef export_excel(df, filenameassets.xlsx): 导出资产清单到Excel with pd.ExcelWriter(filename, engineopenpyxl) as writer: df.to_excel(writer, indexFalse, sheet_name资产清单) print(f[] 已导出 {len(df)} 条资产记录 - {filename})提示pandas 处理这种几千条级别的数据没有任何压力所以不要在“性能”上纠结优先保证逻辑清晰。等数据规模真的达到十万级以上再考虑分块处理或换数据库那是后话。4.5 端口扫描与服务识别给资产“挂上标签”有了域名和 IP 清单下一步就是看每个 IP 上开了什么端口、跑着什么服务。这一步的目的不是为了“找漏洞”而是为了快速识别暴露面——比如某个 IP 意外开放了 3306MySQL默认端口那很可能就存在数据库直接被外网访问的风险。零基础阶段用 python-nmap 是最稳的import nmap def scan_ports(ip_list, ports1-1000): 扫描指定IP列表的端口返回服务识别结果 nm nmap.PortScanner() results [] for ip in ip_list: try: nm.scan(hostsip, portsports, arguments-sV -T4) for host in nm.all_hosts(): if nm[host].state() up: print(f[] {host} 在线) for proto in nm[host].all_protocols(): for port in nm[host][proto]: port_info nm[host][proto][port] results.append({ ip: host, port: port, service: port_info.get(name, ), version: port_info.get(version, ), product: port_info.get(product, ) }) except nmap.PortScannerError as e: print(f[!] 扫描 {ip} 出错: {e}) return results参数解释-sV启用版本探测告诉 Nmap 不只要看端口开没开还要识别端口背后的服务版本-T4时序模板数字越大扫描越快。到 T4 已经比较激进适合内网环境。公网扫描不建议超过 T4容易被目标设备的防火墙限速或触发告警。注意权限Nmap 的-sV在某些系统上需要 root 权限因为它内部要发原始 Socket 报文。如果提示权限不足最省事的方法是给 Python 脚本的执行用户加 sudo但千万别为了方便随手chmod 777任何系统目录。真遇到权限问题优先检查nmap命令本身能不能以当前用户执行再考虑脚本层面怎么调整。这里必须多说一句端口扫描和指纹识别请严格限定在你自己有权限的资产范围。如果是公司内网固定 IP 段确保这是运维或安全部门授权的任务如果是个人学习环境用靶机或自己的服务器就好。工具本身没有属性用在哪里才是关键。5. 进阶增强让脚本从“能用”变成“好用”5.1 整体流程编排把各模块串成一个工具前面的模块是分开写的实战时当然不能一个个手动跑需要用入口函数把全流程串起来def main(): target input(请输入主域名: ).strip() if not target: print(域名不能为空) return print(f[*] 开始收集资产: {target}) # 第一步子域名发现CT 字典 print([*] 子域名发现中...) subs_from_ct subdomains_from_crt(target) subs_from_dict brute_subdomains(target, subnames.txt) # 常见的子域字典文件 all_subs set(subs_from_ct) | set([s[0] for s in subs_from_dict]) if not all_subs: print([-] 未发现子域名仅保留主域名) all_subs set([target]) else: all_subs.add(target) # 主域名本身也纳入资产 print(f[] 共发现 {len(all_subs)} 个域名) # 第二步批量解析 print([*] 批量解析 IP...) ip_map resolve_batch(list(all_subs), max_workers30) # 第三步生成资产表 print([*] 生成资产表...) df build_asset_frame(ip_map) export_excel(df, assets_domain_ip.xlsx) # 第四步端口扫描 print([*] 端口扫描中这一步耗时较长...) unique_ips df[ip].unique().tolist() port_results scan_ports(unique_ips, ports1-1000) port_df pd.DataFrame(port_results, columns[ip, port, service, version, product]) port_df port_df.drop_duplicates().reset_index(dropTrue) export_excel(port_df, assets_ports.xlsx) print([] 全部完成请查看生成的 Excel 文件。)这样整个流程就形成了一个完整的“输入域名 → 输出两张表”的工具。第一张表是域名-IP 的对应关系第二张表是 IP-端口-服务的对应关系。两份表交叉着看基本就能把一个小型公司的互联网资产梳理清楚了。5.2 加入爬虫逻辑从主页提取更多资产线索有一个很实用但容易忽略的细节很多公司主页的 HTML 源码里藏着JS文件、API 接口地址、静态资源域名。这些也是资产的一部分。给脚本加一个“主页分析”模块用 requests 抓首页再用正则把可疑域名捞出来import re def extract_domains_from_html(html, root_domain): 从网页源码中提取与根域名相关的子域名 # 匹配 http:// 或 https:// 开头的完整URL urls re.findall(rhttps?://([\w\.-]), html) subdomains set() for u in urls: # 只保留属于目标根域名的子域名过滤外站链接 if u.endswith(root_domain): subdomains.add(u) return subdomains代码简单但我建议在实际使用中加一层过滤条件只保留根域名下的二级、三级子域外部 CDN、统计脚本、广告联盟的域名大概率是干扰项手动去噪太费劲正则直接拦截更省事。这种“从 JS 和链接中提取子域名”的方法有个专业叫法——被动 web 信息收集。它的价值在于不主动去遍历路径只是分析目标自己“暴露”出来的线索。零基础阶段掌握这个思路后面学爬虫时衔接会很顺畅。5.3 结果可视化的几个简单方案Excel 表格用于归档没问题但如果你想给领导或同事直观地展示“我们有多少资产、分布在哪里”建议做一次可视化。零基础不推荐上复杂的数据可视化框架用以下三种轻量方案即可方案一pandas 直接输出统计图表pandas 内置了简单的绘图能力配合 matplotlib 输出柱状图或饼图import matplotlib.pyplot as plt # 统计每个IP上开放的端口数量 port_counts port_df.groupby(ip)[port].count().sort_values(ascendingFalse) port_counts.head(20).plot(kindbarh, figsize(10, 6)) plt.xlabel(开放端口数) plt.ylabel(IP地址) plt.title(Top20 开放端口数最多的IP) plt.tight_layout() plt.savefig(port_top20.png)方案二CSV 导入在线可视化工具把 pandas 导出的 CSV 直接扔进一些在线图表生成平台10 分钟就能出一张像样的仪表盘。这个方案的动作量最小。方案三加入地图坐标标记如果资产清单里有 IP 对应的物理位置归属比如通过公网 IP 库查询可以用 Python 的几个地理可视化库画一张“资产分布图”。这个相对复杂零基础可以放到二期再做。5.4 部署成定时任务让资产清单自动更新资产不是一成不变的——新业务上线会加域名老系统切走会清 IP。所以“收集一次”远远不够做成定时任务才是工程级的用法。Linux 环境下用 crontab 即可实现周期性执行。假设脚本是/opt/asset/asset_collect.py输出目录是/opt/asset/output/0 2 * * 1 cd /opt/asset python asset_collect.py example.com logs/collect.log 21含义每周一凌晨 2 点执行一次资产收集日志追加输出到日志文件。Windows 用户则可以用任务计划程序触发条件设为“每周”操作里指定 Python 解释器路径和脚本路径即可。经验之谈定时任务跑了几周后你会慢慢积累一份“历史资产变化记录”。这比单次的资产清单更有价值——通过对比前后两次结果你能发现哪些 IP 新开放了高危端口、哪些域名的新增了解析这些往往是安全事件的早期信号。所以建议每次运行都保留历史归档文件不要覆盖式输出。6. 踩坑记录与排查建议6.1 常见问题速查表我把实际跑脚本时最容易碰到的几个问题整理成表遇到问题可以快速对照问题可能原因解决办法DNS 查询大多数超时线程开太多DNS 服务器限流降低max_workers到 10~20或改用备用 DNS 服务器dns.resolver报NoNameservers本地网络 DNS 配置异常检查本机/etc/resolv.conf或 Windows 的 DNS 设置Nmap 报You cannot use -sV and -O参数冲突去掉-O参数-sV和系统探测不能在同一次扫描中混用导出的 Excel 打开乱码编码问题CSV 没加 UTF-8 BOMExcel 导出直接用 pandas 的to_excel不要经过 CSV 中转CT 查询返回大量外站域名目标域名存在泛解析在结果过滤时检查通配符并用 DNS 二次确认是否真实解析脚本在内网无法访问外网 API内网隔离策略把 CT 查询等外网依赖模块做开关控制离线时自动跳过6.2 经验一IP 归属信息别过度依赖但一定要做交叉验证在资产收集实践里我见过不少新人拿到一个公网 IP就急着用 IP 归属库查询。查出来显示“某云厂商”就认定这是某云上的资产。这个判断逻辑非常脆弱——大厂的 IP 段可能被二次分配、IP 归属库可能半月以上不更新、CDN 节点和回源 IP 的区别更不是新手一眼能分辨的。正确的做法是交叉验证把 DNS 解析结果、证书信息、网页返回的 Server 头、ICP 备案信息国内场景等多个维度拼在一起看。比如域名解析到了云厂商的 IP但证书上写的组织名不是你正在排查的目标那就应该打上“疑似第三方托管”的标记而不是直接纳入或排除。资产管理要求的是准确率不是速度。6.3 经验二日志管理比脚本本身更重要新手阶段大家都会忽略日志。我一开始也是如此——脚本输出到控制台跑完就完了。等到需要追溯“三天前查到的那个 IP 到底什么时候开始开放的”发现自己根本没留日志只能重跑一遍。而且重跑的结果可能和当时不一样因为目标资产本身是动态的。所以建议从第一天就养成习惯每次运行生成独立的日志文件文件名带时间戳关键步骤成功解析、扫描完成、导出成功都写日志异常情况不仅打印到屏幕也写入日志方便后续分析。实现方式很简单Python 原生的 logging 模块就够了import logging logging.basicConfig( filenamefasset_collect_{datetime.now():%Y%m%d_%H%M%S}.log, levellogging.INFO, format%(asctime)s [%(levelname)s] %(message)s )6.4 经验三别人给的字典不一定适配你的场景网上能下载到一大堆“最强子域字典”但实际效果往往差强人意。原因很简单不同公司的命名习惯完全不同外企可能用login而不叫admin电商公司可能有m移动端但没有wap金融企业喜欢用ebank而不是online。调优方法也不神秘把第一次跑出来的有效子域名存成一份“成功字典”针对目标行业补充词根后面每次新增域名时都会越用越准。这是让工具“长在自己项目里”的关键一步。7. 向后延伸这套技能还能用在哪很多人担心“学了资产收集是不是就只会这一个点”。其实不是这套流程里涉及的技术能力往哪个方向延伸都成立DNS 原理与解析流程做网络排障、域名迁移、CDN 配置时都适用并发与异步思维用 ThreadPoolExecutor 处理“大量小任务”的经验写爬虫、做数据采集时通用数据清洗习惯pandas 处理脏数据的能力做数据分析一样能复用定时任务与自动化部署crontab 管理、日志输出、异常重试这是运维自动化的基本功。再往上层走资产收集和配置管理数据库CMDB、安全基线与合规检查平台、攻击面管理平台都是天然衔接的。很多公司专门有岗位叫“安全运营工程师”日常工作里很大一部分就是维护资产台账、梳理暴露面、推动下线老旧系统。你从资产收集切入等于一只脚已经踏进了这个岗位的门槛。至于更进阶的方向比如通过网关日志和流量镜像做被动资产发现、利用威胁情报平台做外网暴露面监控、结合身份管理系统关联资产负责人——这些本质上都是在“资产数据”这个地基上盖高楼。地基打牢了后面盖几层楼都不会晃。个人体感资产收集是一个“越做越熟、越熟越快”的领域而且它的价值是复利的。第一次做可能花了整整一天才手动整理出来但脚本一旦跑起来、跑顺了后面每周只需要五分钟看结果推送。你投入的那几个小时会以每周五分钟的代价持续回本。这也是我最终推荐从 Python 入门资产收集的根本理由——入门周期短反馈速度快长期收益稳定。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑