IP 地址查询接口实测评测:5 个实测可用的接口
2026/8/11 1:57:34 网站建设 项目流程

IP 地址查询接口实测评测:5 个实测可用的接口

实测时间:2026-08-10 方式:本机 curl 真实请求,逐个发包验证
样本:114.114.114.114(国内,江苏南京电信)、8.8.8.8(海外,美国)
本文只推荐实测通过的接口,未通过的列在文末附录,注明具体死因。


写在前面

IP 归属地查询是个看起来极其简单的需求——一个 HTTP 请求换一个地名。但真到要选一个接口用的时候,你会发现网上的写法五花八门:参数名不一样、有的只支持 HTTP、返回编码也各有各的脾气,稍不注意就拿到空数据或者一堆乱码。

有个坑最值得先提醒:判断成功不能只看 HTTP 状态码。有些接口照常返回 HTTP 200、JSON 结构完好、字段一个不少,但内容全是空的。代码判状态码通过、解析成功、写进库,等到发现不对劲,可能已经攒了几万条"未知"。所以下面每个接口的判断逻辑,都落到了业务字段上。

这次我们实测了几个流传最广的免费 IP 查询接口,把能稳定跑通的整理出来,测国内 IP、也测海外 IP,附上每个的真实返回和可直接抄的代码。

下面是实测可用的几个,以及各自的脾气。


1. 可用接口总览

接口请求地址中文HTTPS编码需要Key
百度 opendatahttps://opendata.baidu.com/api.php?query={ip}&co=&resource_id=6006&oe=utf8UTF-8
太平洋 pconlinehttps://whois.pconline.com.cn/ipJson.jsp?ip={ip}&json=trueGBK
ip-api.comhttp://ip-api.com/json/{ip}?lang=zh-CNUTF-8
ipinfo.iohttps://ipinfo.io/{ip}/jsonUTF-8否(限额)
ShowAPI 20-1https://route.showapi.com/20-1?appKey={appKey}UTF-8

补充一个:curl https://ifconfig.me/ip是通的,但它只返回你自己的出口 IP,不能查指定 IP,严格说不算同类工具,本文不做展开。


2. 百度 opendata —— 最省事的那个

无需 key、支持 HTTPS、返回 UTF-8,三个条件同时满足的只有它。本地调试首选。

curl"https://opendata.baidu.com/api.php?query=114.114.114.114&co=&resource_id=6006&oe=utf8"

实测返回(节选):

{"status":"0","data":[{"OriginQuery":"114.114.114.114","location":"江苏省南京市 电信","origip":"114.114.114.114","titlecont":"IP地址查询","resourceid":"6006"}]}

⚠️ 参数名是query,不是apiquery

这个坑值得单独说。网上流传的写法里,有相当一部分把参数写成apiquery=。我实测过,明确报错:

curl"https://opendata.baidu.com/api.php?apiquery=114.114.114.114&co=&resource_id=6006&oe=utf8"# {"status":1,"msg":"参数错误","data":[]}

一个错误写法能传播到这个程度,说明转载的人多,实际跑过的人少。

其他要注意的:

  • 成功时status字符串"0",失败时是数字1。类型不一致,判断时别直接==
  • 地址在data[0].location,是「江苏省南京市 电信」这么一整个字符串,省市和运营商没有拆开,要自己切
  • 海外 IP 只到国家级。查8.8.8.8返回的location就俩字:「美国」
importrequestsdefquery_baidu(ip):r=requests.get("https://opendata.baidu.com/api.php",params={"query":ip,"co":"","resource_id":"6006","oe":"utf8"},timeout=5)d=r.json()ifstr(d.get("status"))!="0"ornotd.get("data"):returnNonereturnd["data"][0].get("location")

3. 太平洋 pconline —— 国内定位最准的那个

如果你的业务只面向国内,这个的省市准确度是这批里最好的。

curl-s"https://whois.pconline.com.cn/ipJson.jsp?ip=114.114.114.114&json=true"\|iconv-fGBK-tUTF-8

实测返回:

{"ip":"114.114.114.114","pro":"江苏省","proCode":"320000","city":"南京市","cityCode":"320100","region":"","regionCode":"0","addr":"江苏省南京市 电信","regionNames":"","err":""}

字段拆得比百度细:省、市分开给,还带行政区划编码,直接能入库。

