# `ipgetter` 模块技术文档 > **版本**: `0.6` > **作者**: phoemur@gmail.com > **许可证**: [WTFPL v2](http://www.wtfpl.net/) — Do What The Fuck You Want To Public License --- ## 简介 `ipgetter` 是一个轻量级的 Python 模块,用于从互联网获取用户的**外部 IP 地址(公网 IP)**。该模块特别适用于位于 NAT(网络地址转换)后的设备或路由器后端主机。 它通过随机轮询多个公开的 IP 查询服务来减少对单一服务器的请求压力,并具备容错机制以应对部分服务不可用的情况。 所有服务器响应内容使用正则表达式解析提取 IP,支持自定义解析器,兼容 Python 2.5+ 及 Python 3.x。 --- ## 安装与依赖 ### 安装方式 本模块为单文件脚本,无需安装: ```bash wget https://raw.githubusercontent.com/phoemur/ipgetter/master/ipgetter.py ``` 或直接复制代码保存为 `ipgetter.py`,然后在项目中导入即可。 ### 依赖说明 - 标准库: - `re`, `json`, `time`, `random`, `socket`, `threading.Timer` - `urllib.request`(通过 `future.moves.urllib.request` 兼容 Py2/Py3) - 第三方兼容层(仅需标准库): - 使用了 `future` 库中的跨版本模块路径(但仍只依赖标准库功能) > ⚠️ 注意:虽然引入了 `future.moves.urllib.request`,但并未强制要求安装 `future` 包。若环境不支持,请确保运行于原生 Python 2.7+ 或 3.x 环境。 --- ## 快速开始 ### 基础用法 ```python import ipgetter # 获取当前公网 IP myip = ipgetter.myip() print(myip) # 输出示例: '8.8.8.8' ``` ### 高级测试(调试模式) ```python ipgetter.IPgetter().test() ``` 输出将显示所有服务器返回的结果统计,便于验证一致性与可用性。 --- ## API 接口详解 ### 函数:`myip() → str` 返回当前机器的公网 IP 地址字符串,失败时返回空字符串。 #### 示例: ```python >>> import ipgetter >>> ipgetter.myip() '203.0.113.45' ``` #### 实现逻辑: 调用 `IPgetter().get_external_ip()` 方法完成实际工作。 --- ### 类:`IPgetter` 核心类,提供灵活的 IP 查询控制能力。 #### 构造函数:`__init__()` 初始化一个 `IPgetter` 实例,包含以下属性: | 属性 | 类型 | 描述 | |------|------|------| | `server_list` | list[str] | 支持的 IP 查询服务 URL 列表(共 18 个默认源) | | `parsers` | dict[str → callable] | 自定义每个服务器响应体的解析函数映射表 | | `timeout` | float | 单次请求超时时间(单位:秒,默认 `1.6` 秒) | | `url` | file-like / None | 当前打开的 URL 资源句柄(用于手动关闭) | > 📌 提示:可通过 `add_server()` 动态添加新的查询服务。 #### 方法:`get_external_ip() → str` 从随机打乱的服务器列表中依次尝试获取公网 IP,直到成功且符合非私有 IP 规则为止。 ##### 返回值: - 成功时返回合法公网 IPv4 字符串(如 `'8.8.8.8'`) - 失败或未匹配有效 IP 时返回 `''` ##### 过滤规则: 自动排除以下私有/本地地址段: - `192.*` 开头(典型局域网) - `10.*` 开头(内网地址) - `127.*` 开头(回环地址) > ✅ 此设计避免误取本地接口地址。 ##### 执行流程: 1. 打乱 `server_list` 防止单点负载过高 2. 循环调用 `fetch(server)` 获取响应 3. 使用对应解析器提取 IP(默认使用内置正则) 4. 若得到有效公网 IP,则立即返回 5. 否则继续下一个服务,全部失败返回空串 --- #### 方法:`fetch(server: str) → str` 向指定服务发起 HTTP 请求并返回其响应中提取出的 IP 地址。 ##### 参数: - `server`: 目标服务的完整 URL(必须以 `http://` 或 `https://` 开头) ##### 内部处理细节: - 设置 User-Agent 模拟 Firefox 浏览器请求 - 支持设置超时(兼容 Python 2.5 的 socket hack) - 使用定时器防止阻塞过久(尤其在旧版 Python 上) - 自动处理字符编码(优先 UTF-8,失败转 ISO-8859-1) - 异常捕获并打印错误信息(不影响主流程) ##### 编码处理策略: ```python if PY3K: try: content = content.decode('UTF-8') except UnicodeDecodeError: content = content.decode('ISO-8859-1') ``` > ❗ 不依赖第三方库(如 `chardet`),坚持使用标准库。 ##### 资源清理: 无论成功与否,均确保关闭连接、取消定时器、恢复原始 socket 超时设置。 --- #### 方法:`defaultparser(content: str) → str` 默认的 IP 解析函数,使用正则表达式从文本中提取第一个匹配的 IPv4 地址。 ##### 正则表达式: ```regex (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\. (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\. (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\. (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) ``` ✅ 支持完整的 IPv4 地址格式校验。 ##### 行为: - 成功提取则返回 IP 字符串 - 匹配失败或异常抛出则返回 `''` --- #### 方法:`add_server(server: str, parser: callable)` 动态注册一个新的 IP 查询服务及其专属解析函数。 ##### 参数: - `server`: 新增服务的 URL(例如 `'https://api.ipify.org?format=json'`) - `parser`: 接受 `content: str` 输入并返回 `ip: str` 的可调用对象 ##### 示例: ```python def parse_ipinfo_json(content): data = json.loads(content) return data['ip'] g = IPgetter() g.add_server('http://ipinfo.io/json', parse_ipinfo_json) print(g.get_external_ip()) ``` > 💡 常用于 JSON 接口的服务扩展。 --- #### 方法:`test()` 测试所有服务器的一致性和可达性,输出汇总报告。 ##### 输出内容: - 总服务器数量 - 各 IP 地址出现次数统计 - 每个服务的实际响应结果字典 ##### 示例输出: ``` Number of servers: 18 IP's : 8.8.8.8 = 16 occurrences broken server = 2 occurrences {'http://ifconfig.me/ip': '8.8.8.8', ...} ``` > 🔍 适合开发者调试或评估服务稳定性。 --- #### 方法:`all_result()` 遍历所有服务器并打印 `[url, response]` 对列表(调试用途)。 ⚠️ 当前实现仅为简单打印,无返回值。 --- ## 内置服务器列表(截至 v0.6) 以下是模块默认使用的公共 IP 查询服务(共 18 个): ```text - http://ifconfig.me/ip - http://ipecho.net/plain - http://getmyipaddress.org/ - http://www.my-ip-address.net/ - http://www.canyouseeme.org/ - http://trackip.net/ - http://icanhazip.com/ - http://www.ipchicken.com/ - http://whatsmyip.net/ - http://www.lawrencegoetz.com/programs/ipinfo/ - http://ip-lookup.net/ - http://ipgoat.com/ - http://www.myipnumber.com/my-ip-address.asp - http://www.geoiptool.com/ - http://checkip.dyndns.com/ - http://www.ip-adress.eu/ - http://wtfismyip.com/ - http://httpbin.org/ip ``` > 🔄 所有服务按随机顺序访问,降低单点压力。 > 🛠 如需增删服务,请联系作者 via GitHub。 --- ## 使用建议与注意事项 ### ✅ 最佳实践 - 在生产环境中定期调用 `.myip()` 获取最新 IP。 - 若发现某些服务频繁失效,可通过 `add_server()` 替换更稳定的替代源。 - 使用 `.test()` 定期检查服务健康状态。 ### ⚠️ 注意事项 - 仅支持 IPv4(目前无 IPv6 支持) - 不保证 100% 准确率(取决于第三方服务可用性) - 错误请求可能触发某些服务的限流机制 - 超时设置较短(1.6s),适合快速探测,高延迟网络下可适当调大 --- ## 许可证 ``` Copyright 2014 phoemur@gmail.com This work is free. You can redistribute it and/or modify it under the terms of the Do What The Fuck You Want To Public License, Version 2, as published by Sam Hocevar. See http://www.wtfpl.net/ for more details. ``` 👉 即:你可以自由地使用、修改、分发此代码,只要你不违法。 --- ## 贡献与反馈 欢迎提交 Issue 或 Pull Request 至 GitHub 仓库: 🔗 [https://github.com/phoemur/ipgetter](https://github.com/phoemur/ipgetter) 若您希望添加或移除某个 IP 查询服务,请联系作者。 --- ## 示例:扩展 JSON 接口支持 ```python import ipgetter import json def parse_ipinfo(content): return json.loads(content)['ip'] g = ipgetter.IPgetter() g.add_server('http://ipinfo.io/json', parse_ipinfo) print("My public IP is:", g.get_external_ip()) ``` --- ## 版本历史 | 版本 | 说明 | |------|------| | `0.6` | 当前版本,优化健壮性,增加可扩展性 | | `0.5` | 初始开源版本 | --- ## 致谢 感谢以下服务提供免费的 IP 查询接口: - ifconfig.me - icanhazip.com - ipinfo.io - httpbin.org - dyndns 等 🙏 维护这些开放资源的人们让此类工具成为可能。 --- 📘 文档最后更新:2025年4月5日