fix:IP定位

pull/91/head
Maziang 5 months ago
parent 2cd81a5195
commit 2185df2667

@ -1281,27 +1281,150 @@ class WeatherAPI:
def get_isp_info(self):
"""获取ISP信息"""
try:
url = "http://ip-api.com/json/"
response = requests.get(url, timeout=5)
response.raise_for_status()
# 尝试多个ISP信息服务以提高成功率
# 方法1: 使用ip-api.com接口
try:
url = "http://ip-api.com/json/"
headers = {'User-Agent': 'MagicWord/1.0'}
response = requests.get(url, timeout=5, headers=headers)
response.raise_for_status()
data = response.json()
if data.get('status') == 'success':
isp = data.get('isp', '')
org = data.get('org', '')
as_info = data.get('as', '')
country = data.get('country', '')
return f"{isp} {org} {as_info} {country}".strip()
except Exception as e:
print(f"ip-api ISP信息获取失败: {e}")
pass
# 方法2: 使用ipinfo.io接口
try:
url = "https://ipinfo.io/json"
headers = {'User-Agent': 'MagicWord/1.0'}
response = requests.get(url, timeout=5, headers=headers)
response.raise_for_status()
data = response.json()
if 'org' in data:
org = data.get('org', '')
country = data.get('country', '')
return f"{org} {country}".strip()
except Exception as e:
print(f"ipinfo ISP信息获取失败: {e}")
pass
# 方法3: 使用httpbin.org获取基础信息
try:
url = "https://httpbin.org/ip"
headers = {'User-Agent': 'MagicWord/1.0'}
response = requests.get(url, timeout=5, headers=headers)
response.raise_for_status()
# 这个接口主要用于获取IP不是ISP信息但可以作为备选
data = response.json()
origin = data.get('origin', '')
if origin:
return f"IP: {origin}"
except Exception as e:
print(f"httpbin ISP信息获取失败: {e}")
pass
data = response.json()
if data.get('status') == 'success':
isp = data.get('isp', '')
org = data.get('org', '')
as_info = data.get('as', '')
return f"{isp} {org} {as_info}".strip()
return None
except Exception as e:
print(f"获取ISP信息失败: {e}")
print(f"获取ISP信息总体失败: {e}")
return None
def get_location_by_ip(self):
"""通过IP地址获取用户位置"""
try:
# 首先获取公网IP地址
ip_address = None
try:
# 使用多个IP获取服务确保能获取到公网IP
ip_services = [
"https://api.ipify.org",
"https://icanhazip.com",
"https://ident.me",
"https://ipecho.net/plain",
"https://myexternalip.com/raw"
]
for service in ip_services:
try:
response = requests.get(service, timeout=3)
if response.status_code == 200:
ip_address = response.text.strip()
# 验证是否为有效的IPv4地址
import re
if re.match(r'^(\d{1,3}\.){3}\d{1,3}$', ip_address):
print(f"获取到公网IP: {ip_address}")
break
else:
ip_address = None
except:
continue
if not ip_address:
print("无法获取公网IP地址")
except Exception as e:
print(f"获取IP地址失败: {e}")
# 尝试多个免费的IP地理位置API
# API 1: 搜狐IP接口HTTP无SSL问题
# API 1: 使用ip-api.com接口更稳定的免费服务支持HTTPS
try:
if ip_address:
url = f"https://ip-api.com/json/{ip_address}"
else:
url = "https://ip-api.com/json/"
headers = {'User-Agent': 'MagicWord/1.0'}
response = requests.get(url, timeout=5, headers=headers)
response.raise_for_status()
data = response.json()
if data.get('status') == 'success':
city = data.get('city', '')
region = data.get('regionName', '')
country = data.get('country', '')
if city and city not in ['null', 'None', '']:
print(f"ip-api定位成功: {city}, {region}, {country}")
# 如果城市信息不完整,尝试用地区信息补充
if len(city) < 2 and region:
city = region
return city
except Exception as e:
print(f"ip-api接口失败: {e}")
pass
# API 2: 使用ipinfo.io接口需要处理免费版限制
try:
if ip_address:
url = f"https://ipinfo.io/{ip_address}/json"
else:
url = "https://ipinfo.io/json"
headers = {'User-Agent': 'MagicWord/1.0'}
response = requests.get(url, timeout=5, headers=headers)
response.raise_for_status()
data = response.json()
if 'city' in data:
city = data.get('city', '')
region = data.get('region', '')
country = data.get('country', '')
if city and city not in ['null', 'None', '']:
print(f"ipinfo定位成功: {city}, {region}, {country}")
# 如果城市信息不完整,尝试用地区信息补充
if len(city) < 2 and region:
city = region
return city
except Exception as e:
print(f"ipinfo接口失败: {e}")
pass
# API 3: 搜狐IP接口HTTP无SSL问题
try:
url = "http://pv.sohu.com/cityjson?ie=utf-8"
response = requests.get(url, timeout=5)
@ -1326,7 +1449,7 @@ class WeatherAPI:
print(f"搜狐IP接口失败: {e}")
pass
# API 2: 使用pconline接口HTTP
# API 4: 使用pconline接口HTTP
try:
url = "http://whois.pconline.com.cn/ipJson.jsp"
response = requests.get(url, timeout=5)
@ -1349,26 +1472,14 @@ class WeatherAPI:
print(f"pconline接口失败: {e}")
pass
# API 3: 使用ip-api.com接口更稳定的免费服务
# API 5: 使用淘宝IP接口
try:
url = "http://ip-api.com/json/"
response = requests.get(url, timeout=5)
response.raise_for_status()
data = response.json()
if data.get('status') == 'success':
city = data.get('city', '')
if city:
print(f"ip-api定位成功: {city}")
return city
except Exception as e:
print(f"ip-api接口失败: {e}")
pass
# API 4: 使用淘宝IP接口
try:
url = "http://ip.taobao.com/outGetIpInfo"
params = {'ip': '', 'accessKey': 'alibaba-inc'}
if ip_address:
url = "http://ip.taobao.com/outGetIpInfo"
params = {'ip': ip_address, 'accessKey': 'alibaba-inc'}
else:
url = "http://ip.taobao.com/outGetIpInfo"
params = {'ip': '', 'accessKey': 'alibaba-inc'}
response = requests.get(url, params=params, timeout=5)
response.raise_for_status()
@ -1387,25 +1498,42 @@ class WeatherAPI:
return None
except Exception as e:
print(f"IP定位总体失败: {e}")
return None
# 返回默认城市而不是None确保天气功能仍然可用
return "北京"
def get_current_location(self):
"""获取当前位置信息"""
try:
# 首先尝试通过IP获取位置
city = self.get_location_by_ip()
if city:
print(f"通过IP定位成功: {city}")
location_result = self.get_location_by_ip()
# 检查是否是默认城市表示IP定位失败
if location_result == "北京":
print("IP定位失败使用默认城市")
print("自动定位失败,建议手动选择城市")
return None
if location_result:
print(f"通过IP定位成功: {location_result}")
# 检查是否是教育网或特殊网络环境
isp_info = self.get_isp_info()
if isp_info and ('教育网' in isp_info or 'CERNET' in isp_info or 'University' in isp_info):
if isp_info and ('教育网' in isp_info or 'CERNET' in isp_info or 'University' in isp_info or '大学' in isp_info):
print(f"检测到教育网环境: {isp_info}")
print("教育网IP定位可能不准确建议手动选择城市")
# 教育网环境下如果定位到北京可能是IP分配问题
if city.lower() in ['beijing', '北京', 'haidian', '海淀']:
if isinstance(location_result, str) and location_result.lower() in ['beijing', '北京', 'haidian', '海淀']:
print("提示:教育网环境下北京定位可能是网络出口导致的")
return {'city': city, 'note': '教育网环境,定位可能不准确', 'isp': isp_info}
return {'city': location_result, 'note': '教育网环境,定位可能不准确', 'isp': isp_info}
# 处理返回结果格式
city = None
if isinstance(location_result, dict) and 'city' in location_result:
city = location_result['city']
elif isinstance(location_result, str):
city = location_result
else:
city = str(location_result)
# 智能处理 - 如果是区级单位,映射到市级城市
district_to_city_map = {
@ -1553,6 +1681,7 @@ class WeatherAPI:
except Exception as e:
print(f"获取当前位置失败: {e}")
# 即使出现异常也返回None而不是抛出异常确保程序继续运行
return None
def get_city_weather_by_name(self, city_name):

Loading…
Cancel
Save