但它有三个坑,一个比一个隐蔽:

其一,必须走 HTTPS。实测http://明确返回403 Forbidden,只有https://是 200。这一条要特别注意——网上能搜到的示例几乎清一色写的是http://,直接复制粘贴必挂,而且 403 这个错误码容易让人误以为是被反爬了,实际只是协议问题。

其二,返回是 GBK。不是 UTF-8。不转码就是满屏乱码。

其三,海外 IP 只到国家。8.8.8.8的实测结果:

{"ip":"8.8.8.8","pro":"","city":"","addr":" 美国","err":"noprovince"}

省市全空,err字段有值。好在它诚实——err非空就是明确告诉你"这次没查全",可以拿来做判断依据。做海外业务的话,这个接口直接排除。

一个小彩蛋:省掉ip参数就是查自己的出口 IP。

curl-s"https://whois.pconline.com.cn/ipJson.jsp?json=true"|iconv-fGBK-tUTF-8# {"ip":"116.54.67.111","pro":"云南省","city":"昆明市","addr":"云南省昆明市 电信","err":""}

Python 版,注意那行encoding

importrequestsdefquery_pconline(ip=""):r=requests.get("https://whois.pconline.com.cn/ipJson.jsp",params={"ip":ip,"json":"true"},timeout=5)r.encoding="gbk"# ← 关键,漏了就是乱码returnr.json()

4. ip-api.com —— 字段最全的那个

免费接口里唯一同时给经纬度、时区、ASN 的。

curl"http://ip-api.com/json/114.114.114.114?lang=zh-CN"

实测返回:

{"status":"success","country":"中国","countryCode":"CN","region":"SD","regionName":"山东","city":"济南市","zip":"250000","lat":36.6518,"lon":117.12,"timezone":"Asia/Shanghai","isp":"China Unicom Shandong Province network","org":"NanJing XinFeng Information Technologies, Inc.","as":"AS137702 Nanjing, Jiangsu Province, P.R.China.","query":"114.114.114.114"}

字段丰富度确实是第一档的。但代价也明显:

免费版不支持 HTTPS。实测https://ip-api.com/...直接连接失败,不是证书问题,是根本不监听。这意味着如果你的站点跑在 HTTPS 上,前端直连会被浏览器的混合内容策略拦掉,只能放到服务端调。

限速 45 次/分钟,按来源 IP 计。好在它把余量放在响应头里了,实测:

X-Rl: 44 ← 本窗口剩余次数 X-Ttl: 60 ← 窗口重置倒计时(秒)

有这两个头就能做自适应限流,不用瞎猜。这点比那些一声不吭直接封你的接口友好得多。

国内精度是短板。上面那个例子,它把江苏南京的114.114.114.114判成了山东济南——省都错了。反倒是海外 IP 准得多。定位一句话:海外看它,国内别指望。

批量查询也支持,一次最多 100 个,同样计入限速:

curl-XPOST"http://ip-api.com/batch"-H"Content-Type: application/json"\-d'[{"query":"114.114.114.114","lang":"zh-CN"},{"query":"8.8.8.8","lang":"zh-CN"}]'

5. ipinfo.io —— 海外场景的选择

curl"https://ipinfo.io/8.8.8.8/json"

实测返回:

{"ip":"8.8.8.8","hostname":"dns.google","city":"Mountain View","region":"California","country":"US","loc":"37.4056,-122.0775","org":"AS15169 Google LLC","postal":"94043","timezone":"America/Los_Angeles","anycast":true}

字段设计是这批里最规范的:给 hostname,给 ASN,给邮编,甚至标了anycast: true——对做网络分析的人来说这个字段挺有用。HTTPS 原生支持,匿名就能调。

缺点也直接:全英文,没有中文地名,要展示给国内用户得自己做映射。国内定位偏差同样明显,114.114.114.114被它判成了上海。匿名调用有配额限制,量大需要注册 token。

定位很清楚:做海外业务用它,做国内业务别碰。


6. ShowAPI「全球IP归属地查询」—— 有服务商兜底的一个选项

接口页:https://www.showapi.com/apiGateway/view/20
服务商:昆明秀派科技有限公司(官方自营) 分类:交通地理免费服务,注册即用,无需单独购买

