196 lines
7.6 KiB
Python
196 lines
7.6 KiB
Python
"""功能模块"""
|
|||
|
|
import math
|
||
|
|
from typing import TypedDict, Union
|
||
|
|
|
||
|
|
import jmespath
|
||
|
|
import pydash
|
||
|
|
import requests
|
||
|
|
|
||
|
|
|
||
|
|
# WechatMapClass.haversine(lat1=32.
|
||
|
|
# 474664, lon1=119.893471, lat2=32.
|
||
|
|
# 471578, lon2=119.917068)
|
||
|
|
# WechatMapClass.addressToCoordinat
|
||
|
|
# eConversion(address="江苏省泰州市海陵区济川东路与青年南路交叉口东220米泰州万达广场(2号入口)")
|
||
|
|
# WechatMapClass.coordinateToAddressConversion(location="32.474664,119.893471")
|
||
|
|
# WechatMapClass.coordinateToAddressConversion(location="32.471578,119.917068")
|
||
|
|
class OriginPointOptional(TypedDict):
|
||
|
|
经度: Union[float, str]
|
||
|
|
纬度: Union[float, str]
|
||
|
|
|
||
|
|
|
||
|
|
from pydantic import BaseModel
|
||
|
|
|
||
|
|
|
||
|
|
class AdInfo(BaseModel):
|
||
|
|
city: str
|
||
|
|
adcode: int
|
||
|
|
nation: str
|
||
|
|
district: str
|
||
|
|
province: str
|
||
|
|
nation_code: int
|
||
|
|
|
||
|
|
|
||
|
|
class Location(BaseModel):
|
||
|
|
lat: float
|
||
|
|
lng: float
|
||
|
|
|
||
|
|
|
||
|
|
class Result(BaseModel):
|
||
|
|
ip: str
|
||
|
|
ad_info: AdInfo
|
||
|
|
location: Location
|
||
|
|
|
||
|
|
|
||
|
|
class IP解析地址模型Response(BaseModel):
|
||
|
|
result: Result
|
||
|
|
status: int
|
||
|
|
message: str
|
||
|
|
|
||
|
|
|
||
|
|
class wei地图工具:
|
||
|
|
"""注释"""
|
||
|
|
|
||
|
|
key = "7SNBZ-FLN63-LRA3S-YJBAK-XSHQ3-TGF5E" # 腾讯地图的key
|
||
|
|
|
||
|
|
# key = "LREBZ-PH5R7-2NIXW-H7JDB-CVHTK-4YFUJ" # 莫大帅注册地地图的腾讯地图的key
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def 公式计算二点之间的距离(cls, orgin原点: OriginPointOptional, user原点: OriginPointOptional) -> float:
|
||
|
|
""""""
|
||
|
|
# 地球半径,单位为公里
|
||
|
|
R = 6371.0
|
||
|
|
# orgin原点: OriginPointOptional = {"纬度": 30.80377, "经度": 104.151812}
|
||
|
|
# user原点: OriginPointOptional = {"纬度": 30.80377, "经度": 104.151812}
|
||
|
|
# 将角度转换为弧度
|
||
|
|
orgin纬度 = math.radians(orgin原点.get("纬度"))
|
||
|
|
orgin经度 = math.radians(orgin原点.get("经度"))
|
||
|
|
user纬度 = math.radians(user原点.get("纬度"))
|
||
|
|
user经度 = math.radians(user原点.get("纬度"))
|
||
|
|
|
||
|
|
# 经纬度差值
|
||
|
|
经度差 = user经度 - orgin经度
|
||
|
|
纬度差 = user纬度 - orgin纬度
|
||
|
|
print(经度差, 纬度差)
|
||
|
|
|
||
|
|
# Haversine公式
|
||
|
|
a = math.sin(纬度差 / 2) ** 2 + math.cos(orgin纬度) * math.cos(user纬度) * math.sin(经度差 / 2) ** 2
|
||
|
|
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
|
||
|
|
# 计算两点间的距离
|
||
|
|
distance = R * c
|
||
|
|
print(f"The distance between two points is {distance} km.")
|
||
|
|
return distance
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def 腾讯地图计算二点之间的距离(cls, toData终点: OriginPointOptional, fromData起点: OriginPointOptional):
|
||
|
|
""""""
|
||
|
|
fromStrDat = dict(sorted(fromData起点.items(), reverse=False))
|
||
|
|
fromStr = ",".join(fromStrDat.values())
|
||
|
|
toStrDat = dict(sorted(toData终点.items(), reverse=False))
|
||
|
|
toStr = ",".join(toStrDat.values())
|
||
|
|
print("排序后的值为", fromStr, toStr)
|
||
|
|
data = {"key": cls.key, "from": fromStr, "to": toStr}
|
||
|
|
url = f"https://apis.map.qq.com/ws/distance/v1/matrix?mode=driving"
|
||
|
|
res_data = requests.post(url=url, data=data)
|
||
|
|
print(res_data.json())
|
||
|
|
res_json = res_data.json() # type: dict
|
||
|
|
d = {
|
||
|
|
'status': 0,
|
||
|
|
'message': 'Success',
|
||
|
|
'request_id': '9435209f1ee84219ae7826e65f577331',
|
||
|
|
'result': {
|
||
|
|
'rows': [{
|
||
|
|
'elements': [{
|
||
|
|
'distance': 3550, # 起点到终点的距离,单位:米
|
||
|
|
'duration': 651, # 表示从起点到终点的结合路况的时间,秒为单位注:步行/骑行方式(不计算耗时)以及起终点附近没有道路造成无法计算时,不返回本此节点
|
||
|
|
}],
|
||
|
|
}],
|
||
|
|
},
|
||
|
|
}
|
||
|
|
distance = jmespath.search(data=res_data.json(), expression="result.rows[0].elements[0].distance")
|
||
|
|
return distance
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def 地址转换为坐标(cls, address: str):
|
||
|
|
""""""
|
||
|
|
url = f"https://apis.map.qq.com/ws/geocoder/v1/?address={address}"
|
||
|
|
res = requests.get(url=url, params={"key": cls.key}, )
|
||
|
|
d = {
|
||
|
|
'status': 0,
|
||
|
|
'message': 'Success',
|
||
|
|
'request_id': '9b049a3ff13c4ac3bda3bb5a9fe0c0a8',
|
||
|
|
'result': {
|
||
|
|
'title': '泰州海陵万达广场',
|
||
|
|
'location': { # 解析到的坐标(GCJ02坐标系)
|
||
|
|
'lng': 119.917068, # 经度
|
||
|
|
'lat': 32.471578, # 纬度
|
||
|
|
},
|
||
|
|
'ad_info': { # 行政区划信息 object 是
|
||
|
|
'adcode': '321202', # string 是 行政区划代码,规则详见:行政区划代码说明
|
||
|
|
},
|
||
|
|
'address_components': {
|
||
|
|
'province': '江苏省',
|
||
|
|
'city': '泰州市',
|
||
|
|
'district': '海陵区',
|
||
|
|
'street': '济川东路',
|
||
|
|
'street_number': '',
|
||
|
|
},
|
||
|
|
'similarity': 0.99,
|
||
|
|
'deviation': 1000,
|
||
|
|
'reliability': 7, # 可信度参考:值范围 1 <低可信> - 10 <高可信>
|
||
|
|
'level': 11, # 解析精度级别,分为11个级别,一般>=9即可采用(定位到点,精度较高) 也可根据实际业务需求自行调整,完整取值表见下文。
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def 经纬度转换为地址(cls, location):
|
||
|
|
""""""
|
||
|
|
pass
|
||
|
|
url = f'https://apis.map.qq.com/ws/geocoder/v1/?location={location}'
|
||
|
|
res = requests.get(url=url, params={"key": cls.key}, )
|
||
|
|
return res.json()
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def ip地址转为地址(cls, x_forwarded_for: str | bool, ):
|
||
|
|
""""""
|
||
|
|
url = "https://apis.map.qq.com/ws/location/v1/ip"
|
||
|
|
response_data = requests.get(url=url, params={"key": cls.key, "ip": x_forwarded_for}, )
|
||
|
|
data = response_data.json() # type: dict
|
||
|
|
print(data)
|
||
|
|
resData = pydash.omit(data, "request_id")
|
||
|
|
d = {
|
||
|
|
'status': 0,
|
||
|
|
'message': 'Success',
|
||
|
|
'request_id': '8805bff3303f42dd8a1cbcca3701cf63',
|
||
|
|
'result': {
|
||
|
|
'ip': '240e:3a3:b201:3f10:185c:efdb:c5b0:b95c',
|
||
|
|
'location': {
|
||
|
|
'lat': 32.49098,
|
||
|
|
'lng': 119.91956,
|
||
|
|
},
|
||
|
|
'ad_info': {
|
||
|
|
'nation': '中国',
|
||
|
|
'province': '江苏省',
|
||
|
|
'city': '泰州市',
|
||
|
|
'district': '海陵区',
|
||
|
|
'adcode': 321202,
|
||
|
|
'nation_code': 156,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
# nation = jmespath.search(data=data, expression="result.ad_info.nation", ) # 国家
|
||
|
|
# province = jmespath.search(data=data, expression="result.ad_info.province", ) # 省份
|
||
|
|
# city = jmespath.search(data=data, expression="result.ad_info.city", )
|
||
|
|
# district = jmespath.search(data=data, expression="result.ad_info.district", ) # 区
|
||
|
|
# adcode = jmespath.search(data=data, expression="result.ad_info.adcode", ) # 区号
|
||
|
|
# ip = jmespath.search(data=data, expression="result.ip", )
|
||
|
|
# lat = jmespath.search(data=data, expression="result.location.lat", )
|
||
|
|
# lng = jmespath.search(data=data, expression="result.location.lng", )
|
||
|
|
|
||
|
|
return resData
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
# wei地图工具.腾讯地图计算二点之间的距离(toData终点={"纬度": "30.80377", "经度": "104.151812"}, fromData起点={"纬度": "30.80377", "经度": "104.151812"})
|
||
|
|
print(wei地图工具.ip地址转为地址(x_forwarded_for="119.84.150.100", ))
|