恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

FofaViewer批量搜索爬虫实战:FOFA API调用与Python资产发现

  • 首页
  • 资讯中心
  • /
  • FofaViewer批量搜索爬虫实战:FOFA API调用与Python资产发现

相关资讯

ICEM CFD二维非结构网格装配与拓扑控制实战指南 2026/10/4 8:38:53
基于MATLAB/Simulink的MIMO系统仿真建模与性能分析 2026/10/4 8:38:53
Vue2与Vue3双轨学习操作系统:从响应式原理到工程落地 2026/10/4 8:38:53

最新资讯

ZLibrary 类项目合规避坑指南:从技术实现到法律风险的全方位梳理
基于 Spring Boot 的在线培训考试管理系统设计与实现
基于 Spring Boot 的服饰服装租赁平台设计与实现
原创性如何?8款AI写作辅助软件榜单,毕业答辩稳了!
OpenRig:多智能体编程缺的那层控制平面
AI工业控制系统架构与边缘计算部署实战

今日推荐

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本周热门

MR25H40CDF + PIC18F65K40:工业记录仪高可靠存储实战
基于STM32的数控恒压恒流电源设计:从硬件到PID调参全解析
LT9211 MIPI重定时器原理与双路扇出实战指南

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

FofaViewer批量搜索爬虫实战:FOFA API调用与Python资产发现

