新增获取省市区接口

This commit is contained in:
18610128193
2026-06-17 15:29:52 +08:00
parent 15179cd2a4
commit 189aef6a82
4 changed files with 23576 additions and 1 deletions
+241
View File
@@ -0,0 +1,241 @@
import json
import os
from typing import Optional, List, Dict
# 缓存文件路径
CACHE_FILE_PATH = os.path.join(os.path.dirname(__file__), 'area_cache.json')
class AreaInfo:
def __init__(self, code: str, name: str, level: str, geoname_id: int = None):
self.code = code
self.name = name
self.level = level
self.geoname_id = geoname_id
self.sub_districts: List[AreaInfo] = []
def to_dict(self):
return {
"code": self.code,
"name": self.name,
"level": self.level,
"geoname_id": self.geoname_id,
"sub_districts": [sd.to_dict() for sd in self.sub_districts] if self.sub_districts else [],
}
@classmethod
def from_dict(cls, data: dict):
area = cls(
code=data.get("code"),
name=data.get("name"),
level=data.get("level"),
geoname_id=data.get("geoname_id"),
)
sub_districts = data.get("sub_districts", [])
for sub in sub_districts:
area.sub_districts.append(cls.from_dict(sub))
return area
def parse_district_data(district_data: dict) -> AreaInfo:
"""解析巨量接口返回的区域数据"""
area = AreaInfo(
code=district_data.get("code"),
name=district_data.get("name"),
level=district_data.get("level"),
geoname_id=district_data.get("geoname_id"),
)
sub_districts = district_data.get("sub_districts")
if sub_districts:
for sub in sub_districts:
area.sub_districts.append(parse_district_data(sub))
return area
def save_area_cache(areas: List[AreaInfo]) -> None:
"""将区域数据保存到缓存文件"""
data = [area.to_dict() for area in areas]
with open(CACHE_FILE_PATH, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def load_area_cache() -> Optional[List[AreaInfo]]:
"""从缓存文件加载区域数据"""
if not os.path.exists(CACHE_FILE_PATH):
return None
try:
with open(CACHE_FILE_PATH, 'r', encoding='utf-8') as f:
data = json.load(f)
return [AreaInfo.from_dict(item) for item in data]
except (json.JSONDecodeError, IOError):
return None
def clear_area_cache() -> None:
"""清除缓存文件"""
if os.path.exists(CACHE_FILE_PATH):
os.remove(CACHE_FILE_PATH)
def filter_by_level(areas: List[AreaInfo], target_level: str) -> List[AreaInfo]:
"""
根据级别过滤区域信息
:param areas: 区域列表
:param target_level: ONE_LEVEL / TWO_LEVEL / THREE_LEVEL
:return: 指定级别的区域列表
"""
result = []
def traverse(area: AreaInfo):
if area.level == target_level:
filtered = AreaInfo(
code=area.code,
name=area.name,
level=area.level,
geoname_id=area.geoname_id,
)
result.append(filtered)
if area.sub_districts:
for sub in area.sub_districts:
traverse(sub)
for area in areas:
traverse(area)
return result
def get_first_level_areas(areas: List[AreaInfo]) -> List[AreaInfo]:
"""获取所有一级区域(省/直辖市)"""
return filter_by_level(areas, "ONE_LEVEL")
def get_second_level_areas(areas: List[AreaInfo], parent_code: str = None) -> List[AreaInfo]:
"""
获取二级区域(市)
:param areas: 区域列表
:param parent_code: 一级区域code,不传则返回所有二级区域
:return: 二级区域列表
"""
if parent_code:
def find_parent_and_get_children(area: AreaInfo):
if area.code == parent_code:
return [AreaInfo(
code=sub.code,
name=sub.name,
level=sub.level,
geoname_id=sub.geoname_id,
) for sub in area.sub_districts] if area.sub_districts else []
if area.sub_districts:
for sub in area.sub_districts:
result = find_parent_and_get_children(sub)
if result:
return result
return []
for area in areas:
result = find_parent_and_get_children(area)
if result:
return result
return []
else:
return filter_by_level(areas, "TWO_LEVEL")
def get_third_level_areas(areas: List[AreaInfo], parent_code: str) -> List[AreaInfo]:
"""
获取三级区域(区/县)
:param areas: 区域列表
:param parent_code: 二级区域code
:return: 三级区域列表
"""
def find_parent_and_get_children(area: AreaInfo):
if area.code == parent_code:
return [AreaInfo(
code=sub.code,
name=sub.name,
level=sub.level,
geoname_id=sub.geoname_id,
) for sub in area.sub_districts] if area.sub_districts else []
if area.sub_districts:
for sub in area.sub_districts:
result = find_parent_and_get_children(sub)
if result:
return result
return []
for area in areas:
result = find_parent_and_get_children(area)
if result:
return result
return []
def get_area_by_level(areas: List[AreaInfo], level: str, parent_code: str = None) -> List[AreaInfo]:
"""
根据级别获取区域信息
:param areas: 区域列表
:param level: ONE_LEVEL / TWO_LEVEL / THREE_LEVEL
:param parent_code: 父级区域codeTWO_LEVEL和THREE_LEVEL时可选/必填)
:return: 区域列表
"""
level = level.upper()
if level == "ONE_LEVEL":
return get_first_level_areas(areas)
elif level == "TWO_LEVEL":
return get_second_level_areas(areas, parent_code)
elif level == "THREE_LEVEL":
if not parent_code:
raise ValueError("获取三级区域需要提供二级区域code")
return get_third_level_areas(areas, parent_code)
else:
raise ValueError(f"不支持的级别: {level}")
async def fetch_and_cache_area_data(oauth_id: str, advertiser_id: str = 1836693172153543, code: str = "CN") -> List[AreaInfo]:
"""
从接口获取区域数据并缓存到文件
:param oauth_id: 授权ID
:param code: 行政区域编码,默认中国CN
:return: 区域列表
"""
from app.utils.douyinApi import DouyinApi
params = {
"advertiser_id": advertiser_id,
"codes": json.dumps([code]),
"language": "ZH_CN",
"sub_district": "THREE_LEVEL",
"version": "V2_3_2"
}
area_response = await DouyinApi().get_area(oauth_id=oauth_id, params=params)
if area_response.get("code") != 0:
raise Exception(f"获取区域信息失败: {area_response.get('message', '未知错误')}")
districts_data = area_response.get("data", {}).get("districts", [])
if not districts_data:
raise Exception("接口返回的区域数据为空")
area_list = [parse_district_data(d) for d in districts_data]
save_area_cache(area_list)
return area_list
def get_cached_area_data() -> Optional[List[AreaInfo]]:
"""获取缓存的区域数据"""
return load_area_cache()
File diff suppressed because it is too large Load Diff
+13
View File
@@ -52,4 +52,17 @@ class DouyinApi:
url,
'POST',
options
)
#获取区域信息
async def get_area(self, oauth_id: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
if not oauth_id:
raise RuntimeError('OAuth ID is not set.')
url = "https://api.oceanengine.com/open_api/2/tools/admin/info/"
return await self.request.request_with_token_with_context(
oauth_id,
url,
'GET',
{'params': params or {}}
)