weather.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import requests
  2. import os
  3. from dotenv import load_dotenv
  4. load_dotenv()
  5. class Weather:
  6. """天气查询类,封装OpenWeatherMap API功能"""
  7. def __init__(self, api_key=None, unit='metric'):
  8. """
  9. 初始化Weather类
  10. :param api_key: OpenWeatherMap API密钥,默认为环境变量中的OPENWEATHER_API_KEY
  11. :param unit: 温度单位(metric=摄氏,imperial=华氏)
  12. """
  13. self.api_key = api_key or os.environ.get("OPENWEATHER_API_KEY")
  14. self.unit = unit
  15. self.base_url = "http://api.openweathermap.org/data/2.5/weather"
  16. # 如果没有API密钥,使用模拟数据
  17. self.demo_mode = not self.api_key
  18. if self.demo_mode:
  19. print("⚠️ 警告: 未设置API密钥,使用演示模式")
  20. print(" 请设置OPENWEATHER_API_KEY环境变量以获得真实天气数据")
  21. def get_weather(self, city_name):
  22. """
  23. 查询指定城市的天气信息
  24. :param city_name: 城市名称(英文)
  25. :return: 格式化后的天气信息字符串
  26. """
  27. # 如果是演示模式,使用模拟数据
  28. if self.demo_mode:
  29. return self._get_demo_weather()
  30. params = {
  31. "q": city_name,
  32. "appid": self.api_key,
  33. "units": self.unit
  34. }
  35. try:
  36. response = requests.get(self.base_url, params=params)
  37. data = response.json()
  38. if response.status_code == 200:
  39. return self._format_weather_data(data)
  40. else:
  41. return f"错误 {data['cod']}: {data['message']}"
  42. except Exception as e:
  43. return f"请求失败: {str(e)}"
  44. def get_weather_details(self, city_name):
  45. """
  46. 获取详细的天气数据(字典格式)
  47. :param city_name: 城市名称(英文)
  48. :return: 包含详细天气数据的字典
  49. """
  50. # 如果是演示模式,使用模拟数据
  51. if self.demo_mode:
  52. return self._get_demo_weather()
  53. params = {
  54. "q": city_name,
  55. "appid": self.api_key,
  56. "units": self.unit
  57. }
  58. try:
  59. response = requests.get(self.base_url, params=params)
  60. data = response.json()
  61. if response.status_code == 200:
  62. return self._parse_weather_data(data)
  63. else:
  64. return {"error": f"错误 {data['cod']}: {data['message']}"}
  65. except Exception as e:
  66. return {"error": f"请求失败: {str(e)}"}
  67. def _get_demo_weather(self):
  68. return {
  69. "city": 'shanghai',
  70. "temperature": 25,
  71. "temperature_unit": "°C",
  72. "description": "晴天",
  73. "humidity": 60,
  74. "wind_speed": 10,
  75. "wind_unit": "m/s"
  76. }
  77. def _parse_weather_data(self, data):
  78. """
  79. 解析天气数据为字典格式
  80. :param data: API返回的原始数据
  81. :return: 解析后的天气数据字典
  82. """
  83. weather_desc = data['weather'][0]['description'].title()
  84. temp = data['main']['temp']
  85. humidity = data['main']['humidity']
  86. wind_speed = data['wind']['speed']
  87. city = data['name']
  88. return {
  89. "city": city,
  90. "temperature": temp,
  91. "temperature_unit": "°C" if self.unit == 'metric' else "°F",
  92. "description": weather_desc,
  93. "humidity": humidity,
  94. "wind_speed": wind_speed,
  95. "wind_unit": "m/s"
  96. }
  97. def _format_weather_data(self, data):
  98. """
  99. 格式化天气数据为字符串
  100. :param data: API返回的原始数据
  101. :return: 格式化后的天气信息字符串
  102. """
  103. weather_data = self._parse_weather_data(data)
  104. return (
  105. f"🏙️ 城市: {weather_data['city']}\n"
  106. f"🌡️ 温度: {weather_data['temperature']}{weather_data['temperature_unit']}\n"
  107. f"📝 天气: {weather_data['description']}\n"
  108. f"💧 湿度: {weather_data['humidity']}%\n"
  109. f"🌬️ 风速: {weather_data['wind_speed']} {weather_data['wind_unit']}"
  110. )
  111. def set_unit(self, unit):
  112. """
  113. 设置温度单位
  114. :param unit: 温度单位(metric=摄氏,imperial=华氏)
  115. """
  116. if unit not in ['metric', 'imperial']:
  117. raise ValueError("单位必须是 'metric' 或 'imperial'")
  118. self.unit = unit
  119. def set_api_key(self, api_key):
  120. """
  121. 设置API密钥
  122. :param api_key: 新的API密钥
  123. """
  124. self.api_key = api_key
  125. def get_weather(city_name, api_key=os.environ.get("OPENWEATHER_API_KEY"), unit='metric'):
  126. """
  127. 向后兼容的函数,使用Weather类实现
  128. :param city_name: 城市名称(英文)
  129. :param api_key: 你的OpenWeatherMap API密钥
  130. :param unit: 温度单位(metric=摄氏,imperial=华氏)
  131. :return: 格式化后的天气信息
  132. """
  133. weather = Weather(api_key=api_key, unit=unit)
  134. return weather.get_weather(city_name)
  135. # 使用示例
  136. if __name__ == "__main__":
  137. weather = Weather()
  138. weather_info = weather.get_weather("harbin")
  139. print(weather_info)