IPWeatherObject.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. # @Author : Rocky
  2. # @File : IPWeatherObject.py
  3. # @Time : 2023/8/16 8:56
  4. import datetime
  5. import geoip2.webservice
  6. import requests
  7. from Model.models import IPAddr, OpenWeatherMapCallCount
  8. from Object.RedisObject import RedisObject
  9. from Service.CommonService import CommonService
  10. from Ansjer.config import LOGGER
  11. class IPQuery:
  12. """
  13. 阿里云IP地址查询
  14. https://market.aliyun.com/products/57002003/cmapi021970.html?spm=5176.2020520132.recommend-card.dbottom-suggestion.33e17218GYjWDt#sku=yuncode15970000020
  15. """
  16. def __init__(self, ip):
  17. self.appcode = 'd7d63b34b1d54214be446608a57ff0a2'
  18. self.host = 'https://c2ba.api.huachen.cn'
  19. self.path = '/ip'
  20. self.district = '' # 区
  21. self.city = '' # 市
  22. self.region = '' # 省/州
  23. self.country_id = ''
  24. param = 'ip=' + ip
  25. url = self.host + self.path + '?' + param
  26. # 获取ip的区级和城市信息
  27. headers = {'Authorization': 'APPCODE ' + self.appcode}
  28. res = requests.get(url=url, headers=headers)
  29. if res.status_code == 200:
  30. # 反序列化响应数据
  31. res_data = eval(res.content.decode('utf-8'))
  32. if res_data['ret'] == 200:
  33. district = res_data['data']['district']
  34. city = res_data['data']['city']
  35. region = res_data['data']['region']
  36. country_id = res_data['data']['country_id']
  37. # 国内城市数据不为空字符,拼上'市'字
  38. if country_id == 'CN' and city != '':
  39. city += '市'
  40. # ip地址信息存表或更新
  41. ip_addr_qs = IPAddr.objects.filter(ip=ip, is_geoip2=False)
  42. if ip_addr_qs.exists():
  43. ip_addr_qs.update(district=district, city=city, region=region, country_code=country_id)
  44. else:
  45. IPAddr.objects.create(ip=ip, district=district, city=city, region=region, country_code=country_id)
  46. # 确定天气城市
  47. if district != '':
  48. self.district = district
  49. elif city != '':
  50. self.district = city
  51. self.country_id = country_id
  52. class WeatherInfo:
  53. """
  54. 阿里云墨迹天气服务
  55. https://market.aliyun.com/products/57096001/cmapi013828.html?spm=5176.2020520132.101.19.2b8f7218NuiGPd#sku=yuncode782800000
  56. """
  57. def __init__(self, city_id):
  58. self.appcode = 'd7d63b34b1d54214be446608a57ff0a2'
  59. self.headers = {'Authorization': 'APPCODE ' + self.appcode,
  60. 'Content-Type': 'application/x-www-form-urlencoded'}
  61. self.city_id = city_id
  62. def get_city_weather(self):
  63. url = "https://aliv18.data.moji.com/whapi/json/alicityweather/condition" # 获取实时天气
  64. data = {'cityId': self.city_id}
  65. response = requests.post(url, headers=self.headers, data=data, verify=False)
  66. if response.status_code == 200:
  67. result = response.json()
  68. if result['code'] == 0:
  69. # 返回温湿度
  70. return result['data']['condition']['temp'], result['data']['condition']['humidity']
  71. return None, None
  72. def get_city_24_weather(self):
  73. url = 'https://aliv18.data.moji.com/whapi/json/alicityweather/forecast24hours' # 获取城市24小时天气
  74. data = {'cityId': self.city_id}
  75. response = requests.post(url, headers=self.headers, data=data, verify=False)
  76. if response.status_code == 200:
  77. result = response.json()
  78. if result['code'] == 0:
  79. # 返回天气列表
  80. return result['data']['hourly']
  81. return None
  82. class GeoIP2:
  83. """
  84. MaxMind GeoIP2查询国外ip
  85. 同时保存ip信息
  86. https://www.maxmind.com/
  87. """
  88. def __init__(self, ip):
  89. self.account_id = 938644
  90. self.license_key = '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'
  91. self.license_key_sandbox = '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'
  92. try:
  93. with geoip2.webservice.Client(self.account_id, self.license_key) as client:
  94. # You can also use `client.city` or `client.insights`
  95. # `client.insights` is not available to GeoLite2 users
  96. response = client.city(ip)
  97. # 经纬度精确到小数点两位
  98. lat = round(response.location.latitude, 2)
  99. lon = round(response.location.longitude, 2)
  100. # 获取中文或英文城市名,省/州
  101. city = ''
  102. city_names = response.city.names
  103. city_cn = city_names.get('zh-CN')
  104. if city_cn:
  105. city = city_cn
  106. elif city_names.get('en'):
  107. city = city_names['en']
  108. region = ''
  109. subdivisions_names = response.subdivisions[0].names
  110. region_cn = subdivisions_names.get('zh-CN')
  111. if region_cn:
  112. region = region_cn
  113. elif subdivisions_names.get('en'):
  114. region = subdivisions_names['en']
  115. country_code = response.country.iso_code
  116. # 保存ip信息
  117. ip_addr_data = {
  118. 'ip': ip,
  119. 'lat': lat,
  120. 'lon': lon,
  121. 'city': city,
  122. 'region': region,
  123. 'country_code': country_code,
  124. 'is_geoip2': True
  125. }
  126. IPAddr.objects.create(**ip_addr_data)
  127. except Exception as e:
  128. LOGGER.info('GeoIP2解析ip异常:error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  129. class OpenWeatherMap:
  130. """
  131. OpenWeatherMap查询国外天气服务
  132. https://openweathermap.org/
  133. """
  134. def __init__(self, lat, lon):
  135. self.appid = '7a6cd7dfeb034ededa451ed575788857'
  136. self.lat = lat # 纬度
  137. self.lon = lon # 经度
  138. def get_weather(self):
  139. """
  140. 从缓存查询天气数据
  141. 或者查询当前天气,并缓存数据
  142. @return: temp, humidity
  143. """
  144. # 查询缓存数据
  145. today = datetime.datetime.today()
  146. now_time = datetime.datetime(today.year, today.month, today.day, today.hour)
  147. str_time = now_time.strftime('%Y-%m-%d %H:%M:%S')
  148. time_stamp = CommonService.str_to_timestamp(str_time)
  149. key = 'weather:lat:{}_lon:{}_time_stamp:{}'.format(self.lat, self.lon, time_stamp)
  150. redis_obj = RedisObject()
  151. weather = redis_obj.get_data(key)
  152. if weather:
  153. temp, humidity = weather.split('/')
  154. else:
  155. temp, humidity = self.get_current_weather(str_time[:7])
  156. if temp is not None and humidity is not None:
  157. key = 'weather:lat:{}_lon:{}_time_stamp:{}'.format(self.lat, self.lon, time_stamp)
  158. redis_obj.set_ex_data(key, '{}/{}'.format(temp, humidity), 3600)
  159. return temp, humidity
  160. def get_current_weather(self, month):
  161. """
  162. 根据经纬度获取当前天气
  163. @param month: 年月份
  164. @return: temp, humidity
  165. """
  166. url = 'https://api.openweathermap.org/data/2.5/weather'
  167. params = {
  168. 'lat': self.lat,
  169. 'lon': self.lon,
  170. 'appid': self.appid,
  171. 'units': 'metric' # 公制单位,温度单位:摄氏度
  172. }
  173. res = requests.get(url=url, params=params, timeout=10)
  174. # 记录调用次数
  175. open_weather_map_call_count_qs = OpenWeatherMapCallCount.objects.filter(month=month).values('count')
  176. if not open_weather_map_call_count_qs.exists():
  177. OpenWeatherMapCallCount.objects.create(month=month)
  178. else:
  179. count = open_weather_map_call_count_qs[0]['count'] + 1
  180. open_weather_map_call_count_qs.update(count=count)
  181. if res.status_code != 200:
  182. return None, None
  183. res_data = eval(res.text)
  184. if res_data['cod'] != 200:
  185. return None, None
  186. temp = int(res_data['main']['temp'])
  187. humidity = int(res_data['main']['humidity'])
  188. return temp, humidity