大家好,我是何三,独立开发者
为什么要搞这个脚本
做网站的人都知道,ICP备案查询这事儿,太烦了。
每次想查一个域名的备案信息,打开工信部官网,输验证码,等半天加载,查完一个再查另一个——你要是手里有几十个域名需要批量排查,那简直是受罪。
我之前帮朋友整理一批域名的归属情况,一个一个手动查,查到第12个的时候,差点把键盘砸了。
所以,能不能用Python写个脚本,调第三方接口自动查?
答案是:可以,而且很简单。

⚠️ 免责声明(必读)
在开始之前,有些话得先说清楚:
- 本脚本仅供学习和技术研究使用,严禁用于任何非法用途。
- 脚本调用的第三方接口数据来源于公开信息,不涉及任何 hacking 或未授权访问。
- 使用本脚本查询ICP备案信息时,请遵守《中华人民共和国网络安全法》《中华人民共和国个人信息保护法》等相关法律法规。
- 因使用者个人行为导致的任何法律后果,由使用者自行承担,与本文作者无关。
- 第三方接口的可用性和数据准确性由接口提供方负责,作者不对数据的完整性和时效性做任何保证。
- 请合理控制请求频率,避免对接口服务方造成不必要的压力,建议加入适当的延时和限流措施。
- 本脚本涉及的代码和技术方案仅供技术交流,不构成任何商业建议。
简单说就是:学习交流可以,别搞事情,搞事情别找我。
准备工作
你需要准备的东西不多:
- Python 3.6+(这个应该都有吧)
requests库- 一个可用的ICP查询第三方API
第三方接口去哪找?说实话,市面上有不少,有些免费的,有些收费的,有些需要注册。我用的比较多的几个渠道:
- 站长工具API
- ICP备案查询网
- 各种API聚合平台(比如聚合数据、极速数据等)
具体用哪个看你自己,反正思路是一样的:构造请求 → 解析返回 → 提取信息。
先装依赖:
pip install requests
搞定。
实战:对接第三方接口查询ICP
下面直接上代码。我以一个通用的ICP查询API为例(你需要替换成你自己申请的API地址和密钥):
核心查询脚本
import requests
import time
import json
class ICPQuery:
"""ICP备案查询工具"""
def __init__(self, api_url, api_key=None):
"""
初始化查询器
:param api_url: 第三方API地址
:param api_key: API密钥(如需要)
"""
self.api_url = api_url
self.api_key = api_key
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
def query_single(self, domain):
"""
查询单个域名的ICP备案信息
:param domain: 域名
:return: 备案信息字典
"""
try:
params = {'domain': domain, 'key': self.api_key}
response = requests.get(
self.api_url,
params=params,
headers=self.headers,
timeout=10
)
response.raise_for_status()
result = response.json()
# 根据实际API返回结构解析
if result.get('code') == 200 or result.get('status') == 'success':
data = result.get('data', {})
return {
'domain': domain,
'unit_name': data.get('unitName', '未知'), # 主办单位
'nature_name': data.get('natureName', '未知'), # 单位性质
'icp': data.get('icp', '未知'), # 备案号
'update_time': data.get('updateTime', '未知'), # 审核时间
'status': '成功'
}
else:
return {'domain': domain, 'status': '未查到备案信息', 'msg': result.get('msg', '')}
except requests.exceptions.Timeout:
return {'domain': domain, 'status': '查询超时'}
except requests.exceptions.RequestException as e:
return {'domain': domain, 'status': f'请求异常: {str(e)}'}
except json.JSONDecodeError:
return {'domain': domain, 'status': '返回数据解析失败'}
def query_batch(self, domains, delay=1.5):
"""
批量查询域名备案信息
:param domains: 域名列表
:param delay: 请求间隔(秒),防止被封
:return: 查询结果列表
"""
results = []
total = len(domains)
for i, domain in enumerate(domains, 1):
print(f"[{i}/{total}] 正在查询: {domain}")
result = self.query_single(domain.strip())
results.append(result)
# 打印结果
if result.get('status') == '成功':
print(f" ✅ {result['unit_name']} | {result['icp']}")
else:
print(f" ❌ {result['status']}")
# 控制请求频率,避免被限制
if i < total:
time.sleep(delay)
return results
def export_csv(self, results, filename='icp_results.csv'):
"""
导出查询结果为CSV文件
:param results: 查询结果列表
:param filename: 输出文件名
"""
import csv
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.writer(f)
writer.writerow(['域名', '主办单位', '单位性质', '备案号', '审核时间', '状态'])
for r in results:
writer.writerow([
r.get('domain', ''),
r.get('unit_name', ''),
r.get('nature_name', ''),
r.get('icp', ''),
r.get('update_time', ''),
r.get('status', '')
])
print(f"\n📁 结果已导出: {filename}")
if __name__ == '__main__':
# ========== 配置区 ==========
# 替换为你自己的API地址和密钥
API_URL = 'https://api.example.com/icp/query'
API_KEY = 'your_api_key_here'
# 需要查询的域名列表
DOMAINS = [
'baidu.com',
'qq.com',
'github.com',
'example.com', # 这个大概率查不到
]
# ============================
query = ICPQuery(API_URL, API_KEY)
# 批量查询
results = query.query_batch(DOMAINS, delay=1.5)
# 导出CSV
query.export_csv(results)
使用说明
代码逻辑其实不复杂,拆开来说:
第一步:初始化。把API地址和密钥传进去,设置请求头伪装一下(有些接口会检查UA)。
第二步:查询单个域名。发起GET请求,拿到JSON返回,按字段提取备案信息。这里面做了异常处理——超时、请求失败、JSON解析错误都兜住了。
第三步:批量查询。循环遍历域名列表,每次查询之间 sleep 1.5秒。这个延时很重要,别问我是怎么知道的(问就是被封过IP)。
第四步:导出CSV。用 csv 模块把结果写到文件里,编码用 utf-8-sig,这样Excel打开不会乱码。
进阶玩法
1. 从文件读取域名
域名多的话,一个个写在代码里太蠢了。直接从txt文件读:
def read_domains_from_file(filepath):
"""从文本文件读取域名列表,每行一个"""
with open(filepath, 'r', encoding='utf-8') as f:
domains = [line.strip() for line in f if line.strip()]
return domains
# 使用
domains = read_domains_from_file('domains.txt')
results = query.query_batch(domains)
2. 加上简单的日志记录
查询几十个域名的时候,终端输出太多看不过来。写个日志:
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
filename='icp_query.log',
filemode='a'
)
# 在 query_single 方法里加一行
logging.info(f"查询 {domain}: {result}")
3. 异步加速查询
如果你觉得1.5秒的间隔太慢,可以用 aiohttp 做异步请求,配合信号量控制并发数。不过这个就涉及得比较深了,有机会再单独写一篇。
算了,先贴个简版:
import aiohttp
import asyncio
async def async_query(domain, api_url, api_key, semaphore):
async with semaphore:
try:
params = {'domain': domain, 'key': api_key}
async with aiohttp.ClientSession() as session:
async with session.get(api_url, params=params, timeout=10) as resp:
result = await resp.json()
return {'domain': domain, 'data': result}
except Exception as e:
return {'domain': domain, 'error': str(e)}
async def batch_async(domains, api_url, api_key, concurrency=3):
semaphore = asyncio.Semaphore(concurrency)
tasks = [async_query(d, api_url, api_key, semaphore) for d in domains]
return await asyncio.gather(*tasks)
# 运行
# results = asyncio.run(batch_async(domains, API_URL, API_KEY))
并发数别设太大,3-5个差不多了。做人留一线,别把人家接口打崩了。
常见坑点提醒
写这个脚本的过程中,踩了几个坑,提前给你们避一下:
-
接口返回格式不统一。不同API的字段名不一样,有的叫
unitName,有的叫companyName,拿到接口文档后先测试一下,确认字段名再写解析逻辑。 -
编码问题。CSV导出一定要用
utf-8-sig,不然用Excel打开就是一堆乱码。别问我为什么强调两次(被坑过两次)。 -
请求频率控制。有些免费的API限流很严格,建议把
delay设成2-3秒。宁可慢点,别把IP搞黑了。 -
域名格式。输入的时候别带
http://或https://,纯域名就行,比如baidu.com而不是https://www.baidu.com。接口一般不认这种格式。 -
备案信息延迟。新备案的域名在工信部更新可能有1-3天的延迟,查不到不代表没备案,别慌。
技术支持
如果在使用过程中遇到任何问题,或者需要定制化开发,欢迎联系我:
QQ: 466867714
总结
这个脚本说到底就是一个 HTTP请求 + JSON解析 + 数据导出 的组合拳。没什么高深的东西,但确实是能解决实际问题的工具。
手动查10个域名可能要半小时,脚本跑完也就一两分钟。这就是自动化的价值——把人从重复劳动中解放出来,去做更有意思的事。
不过话说回来,市面上其实也有一些现成的ICP批量查询工具,免费的收费的都有。但自己写脚本的好处是:可控、可定制、不会被别人限制功能。
想要源码完整版的,关注公众号后台留言联系我。
本文使用 MGO 编辑并发布
关注"何三笔记",回复"mgo" 免费下载使用