前面 4 个免费接口,好用归好用,但有一个现实问题:没有 SLA,也没有人对它负责。太平洋和百度本质是人家自家业务的副产品——不是对外开放的产品,随时可能加验证、加频控,甚至某天就没了,而且不会有任何通知。

ShowAPI 这个接口是商业化托管的:有服务商主体,有工单售后,有 OpenAPI 规范文档,定位精确到县区(前面几个最多到市)。它的代价也要说清楚:要注册拿 appKey、有调用额度、免费额度用完后要付费。把它当成"多花一点接入成本、换来更稳一点"的备选就行。

6.1 接入点

接入点地址入参用途超时
全球IP地址查询https://route.showapi.com/20-1?appKey={appKey}ipIP → 地理位置5s

POST / GET 都支持,实测都能打通网关。

6.2 调用示例

# IP 查地理位置curl-XPOST"https://route.showapi.com/20-1?appKey=YOUR_APPKEY"\-H"content-type: application/x-www-form-urlencoded"\-d"ip=203.0.113.220"

返回结构:

{"showapi_res_code":0,"showapi_res_error":"","showapi_res_id":"ce135f6739294c63be0c021b76b6fbff","showapi_fee_num":1,"showapi_res_body":{"country":"中国","region":"广东","city":"东莞","county":"","isp":"电信","area":"华南","continents":"亚洲","en_name":"China","en_name_short":"CN","city_code":"441900","lnt":"113.760234","lat":"23.048884","ret_code":0}}

字段是这批里最全的:中英文国家名、片区、洲、行政区划码、经纬度、运营商,一次给齐。

⚠️ 必须判两层状态码:

  • 外层showapi_res_code:网关级,0为成功
  • 内层showapi_res_body.ret_code:业务级,0为成功

只判外层会漏掉业务层面的失败。这是网关型 API 的通用模式,不熟悉的人很容易只判一层。

6.3 鉴权与错误码

鉴权走URL query 参数appKey(OpenAPI 里定义为apiKey / in: query)。appKey 在控制台 https://www.showapi.com/console#/myApp 获取。

我用无效 key 探了一下网关,错误语义分得很清楚:

场景showapi_res_codeshowapi_res_errorHTTP
完全不传 appKey-1002appKey err200
appKey 无效-1004appKey err200
正常0""200

-1002-1004区分了"没传"和"传错",排查时能省事。

但注意最后一列:HTTP 状态码恒为 200,无论成功失败。这和文末附录里那两个"假活"接口是同一个道理——判断成败必须解析 body,HTTP code 在这里没有信息量。

6.4 免费额度与计费

页面标注「免费服务 / 免费接口,注册即用,无需单独购买」。返回体里的showapi_fee_num是本次调用的计费次数,可以直接拿来对账。剩余额度在控制台「免费接口额度」看。


7. 横向对比

维度百度opendata太平洋ip-apiipinfo.ioShowAPI 20-1
HTTPS
中文
编码UTF-8GBKUTF-8UTF-8UTF-8
国内精度省市省市(准)省市(有误判)县区
海外精度仅国家仅国家
经纬度
运营商
行政区划码
限速未公示未公示45/分匿名限额按额度
正式文档✔ OpenAPI
SLA/售后付费版✔ 官方自营
需要 Key

这张表里的行各有取舍:免费接口胜在零成本、即开即用,短板是没文档、没售后、精度或协议有缺;ShowAPI 胜在字段全、有服务商兜底、精度到县区,代价是要 key、有额度。按自己场景挑就行,没有哪个是"全能最优"。


8. 选型建议

场景推荐
本地调试 / 一次性脚本百度 opendata(无 key、HTTPS、UTF-8,最省事)
只查国内、要省市准确太平洋 pconline(记得 HTTPS + GBK 转码)
要经纬度 / 时区 / ASNip-api(服务端调用,注意 45/分限速与无 HTTPS)
纯海外业务ipinfo.io
只想知道自己的公网 IPcurl https://ifconfig.me/ip
生产环境 / 县区精度ShowAPI 20-1(需 appKey,注意额度)

一句话总结:免费接口零成本、即开即用,适合脚本和轻量场景;真要上生产,要么选有服务商兜底的商业接口,要么自己做好多源降级留好后路。


9. 生产环境参考实现(多源降级)

比较务实的做法:免费接口当"能用就用"的加速层,商业接口兜底。既压住了成本,又不至于全线挂掉。

