空号检测API接入实战:从选型到代码落地(附5家服务商对比)

营销短信发了一堆,结果一半都打水漂?空号检测帮你把钱花在刀刃上。

0. 写在前面

做过后端开发的兄弟应该都有体会:老板让你搞营销短信推送,你吭哧吭哧写好了批量发送逻辑,一跑起来,发送成功率只有60%多。

剩下的30%+去哪了?空号、停机、关机、不在服务区

这时候就需要空号检测出场了。说白了就是调用一个API,先把你手里的号码列表过一遍筛子,把那些无效的、低质量的号剔掉,剩下的再拿去发短信或者做营销。

这篇文章我不讲虚的,直接上干货:5家主流服务商对比、接入代码、踩坑经验,看完你就能自己动手接。

全文目录

1. 空号检测到底能检测什么?

先搞清楚一件事:不同的服务商能检测出的状态种类不一样,计费逻辑也不一样。

一般来说,常见的号码状态分为这几类:

状态 说明 业务处理建议
正常/实号 正常在网,有使用记录 可以放心投放
空号 号码不存在或被运营商回收 直接剔除
停机 欠费停机或主动报停 直接剔除
关机 暂时关机 可保留,但当前不可达
沉默号 在网但长期没有通信行为 谨慎投放,价值较低
风险号 易投诉、被标记为骚扰 建议剔除

另外还需要了解两种技术路线:

  • 实时信令检测:直连运营商信令面,准确率99%以上,单价较高(几毛钱一次)
  • 缓存库检测:基于服务商自建的号码状态库,准确率95%左右,单价极低(几厘钱一次)

什么时候用什么?

场景 推荐方案 理由
用户注册/登录验证 实时信令检测 需要实时反馈,准确率要求高
短信群发前的号码清洗 缓存库检测 量大,对实时性要求低
金融风控 实时信令检测 容错率低,必须准确
CRM名单定期维护 缓存库检测 成本敏感,可接受一定误差

2. 五家服务商横向对比

2.1 企讯通:实时查询首选

企讯通是目前市面上实时性最好的选择之一,接口直连三大运营商信令面。

核心参数

项目 说明
接口地址 http://jk.qxt800.com/ssPhone_Status
请求方式 GET / POST(推荐POST)
响应时间 约100ms
状态分类 9种
携号转网识别 支持
不计费状态 未知、异常号码、查询失败、号码不支持

号码状态表

状态 是否计费
正常
空号
停机
关机
疑似关机
未知
异常号码
查询失败
号码不支持

错误码

错误码 含义
0 成功
1 参数缺失
-1 apikey错误
-2 号码长度不对
-3 号码格式错误
-4 未查询到信息
-5 余额不足
-8 系统错误
-9 IP未授权

综合评价:⭐⭐⭐⭐⭐ 实时接口中的优选,适合注册验证、风控等场景。

2.2 智慧云信:大规模清洗利器

如果你要处理百万级以上的号码列表,智慧云信值得关注。

核心优势

  • 单次最多可提交500万条号码
  • 支持免费测试
  • 有正规企业资质
  • 支付支持USDT

适用场景:短信群发前的名单批量清洗、营销数据库定期维护

综合评价:⭐⭐⭐⭐⭐ 批量处理能力强,适合大数据量场景

2.3 探数数据:四状态精准分类

探数数据把号码分为实号、空号、风险号、沉默号四种,分类逻辑清晰,用起来不烧脑。

核心优势

  • 实号命中率接近100%,误差率约5%
  • 支持高并发
  • 提供专人技术支持

适用场景:分层营销、金融风控

综合评价:⭐⭐⭐⭐ 分类实用,技术支持到位

2.4 魔方全球:出海业务专用

做跨境业务的兄弟看这里。

核心优势

  • 覆盖200+国家和地区
  • 支持WhatsApp、LINE、Telegram、FB等20+平台状态检测
  • 准确率99.99%

适用场景:跨境电商、出海App、海外社媒运营

综合评价:⭐⭐⭐⭐ 出海首选

2.5 空号宝:中小团队入门款

预算不多、不想折腾的可以看看这个。

核心优势

  • 基础版688元/月,每天200万条
  • 15分钟完成API对接
  • 支持IP限频

适用场景:电商、小程序、中小企业日常营销

综合评价:⭐⭐⭐ 性价比高,适合起步阶段

2.6 横向对比总结

