你是否曾需要获取实时天气数据用于出行规划?或是需要抓取股价信息进行投资分析?当手动复制粘贴无法满足需求时,API接口数据获取就成了必备技能。
一、API数据获取的痛点与挑战
二、VBA方案:繁琐但可行的传统路径
2.1 VBA实现API调用的基础框架
Sub GetAPIDataWithVBA()Dim httpRequest As ObjectDim url As StringDim responseText As String' 创建HTTP请求对象Set httpRequest = CreateObject("MSXML2.XMLHTTP")url = "https://api.openweathermap.org/data/2.5/weather?q=Beijing&appid=your_api_key"' 发送GET请求httpRequest.Open "GET", url, FalsehttpRequest.send' 检查请求状态If httpRequest.Status = 200 ThenresponseText = httpRequest.responseText' 处理返回的JSON数据Call ProcessJSONData(responseText)ElseMsgBox "API请求失败,状态码:" & httpRequest.StatusEnd IfEnd Sub
2.2 VBA解析JSON的复杂过程
Function ParseJSONWithVBA(jsonString As String) As ObjectOn Error GoTo ErrorHandlerDim sc As ObjectSet sc = CreateObject("ScriptControl")sc.Language = "JScript"' 注入JSON解析函数sc.AddCode "function parseJson(json){ return JSON.parse(json); }"Set ParseJSONWithVBA = sc.Run("parseJson", jsonString)Exit FunctionErrorHandler:Set ParseJSONWithVBA = NothingErr.Raise 1001, "JSON Parser", "解析失败: " & Err.DescriptionEnd FunctionSub ProcessJSONData(jsonString As String)Dim jsonObject As ObjectSet jsonObject = ParseJSONWithVBA(jsonString)' 访问解析后的数据Dim temperature As Doubletemperature = jsonObject("main")("temp") - 273.15 ' 开尔文转摄氏度' 输出到Excel单元格ThisWorkbook.Sheets("数据").Range("A1").Value = "当前温度"ThisWorkbook.Sheets("数据").Range("B1").Value = temperature & "℃"End Sub
2.3 VBA方案的限制与应对策略
Sub RobustAPICall()On Error GoTo ErrorHandlerDim retryCount As IntegerConst maxRetries As Integer = 3For retryCount = 1 To maxRetriesTryCall GetAPIDataWithVBAExit SubCatch ex As ExceptionIf retryCount = maxRetries ThenErr.Raise 1002, "API调用", "多次重试后仍失败"End If' 等待后重试Application.Wait Now + TimeValue("00:00:02")End TryNext retryCountErrorHandler:Call LogError("API调用失败: " & Err.Description)End Sub
三、Python方案:简洁高效的现代方法
3.1 简洁的API请求与JSON解析
import requestsimport jsondef get_weather_data(city_name, api_key):"""获取天气数据并解析"""url = f"https://api.openweathermap.org/data/2.5/weather?q={city_name}&appid={api_key}"try:response = requests.get(url)response.raise_for_status() # 自动处理HTTP错误# 直接解析JSON响应data = response.json()# 提取所需信息temperature_kelvin = data['main']['temp']temperature_celsius = temperature_kelvin - 273.15weather_description = data['weather'][0]['description']return {'temperature': round(temperature_celsius, 1),'description': weather_description,'city': data['name']}except requests.exceptions.RequestException as e:print(f"API请求失败: {e}")return None# 使用示例weather_info = get_weather_data("Beijing", "your_api_key")if weather_info:print(f"城市: {weather_info['city']}")print(f"温度: {weather_info['temperature']}℃")print(f"天气: {weather_info['description']}")
3.2 高级功能与实战技巧
def get_authenticated_api_data(api_url, api_key):"""处理需要认证的API请求"""headers = {'Authorization': f'Bearer {api_key}','Content-Type': 'application/json'}try:response = requests.get(api_url, headers=headers, timeout=10)response.raise_for_status()return response.json()except requests.exceptions.Timeout:print("请求超时")return Noneexcept requests.exceptions.HTTPError as err:print(f"HTTP错误: {err}")return None# 分页获取所有数据def get_paginated_api_data(base_url, api_key):"""处理分页API数据"""all_data = []page = 1while True:url = f"{base_url}?page={page}&limit=100"data = get_authenticated_api_data(url, api_key)if not data or len(data) == 0:breakall_data.extend(data)page += 1# 避免过于频繁的请求time.sleep(0.5)return all_data
import pandas as pdfrom datetime import datetime, timedeltaclass APIDataManager:"""API数据管理器,支持缓存和批量处理"""def __init__(self, cache_duration=3600): # 默认缓存1小时self.cache_duration = cache_durationself.cache = {}def get_cached_data(self, cache_key):"""获取缓存数据"""if cache_key in self.cache:cached_time, data = self.cache[cache_key]if datetime.now() - cached_time < timedelta(seconds=self.cache_duration):return datareturn Nonedef get_multiple_cities_weather(self, cities, api_key):"""批量获取多个城市天气数据"""results = []for city in cities:cache_key = f"weather_{city}"cached_data = self.get_cached_data(cache_key)if cached_data:results.append(cached_data)else:data = get_weather_data(city, api_key)if data:self.cache[cache_key] = (datetime.now(), data)results.append(data)# 避免触发API限流time.sleep(0.2)return pd.DataFrame(results)# 使用示例manager = APIDataManager()cities = ["Beijing", "Shanghai", "Guangzhou", "Shenzhen"]weather_df = manager.get_multiple_cities_weather(cities, "your_api_key")print(weather_df)
3.3 错误处理与重试机制
from tenacity import retry, stop_after_attempt, wait_exponentialclass RobustAPIClient:"""健壮的API客户端,带重试机制"""def __init__(self, base_retry_delay=1, max_retries=3):self.base_retry_delay = base_retry_delayself.max_retries = max_retries@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))def reliable_api_call(self, url, headers=None, timeout=30):"""带重试的API调用"""try:response = requests.get(url, headers=headers, timeout=timeout)response.raise_for_status()return response.json()except requests.exceptions.ConnectionError:print("网络连接错误,重试中...")raiseexcept requests.exceptions.Timeout:print("请求超时,重试中...")raisedef get_with_fallback(self, primary_url, fallback_url, headers=None):"""带降级方案的API调用"""try:return self.reliable_api_call(primary_url, headers)except Exception as e:print(f"主API失败: {e},尝试备用API")try:return self.reliable_api_call(fallback_url, headers)except Exception as fallback_error:print(f"备用API也失败: {fallback_error}")return None
四、VBA与Python方案深度对比
4.1 技术能力对比
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4.2 开发效率对比
-
基础API调用:VBA需要15-20行,Python仅需5-8行 -
JSON解析:VBA需要10-15行(含外部依赖),Python仅需1行 -
错误处理:VBA需要5-10行,Python需2-3行(使用try-except)
-
VBA总代码量:约40-50行(含JSON解析函数) -
Python总代码量:约10-15行(含错误处理)
4.3 适用场景建议
-
已有Excel工作流,只需简单扩展API功能 -
数据量小,API结构简单 -
团队VBA技术栈成熟,无Python环境 -
一次性任务,无需长期维护
-
复杂API集成,需要认证、分页等高级功能 -
大数据量处理,需要批量请求和缓存 -
生产环境需求,需要健壮的错误处理 -
长期维护项目,需要可读性和可扩展性
五、实战案例:股价监控系统
5.1 业务需求分析
5.2 Python完整解决方案
import requestsimport pandas as pdimport timeimport smtplibfrom datetime import datetimefrom email.mime.text import MIMETextclass StockMonitor:"""股票价格监控系统"""def __init__(self, api_key, alert_emails):self.api_key = api_keyself.alert_emails = alert_emailsself.stock_data = pd.DataFrame()def fetch_stock_prices(self, symbols):"""获取多支股票价格"""base_url = "https://api.example-stock-api.com/v1/quote"results = []for symbol in symbols:url = f"{base_url}?symbol={symbol}&apikey={self.api_key}"try:response = requests.get(url, timeout=10)data = response.json()results.append({'symbol': symbol,'price': data['currentPrice'],'change': data['change'],'percent_change': data['changePercent'],'timestamp': datetime.now()})except Exception as e:print(f"获取{symbol}数据失败: {e}")# 避免频繁请求time.sleep(0.1)return pd.DataFrame(results)def check_alerts(self, alert_rules):"""检查价格预警"""alerts = []for _, rule in alert_rules.iterrows():symbol = rule['symbol']threshold = rule['threshold']current_data = self.stock_data[self.stock_data['symbol'] == symbol]if not current_data.empty:current_price = current_data.iloc[0]['price']if current_price <= threshold:alerts.append({'symbol': symbol,'current_price': current_price,'threshold': threshold,'timestamp': datetime.now()})return alertsdef send_email_alert(self, alert_info):"""发送邮件预警"""msg = MIMEText(f"股票{alert_info['symbol']}价格预警!\n"f"当前价格: {alert_info['current_price']}\n"f"预警阈值: {alert_info['threshold']}\n"f"时间: {alert_info['timestamp']}")msg['Subject'] = f"股票预警 {alert_info['symbol']}"msg['From'] = "monitor@company.com"msg['To'] = ", ".join(self.alert_emails)try:smtp_server = smtplib.SMTP('smtp.company.com', 587)smtp_server.send_message(msg)smtp_server.quit()print(f"已发送{alert_info['symbol']}预警邮件")except Exception as e:print(f"邮件发送失败: {e}")def run_monitoring(self, symbols, alert_rules, interval=300):"""运行监控循环"""while True:print(f"{datetime.now()} - 开始获取股票数据")# 获取最新数据new_data = self.fetch_stock_prices(symbols)self.stock_data = new_data# 检查预警alerts = self.check_alerts(alert_rules)for alert in alerts:self.send_email_alert(alert)# 保存历史数据self.save_to_database(new_data)print(f"本轮监控完成,发现{len(alerts)}个预警")time.sleep(interval)# 使用示例if __name__ == "__main__":monitor = StockMonitor(api_key="your_stock_api_key",alert_emails=["trader1@company.com", "trader2@company.com"])symbols = ["AAPL", "GOOGL", "MSFT", "TSLA", "AMZN"]alert_rules = pd.DataFrame([{"symbol": "AAPL", "threshold": 150.0},{"symbol": "GOOGL", "threshold": 2500.0}])monitor.run_monitoring(symbols, alert_rules)
测试题
-
在VBA中调用API时,常用的主要对象是什么?它支持哪些HTTP方法? -
Python的requests库中,response.raise_for_status()方法的作用是什么? -
VBA和Python在解析JSON数据时的主要区别有哪些? -
在处理需要分页的API数据时,Python相比VBA有什么优势? -
为什么说Python更适合用于生产环境的API数据获取任务?
答案
-
VBA中使用MSXML2.XMLHTTP对象,它支持GET、POST等基本HTTP方法,但需要手动设置请求头和处理响应。 -
raise_for_status()会自动检查HTTP状态码,如果状态码表示错误(4xx或5xx),会自动抛出异常,简化错误处理流程。 -
VBA需要依赖外部组件或自定义函数解析JSON,而Python有内置json库;VBA处理复杂嵌套结构困难,Python可以轻松处理多层嵌套;VBA错误信息不友好,Python有清晰的异常信息。 -
Python支持更简洁的循环和条件逻辑,可以轻松实现自动分页;有丰富的第三方库支持复杂分页逻辑;更好的错误处理和重试机制保障数据完整性。 -
Python有更完善的网络请求功能,支持连接池、超时控制、重试机制;丰富的生态系统提供监控、日志、缓存等工具;更好的性能和支持异步并发处理。
点击下方阅读原文可以加入我的知识星球!