发布时间:2026/10/4 8:38:53
FofaViewer批量搜索爬虫实战:FOFA API调用与Python资产发现 简介FofaViewer又称“佛法”是一款基于FOFA搜索引擎的批量搜索爬虫工具面向网络安全研究人员、渗透测试工程师与资产测绘人员用于高效获取互联网资产信息并支撑漏洞排查与风险评估。资源包共2个文件包含可执行的fofaviewer.jar和用于配置API Key、搜索参数与输出选项的config.properties压缩包大小32.69MB解压后即可在JDK8环境下运行。工具支持关键字、域名、IP范围等条件批量检索结果可导出为CSV或Excel便于后续分析GUI界面直观也支持定时任务持续监控资产变化。资源已吸引2015人学习下载适合需要快速定位指定类型网络资产的读者可直接获得开箱即用的FofaViewer 1.1.11版本及相关配置文件节省自行编译与配置时间。1. FofaViewer 佛法批量搜索爬虫工具不登录网页端也能把千条资产记录拉回本地做资产暴露面排查的时候最烦的还不是查询怎么写而是查完以后一堆结果没法批量整理。FofaViewer 这个被社区叫作“佛法”的搜索爬虫工具本质上是把 FOFA 这个网络空间测绘平台的查询能力搬到了本地图形界面里你填一条查询语法它替你翻页、聚合、导出几分钟把几百上千条资产记录落成表格。标题里的“佛法”没有别的含义就是 FofaViewer 的音译叫法安全从业者和资产管理员习惯这么喊。本文要做的是把这套批量搜索爬虫的底子拆开FOFA 查询语法怎么组织、API 参数怎么传、翻页去重怎么处理、哪些细节会让结果悄悄作废。适合正在做资产台账、需要周期性复盘公网暴露面的读者也适合想自己用 Python 拉 FOFA 数据而不是依赖 GUI 的工程师。2. 先看懂 FofaViewer 手里的牌FOFA 查询语法、API 配额与工具定位用 FofaViewer 之前得先花十分钟把 FOFA 的查询规则和 API 配额搞清楚。很多人一上来就在搜索框里输一串自然语言得到一堆乱七八糟的结果还以为是平台数据不准。其实 FOFA 的查询是靠字段名、运算符和括号组合出来的语法写对了结果才可能对。2.1 FOFA 查询句的常用字段清单title、body、cert、icon_hash 怎么组合FOFA 的查询语句由“字段值”这样的条件组成多个条件之间用并且、||或者连接括号可以用来分组。我最常用的几个字段如下字段名作用常见用法示例title匹配页面标题title管理系统body匹配页面正文 HTML 内容bodyphpmyadminhost匹配域名或 IPhostexample.comip匹配 IP 地址ip1.2.3.4port匹配端口port8080protocol匹配协议protocolhttpscert匹配 SSL 证书中的组织或域名certexample.combanner匹配服务指纹信息bannernginxicon_hash匹配 favicon 图标哈希icon_hash-123456789status_code匹配 HTTP 状态码status_code200country匹配国家或地区编码countryCN组合查询时不要盲目堆条件我一般习惯从“最不可能误报”的字段出发。比如想找某个业务系统的后台登录页先写title后台登录如果发现同一套模板被大量仿站使用就再补一个 hostexample.com或 cert二级条件收紧。用||时要注意括号写title登录 (hosta.com || hostb.com)搜索引擎和脚本解析都是靠括号决定优先级的少写括号很容易查出来一堆无关数据。2.2 FofaViewer 运行机制一句话说清它和 FOFA API 的关系FofaViewer 不是自建了一个搜索引擎它只是一个“壳”真正的数据来自 FOFA 的官方 API。你在 GUI 里输入查询句工具在后台把这句话编码后提交给 FOFA 接口拿到 JSON 后渲染成表格。也就是说FofaViewer 本身就是一个已经封装好的“搜索爬虫”它替你省掉了自己写请求、自己解析 JSON 的功夫。理解了这层关系就明白了为什么它会有配额和频率限制。FOFA 作为一个网络空间测绘平台对每个账号的 API 调用次数、单次返回条数是有限制的。FofaViewer 界面里能搜出多少条背后对应的是你账号的授权范围不是工具本身没有上限。这也解释了为什么同一句话在网页端和客户端搜出来的数量偶尔会有差别网页端分页逻辑和 API 翻页逻辑不完全一致。所以在网上搜“FofaViewer 怎么用”核心问题其实就是“FOFA API 怎么调”。把网络爬虫的原理稍微迁移一下就通了爬虫先拿到一个数据源的请求入口然后按分页循环请求最后把响应结果解析落盘。FOFA 的入口就是search/all接口分页靠page与size参数返回的 JSON 里带着results数组整个过程和普通 requests 爬虫没有本质区别。2.3 用 GUI 还是自己写 Python 爬虫三种落地方式对比我自己既用 FofaViewer 做过快速排查也写过 Python 脚本做周期巡检两种方式适用场景不一样建议按下面这张表选维度FofaViewer GUIPython 脚本直连 API脚本 定时任务上手门槛低下载即可用中需要会 requests 和 JSON中高需要部署环境批量任务处理手动逐条粘贴查询循环执行查询列表全自动定时跑翻页与去重内置翻页去重需手工自己写循环和去重逻辑自动翻页并落库结果导出内置导出表格自定 CSV/JSON 字段每天定期生成新文件适合场景临时查一次、人工分析一次跑几百个查询长期资产变化巡检如果你的需求是“今天查一下某品牌设备有多少暴露”打开 FofaViewer 点几下就够了。如果需求是“每周一把全部公网资产过一遍差异部分自动拉出来”那 GUI 撑不住必须自己写脚本跑 API。这篇文章后面所有代码都按第二种方式写读完你会发现它其实就是把 FofaViewer 的界面操作翻译成了几十行 Python。3. 用 Python 跑通 FofaViewer 同款批量搜索API 调用、翻页去重与任务列表这一章是全文最值得动手的部分。我会从申请密钥开始一步一步把 FOFA 搜索接口调通再扩展成能翻页、去重、批量执行的爬虫脚本。所有代码都基于 requests没有额外依赖复制下来改三个变量就能跑。3.1 准备 API 密钥和基础调用requests base64FOFA API 的身份凭证是邮箱和 API 密钥登录 FOFA 后在个人中心可以生成。密钥的作用范围就是你这个 FOFA 账号的查询权限和积分配额别把它写进前端页面或者提交到公开仓库。调用接口前还存在一个容易踩的步骤查询句必须做 base64 编码接口通过qbase64参数接收。下面是最小可运行版本的请求头和数据准备代码import base64 import requests email your_accountexample.com key your_api_key # 这条语句和你在 FofaViewer 搜索框里填的完全一样 query title管理系统 countryCN # FOFA 要求查询句先 base64 编码注意是 UTF-8 字节编码后再转字符串 qbase64 base64.b64encode(query.encode(utf-8)).decode(utf-8) resp requests.get( https://fofa.info/api/v1/search/all, params{ email: email, key: key, qbase64: qbase64, fields: host,ip,port,protocol,domain,title, size: 100, page: 1, full: false, }, timeout30, ) body resp.json() print(body.get(error), body.get(errmsg))这里params字典里的参数说明email和key是身份凭证qbase64是查询句的编码结果fields决定返回结果里每一行携带哪些字段顺序其实就是后面results数组里每行元素的顺序size是单页最大返回条数page是页码full表示是否返回完整字段集合普通字段查询填false就行省流量也省解析时间。这个最小调用发出去以后如果error为false说明证书没问题可以继续往下做批量逻辑。3.2 最小可运行脚本单条查询、第一页结果解析拿到上面请求的返回体之后下一步要处理results字段。它不是一个字典列表而是一个二维数组每一行是一个列表列表里每个元素的顺序对应fields参数。下面把解析逻辑补全并且对行长度做保护避免字段不足时报错中断import base64 import requests email your_accountexample.com key your_api_key fields host,ip,port,protocol,domain,title query title管理系统 countryCN qbase64 base64.b64encode(query.encode(utf-8)).decode(utf-8) resp requests.get( https://fofa.info/api/v1/search/all, params{ email: email, key: key, qbase64: qbase64, fields: fields, size: 100, page: 1, full: false, }, timeout30, ) body resp.json() if body.get(error): print(请求失败服务端返回, body.get(errmsg)) else: rows body.get(results, []) print(第一页返回行数, len(rows)) for row in rows: # 假设行长度与 fields 数量一致但出于健壮性做一次判断 if len(row) 6: continue host, ip, port, protocol, domain, title row print(f{host} | {ip}:{port} | {protocol} | {title})注意这里我用print逐行打印是为了先验证数据链路真实使用时你会希望把结果追加进列表。还有一个细节requests.get里的params会自动处理 URL 编码不要自己拼 URL 时再把 base64 字符串二次编码否则服务端解出来是乱码查询数直接变成 0。第一次跑如果返回结果为 0优先检查这条。3.3 循环翻页拉全量结果并按 ip:port 去重FOFA 的一次查询命中可能是几万条而 API 单页最多返回有限数量的记录所以要翻页。翻页终止条件不是“下一页没数据”而是当前页码乘以单页大小达到服务端返回的总命中数。去重逻辑也在这一步一起做否则后面导出的表没法直接用。import base64 import time import requests email your_accountexample.com key your_api_key fields host,ip,port,protocol,domain,title query title后台登录 countryCN qbase64 base64.b64encode(query.encode(utf-8)).decode(utf-8) def fetch_all(query_b64, max_pages20): seen set() result_rows [] page 1 while page max_pages: resp requests.get( https://fofa.info/api/v1/search/all, params{ email: email, key: key, qbase64: query_b64, fields: fields, size: 100, page: page, full: false, }, timeout30, ) data resp.json() if data.get(error): print(f第 {page} 页请求失败{data.get(errmsg)}) break rows data.get(results, []) if not rows: break for row in rows: if len(row) 6: continue host, ip, port, protocol, domain, title row # 同一台服务器可能被多个域名关联用 ip:port:protocol 做资产主键 dedup_key f{ip}:{port}:{protocol} if dedup_key in seen: continue seen.add(dedup_key) result_rows.append(row) total data.get(size, 0) print(fpage{page}本页 {len(rows)} 条累计去重后 {len(result_rows)} 条接口总命中 {total}) # 当前页已经覆盖完所有结果退出 if page * 100 total: break page 1 time.sleep(1.5) # 每页间隔 1.5 秒防触发访问频率限制 return result_rows rows fetch_all(qbase64) print(最终有效资产条数, len(rows))这段代码里最值得解释的是dedup_key的选取。FOFA 里同一个ip:port可能会同时出现在多个域名记录下比如一台服务器同时跑着 a.example.com 和 b.example.com 两个站点两条记录的 host 字段不一样但 ip 和端口完全一样。如果以 host 去重一个服务会被算成多个资产资产底账就直接虚胖了。换成ip:port:protocol后只要协议和端口相同就认为是一个资产这是做资产归一的通用做法。page * 100 total是翻页终止条件这里的 100 就是size参数。如果你把size改成 50终止条件里也要改为page * 50 total。很多脚本跑着跑着停不下来的原因就是把size改了但终止条件没同步改。3.4 批量任务列表多条查询排队执行控制请求节奏现实使用中不会只搜一句话而是准备一批查询句对应不同业务系统或设备类型。把查询句放进列表循环执行即可但要注意任务之间的间隔要比页间隔更宽松避免同一个密钥短时间请求次数过多被临时限制。import base64 import time import requests email your_accountexample.com key your_api_key fields host,ip,port,protocol,domain,title tasks [ title后台登录 countryCN, bodythinkphp countryCN, port8080 protocolhttp countryCN, ] def fetch_all(task_query, max_pages10): qbase64 base64.b64encode(task_query.encode(utf-8)).decode(utf-8) seen set() result_rows [] page 1 while page max_pages: # 请求与翻页逻辑同上一节这里省略重复的请求代码 resp requests.get( https://fofa.info/api/v1/search/all, params{ email: email, key: key, qbase64: qbase64, fields: fields, size: 100, page: page, full: false, }, timeout30, ) data resp.json() if data.get(error): print(f任务查询失败{data.get(errmsg)}) break rows data.get(results, []) for row in rows: if len(row) 6: continue host, ip, port, protocol, domain, title row dedup_key f{ip}:{port}:{protocol} if dedup_key in seen: continue seen.add(dedup_key) result_rows.append(row) total data.get(size, 0) if page * 100 total: break page 1 time.sleep(1.2) return result_rows all_results {} for idx, q in enumerate(tasks, start1): print(f任务 {idx} 开始{q}) rows fetch_all(q) all_results[q] rows print(f任务 {idx} 完成有效条数 {len(rows)}) time.sleep(2) # 任务之间留足间隔 print(全部任务执行完成共, len(tasks), 组查询)任务间隔和页间隔是两个不同的控制点页间隔控制的是同一个查询翻页时的请求密度任务间隔控制的是多个不同查询之间的间隔。我一般把页间隔设为 1 秒以上任务间隔设为 2 秒以上。习惯差别不大但至少别写成 0否则很容易撞上接口限流撞一次就得等几分钟才能恢复。4. FofaViewer 批量搜索爬虫避坑5 个影响结果完整性的真实故障代码能跑通只是第一步真正让爬虫“翻车”的往往是一些小细节。以下 5 个问题是我在实际使用 FofaViewer 和自写脚本过程中真实遇到过的每一条都按“现象 → 原因 → 解决”的顺序记录。4.1 触发 API 频率限制请求间隔和并发度反复翻车现象脚本前几百条请求一切正常突然返回error: trueerrmsg里出现类似访问过频的提示或者直接收到 HTTP 429 状态码。再过几分钟又自动恢复但任务已经中断了。原因FOFA API 对单个密钥有请求频率限制尤其是把页间隔设成 0 或者同时开了多个线程时短时间内请求数会陡增服务端的限流策略就会触发。解决把页间隔控制在 1 秒以上不写多线程并发保持单线程顺序翻页。脚本里加上指数退避重试遇到失败先停 2 秒再重试连续失败则暂停 10 秒。可以在fetch_all函数里对响应状态做统一判断凡是返回非 200 或error为true的请求都先停一下再做下一轮。批量任务数量多时把任务拆成几个批次每个批次之间休息 5 到 10 分钟更稳妥。4.2 查询句从网页复制到脚本后结果对不上分页和 full 参数谜团现象在 FofaViewer 图形界面里搜出一千条结果用同样的查询句跑 Python 脚本只拿到一百条而且怎么翻页都只有一百条。原因API 的size参数默认值是 100如果不主动设置单页返回上限就是 100。图形界面内部自动翻页并累加结果你不会感知到有分页这回事。另一个常见原因是查询句里写了fulltrue但返回数据仍然缺字段导致部分结果被解析逻辑过滤掉了。解决手动指定size并按循环翻页逻辑取完所有页。翻页终止条件用接口返回的size字段不要用“某页结果为空”判断因为最后一页可能刚好返回零条但前面还有数据。字段方面需要body、header这类完整内容时确认full取值正确否则解析出来的行长度不够去重时容易丢数据。4.3 host 重复、ip 端口重复不做归一化就无法形成资产台账现象导出的 CSV 里同一个 IP 和端口出现几十行每行只是域名前缀不同。几千行数据人工筛下来实际资产只有几百个台账根本没法用。原因FOFA 把同一服务的多个域名关联分别存储host字段不同但ip、port、protocol一致。只按 host 去重重不掉这些。解决在脚本里构造dedup_key ip:port:protocol作为去重主键保留第一行出现的域名后续相同主键的域名追加到一个列表里而不是直接丢弃。这样既保证资产数量准确又不丢域名映射关系后续做资产关联分析时有更多线索。4.4 icon_hash 指纹撞车批量识别时出现过多无关资产现象用icon_hash搜某个系统图标返回结果里混入了大量其他厂商的资产看起来完全不像同一类系统。原因icon_hash是基于 favicon 图标内容计算的哈希值同一个前端框架、同一套默认图标会被大量站点复用所以哈希结果相同不代表是同一类资产。还有一类情况是同一系统不同版本图标存在细微差异哈希值反而对不上导致漏报。解决icon_hash不要单独作为查询条件要和title、body、cert等字段组合使用。比如先按某个系统的典型图标哈希过滤一遍再叠加一个 title某系统条件把无关站点排除掉。这个过程有点玄学建议先用小批量数据人工抽查一遍看看噪声比例再决定是否复用这条查询。4.5 中文结果乱码Windows 下控制台和 Excel 的双重编码问题现象Python 脚本在终端打印结果时报UnicodeEncodeError或者生成的 CSV 在 Excel 里打开后全是乱码但用记事本看又正常。原因Windows 控制台默认字符集是 GBKPython 在打印非 ASCII 字符时会因为编码不匹配报错。Excel 打开 CSV 文件时默认按系统编码解析未带 BOM 的 UTF-8 文件会被误判成其他编码。解决脚本开头执行sys.stdout.reconfigure(encodingutf-8)强制控制台按 UTF-8 输出。写 CSV 文件时使用encodingutf-8-sig这个编码会写入 BOM 头Excel 打开后中文能正常显示。另外只要不是硬编码字段名数据里的中文标题在脚本内部都走 UTF-8 链路不要手动再编码一次。5. 把批量搜索爬虫沉淀成资产底账统一格式、定时巡检和一次真实教训脚本能稳定跑出数据以后下一步就是把它变成长期能用的资产底账而不是每次手工重新执行一次。这一章的三个落地动作能把前面所有代码串成一个自动化闭环。5.1 统一 JSON/CSV 双格式落盘同一批数据我会同时保存两份JSON 给程序继续处理用CSV 给人看和归档用。JSON 保留所有字段不丢细节CSV 只保留关键的几个字段方便直接筛选。写入时注意 CSV 用utf-8-sig解决 Excel 乱码import json import csv rows [...] # fetch_all 返回的结果 # JSON 用于二次处理ensure_asciiFalse 保证中文可读 with open(assets.json, w, encodingutf-8) as f: json.dump(rows, f, ensure_asciiFalse, indent2) # CSV 用于人工查看utf-8-sig 写入 BOMExcel 直接双击不乱码 with open(assets.csv, w, encodingutf-8-sig, newline) as f: writer csv.writer(f) writer.writerow([host, ip, port, protocol, domain, title]) writer.writerows(rows)newline 这个参数在 Windows 上必须写否则 csv 模块会在每行之间多插入一个空行表格打开后行间距异常这也是一个容易忽略的细节。5.2 定时巡检与差异对比资产暴露面是实时变化的今天搜到的东西明天可能下线也可能新增不少。把脚本交给系统定时任务跑每天生成一份带日期的结果文件# crontab 每天凌晨 2 点整执行一次日志追加写入 0 2 * * * cd /opt/fofa_crawler /usr/bin/python3 crawler.py --tasks tasks.json --output data/ logs/crawler.log 21调度跑起来以后可以再加一层差异对比逻辑把当天结果与昨天结果按ip:port:protocol做集合差新出现的资产单独生成一份diff_new.csv消失的生成diff_gone.csv。这一步用 Python 的 set 差集几十行就能实现但对资产变化监控非常有价值新开端口、新上业务都能通过这个文件第一时间发现。5.3 一次真实教训与我的习惯前几年我写 FOFA 批量脚本时为了赶进度把页间隔设成 0.2 秒短时间跑了三百多个查询结果密钥被临时限制整个任务中断还连累了当时正在用的 GUI 端。那之后我定了一条规矩所有涉及 FOFA API 的脚本页间隔低于 1 秒的版本一律不上生产批量任务前先拿一条查询小范围试跑确认返回条数和字段完整后再放开全部任务。现在维护这类爬虫我会额外保留每次请求的数量和耗时日志排查问题时不靠猜直接看哪一段请求开始报错。这套方法也适用于其他需要批量拉取数据的场景不只是 FOFA。希望这些参数和踩坑记录能帮你在做 FofaViewer 批量搜索和 Python 爬虫时少走一段弯路。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号