importrequests TIMEOUT=5SHOWAPI_KEY="YOUR_APPKEY"# 从 https://www.showapi.com/console#/myApp 获取def_baidu(ip):r=requests.get("https://opendata.baidu.com/api.php",params={"query":ip,"co":"","resource_id":"6006","oe":"utf8"},timeout=TIMEOUT)d=r.json()ifstr(d.get("status"))=="0"andd.get("data"):loc=d["data"][0].get("location")ifloc:return{"src":"baidu","addr":loc}returnNonedef_pconline(ip):r=requests.get("https://whois.pconline.com.cn/ipJson.jsp",params={"ip":ip,"json":"true"},timeout=TIMEOUT)r.encoding="gbk"# GBK,必须d=r.json()ifd.get("addr")andnotd.get("err"):# err 非空说明只查到国家return{"src":"pconline","addr":d["addr"],"province":d.get("pro"),"city":d.get("city"),"city_code":d.get("cityCode")}returnNonedef_ipapi(ip):r=requests.get(f"http://ip-api.com/json/{ip}",params={"lang":"zh-CN"},timeout=TIMEOUT)d=r.json()ifd.get("status")=="success":return{"src":"ip-api","addr":f'{d.get("country","")}{d.get("regionName","")}{d.get("city","")}',"lat":d.get("lat"),"lon":d.get("lon"),"isp":d.get("isp")}returnNonedef_showapi(ip):r=requests.post(f"https://route.showapi.com/20-1?appKey={SHOWAPI_KEY}",data={"ip":ip},headers={"content-type":"application/x-www-form-urlencoded"},timeout=TIMEOUT)d=r.json()ifd.get("showapi_res_code")!=0:# -1002 缺key / -1004 key无效returnNoneb=d.get("showapi_res_body")or{}ifstr(b.get("ret_code"))!="0":# 业务级状态,必须再判一层returnNonereturn{"src":"showapi","addr":f'{b.get("country","")}{b.get("region","")}{b.get("city","")}{b.get("county","")}',"isp":b.get("isp"),"lat":b.get("lat"),"lon":b.get("lnt"),"city_code":b.get("city_code")}defquery_ip(ip):"""按 免费源 → 商业源 顺序降级,任一成功即返回"""forfnin(_baidu,_pconline,_ipapi,_showapi):try:res=fn(ip)ifres:returnresexceptException:continuereturn{"src":None,"addr":"未知"}if__name__=="__main__":foripin("114.114.114.114","8.8.8.8"):print(ip,"->",query_ip(ip))

注意每个函数的返回判断——没有一个是只看 HTTP 状态码的,全部落到了业务字段上。这是这次实测最重要的一条经验。


10. 踩坑清单

  1. HTTP 200 不等于调用成功。ShowAPI 鉴权失败返回 200,附录里两个失效接口也返回 200 但数据全空。判断必须落到业务字段。
  2. 太平洋必须走 HTTPS。http://是 403,而网上示例几乎全写的http://
  3. 太平洋返回 GBK。不转码就是乱码。
  4. 百度 opendata 参数是query不是apiquery后者明确返回「参数错误」,但错误写法流传甚广。
  5. ip-api 免费版没有 HTTPS。前端直连会被混合内容策略拦截。
  6. 别抄别人示例里的第三方 key。实测那些流传的腾讯地图 key 已停用、百度地图 ak 已禁用,全都会报错。要用就自己申请。
  7. 网关型 API 要判两层状态码。外层网关 + 内层业务,缺一不可。
  8. 免费接口的稳定性要心里有数。这类接口随时可能加验证、加频控甚至下线,上线前务必自行复测,上线后最好加监控。

附录:实测不可用,请勿使用

网上流传的 IP 查询接口不少,但大多需要自备 key 或已不稳定,本文只收录实测稳定可用的几个。用任何接口时有一条要牢记:

最该警惕的是"假活"接口:返回 HTTP 200、JSON 字段齐全,但内容恒为空(例如恒返回127.0.0.10.0.0.0)。彻底挂掉的接口会当场暴露,而假活接口会安静地污染你的数据,直到某天有人问"为什么这批用户的归属地全是未知"。所以无论用哪个接口,判断成败一定要落到业务字段上,别只看 HTTP 状态码。


本文所有接口状态均为 2026-08-10 实测结果。免费接口变动频繁,请以自测为准。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询