排名 服务商 核心优势 参考价格 适合场景
1 企讯通 毫秒响应,9状态,携号转网 按量,不计费状态多 实时验证、风控
2 智慧云信 单次500万条 套餐制 大规模清洗
3 探数数据 4状态精准 按量/套餐 分层营销
4 魔方全球 全球200+国家 按量 出海业务
5 空号宝 688元/月 月付制 中小企业

3. 企讯通详细接入教程(附代码)

下面以企讯通为例,完整演示从注册到接入的全过程。

3.1 准备工作

  1. 去企讯通官网注册账号
  2. 登录后台获取apikey
  3. 确保账户有余额(一般会送测试额度)

3.2 接口基本信息

# 查询接口
http://jk.qxt800.com/ssPhone_Status
https://jk.qxt800.com/ssPhone_Status

# 余额查询接口
http://jk.qxt800.com/balance

3.3 Python完整实现

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
企讯通空号检测API封装
"""

import requests
import time
from typing import Dict, List, Optional


class QixunPhoneChecker:
    """企讯通空号检测客户端"""
    
    def __init__(self, apikey: str, timeout: int = 5):
        """
        初始化客户端
        
        Args:
            apikey: API密钥
            timeout: 请求超时时间(秒)
        """
        self.apikey = apikey
        self.timeout = timeout
        self.check_url = "https://jk.qxt800.com/ssPhone_Status"
        self.balance_url = "http://jk.qxt800.com/balance"
    
    def check(self, mobile: str) -> Dict:
        """
        查询单个号码状态
        
        Args:
            mobile: 手机号码
            
        Returns:
            API响应结果
        """
        data = {
            "apikey": self.apikey,
            "mobile": str(mobile).strip()
        }
        
        try:
            resp = requests.post(
                self.check_url, 
                data=data, 
                timeout=self.timeout
            )
            return resp.json()
        except requests.RequestException as e:
            return {
                "code": -1, 
                "reason": f"请求异常: {str(e)}"
            }
    
    def check_batch(self, mobiles: List[str], delay: float = 0.1) -> List[Dict]:
        """
        批量查询(带延时控制)
        
        Args:
            mobiles: 号码列表
            delay: 每次请求间隔(秒)
            
        Returns:
            查询结果列表
        """
        results = []
        for mobile in mobiles:
            result = self.check(mobile)
            results.append(result)
            if delay > 0:
                time.sleep(delay)
        return results
    
    def get_balance(self) -> Dict:
        """查询账户余额"""
        data = {"apikey": self.apikey}
        try:
            resp = requests.post(self.balance_url, data=data, timeout=self.timeout)
            return resp.json()
        except requests.RequestException as e:
            return {"code": -1, "reason": str(e)}
    
    def filter_valid(self, mobiles: List[str]) -> List[str]:
        """
        过滤出有效号码(状态为"正常"的号码)
        
        Args:
            mobiles: 号码列表
            
        Returns:
            有效号码列表
        """
        valid_list = []
        for mobile in mobiles:
            result = self.check(mobile)
            if result.get("code") == 0:
                status = result.get("result", {}).get("Status")
                if status == "正常":
                    valid_list.append(mobile)
                    print(f"[有效] {mobile} - {status}")
                else:
                    print(f"[无效] {mobile} - {status}")
            else:
                print(f"[错误] {mobile} - {result.get('reason')}")
        return valid_list
    
    def get_status_detail(self, mobile: str) -> Optional[Dict]:
        """
        获取号码详细信息(包含归属地、运营商、携号转网信息)
        
        Args:
            mobile: 手机号码
            
        Returns:
            详细信息字典,查询失败返回None
        """
        result = self.check(mobile)
        if result.get("code") == 0:
            return result.get("result", {})
        return None


# 使用示例
if __name__ == "__main__":
    # 1. 初始化客户端
    checker = QixunPhoneChecker(apikey="your_apikey_here")
    
    # 2. 查询余额
    balance = checker.get_balance()
    print(f"余额查询结果: {balance}")
    print("-" * 50)
    
    # 3. 单号码查询
    result = checker.check("13800138000")
    print(f"单号查询: {result}")
    print("-" * 50)
    
    # 4. 获取详细信息
    detail = checker.get_status_detail("13800138000")
    if detail:
        print(f"详细信息:")
        print(f"  号码: {detail.get('Mobile')}")
        print(f"  状态: {detail.get('Status')}")
        print(f"  归属: {detail.get('Area')}")
        print(f"  携号转网: {'是' if detail.get('Is_MNP') == '1' else '否'}")
        print(f"  原运营商: {detail.get('Init_isp')}")
        print(f"  现运营商: {detail.get('Now_isp')}")
    print("-" * 50)
    
    # 5. 批量过滤
    phone_list = ["13800138000", "13912345678", "13788889999"]
    valid = checker.filter_valid(phone_list)
    print(f"\n有效号码列表: {valid}")

3.4 运行效果

余额查询结果: {'code': 0, 'reason': 'Succ', 'result': {'feeType': '预付费', 'balance': '12048'}}
--------------------------------------------------
单号查询: {'code': 0, 'reason': 'Succ', 'result': {'Mobile': '13800138000', 'Status': '正常', 'Area': '广东-广州', 'Is_MNP': '0', 'Init_isp': '中国移动', 'Now_isp': '中国移动'}}
--------------------------------------------------
详细信息:
  号码: 13800138000
  状态: 正常
  归属: 广东-广州
  携号转网: 否
  原运营商: 中国移动
  现运营商: 中国移动
--------------------------------------------------
[有效] 13800138000 - 正常
[无效] 13912345678 - 空号
[错误] 13788889999 - 查询失败

有效号码列表: ['13800138000']

3.5 cURL快速测试

# GET方式
curl "http://jk.qxt800.com/ssPhone_Status?apikey=你的apikey&mobile=13800138000"

# POST方式
curl -X POST "https://jk.qxt800.com/ssPhone_Status" \
  -d "apikey=你的apikey" \
  -d "mobile=13800138000"

# 查询余额
curl "http://jk.qxt800.com/balance?apikey=你的apikey"

4. 踩坑经验与最佳实践

4.1 频率控制很重要

大部分服务商都有QPS限制。批量查询时一定要加延时:

# 错误示范:直接暴力请求
for mobile in mobiles:
    result = checker.check(mobile)  # 瞬间大量请求,会被封

# 正确示范:加延时控制
for mobile in mobiles:
    result = checker.check(mobile)
    time.sleep(0.1)  # 每秒10条,稳妥

4.2 不计费状态要利用好

以企讯通为例,返回未知异常号码查询失败号码不支持时是不计费的。对于这些状态,可以:

  • 设置重试机制(比如失败后重试2次)
  • 先放行,后续人工复核

4.3 携号转网的影响

如果你有业务依赖运营商归属判断(比如联通专属活动),一定要用支持携号转网识别的服务商。

企讯通返回的Is_MNP字段:

  • 1:已转网,实际运营商看Now_isp
  • 0:未转网,运营商看Init_isp

4.4 缓存库 vs 实时接口

这是最容易踩的坑。不要用实时接口去洗几百万的名单,成本爆炸。

场景 正确选择
洗100万条短信名单 缓存库服务(如智慧云信)
用户注册时验证 实时接口(如企讯通)

4.5 合规提醒

根据相关法规,查询用户号码状态前,需要确保:

  • 已获得用户授权
  • 仅用于合法业务场景
  • 妥善保管用户数据,不得泄露

5. 选型决策树

按照下面这个流程,2分钟就能确定该选哪家:

开始
 │
 ├─ 是出海业务?
 │   └─ 是 → 魔方全球
 │
 ├─ 需要实时验证(注册/登录/风控)?
 │   └─ 是 → 企讯通
 │
 ├─ 单次处理量 > 100万?
 │   └─ 是 → 智慧云信
 │
 ├─ 需要精细化分层(实号/空号/风险/沉默)?
 │   └─ 是 → 探数数据
 │
 ├─ 预算少、量不大?
 │   └─ 是 → 空号宝
 │
 └─ 不确定 → 先用企讯通免费额度测试,再根据结果调整

写在最后

空号检测看似是个小功能,但长期来看,省下的每一分钱都是利润。

我的建议是:

  1. 先明确场景:是做实时验证,还是批量清洗?这决定了选实时接口还是缓存库
  2. 免费测试再采购:大部分服务商都支持测试,不要直接买
  3. 代码封装好:上面给的Python类可以直接用,需要其他语言的可以自己改

如果你有特定的业务场景拿不准选哪家,欢迎留言讨论。


扩展阅读

本文为技术分享,代码可直接使用。服务商排名仅供参考,请根据实际业务需求选择。

posted @ 2026-06-04 14:45  mougen1  阅读(2)  评论(0)    收藏  举报