在Pandas DataFrame中迭代Google Analytics API报错及结果转DataFrame问题
问题分析与解决方案
一、解决TypeError: Object of type 'date' is not JSON serializable错误
这个报错的核心原因有两点:
- 日期类型不兼容:你的
date_和date_date字段是Python原生的date对象,但Google Analytics API要求日期参数必须是**YYYY-MM-DD格式的字符串**,JSON无法直接序列化date对象。 - 参数格式错误:你给
start_date和end_date传了列表(比如[f.loc[i]['date_']]),但API的dateRanges配置里,startDate和endDate只接受单个字符串,不需要用列表包裹。
修复步骤
- 把
date对象通过strftime('%Y-%m-%d')转换成符合要求的字符串; - 去掉参数的列表包裹,直接传入字符串。
修改后的API调用参数部分:
start_date=f.loc[i]['date_'].strftime('%Y-%m-%d'), end_date=f.loc[i]['date_date'].strftime('%Y-%m-%d'),
同时,你的get_report函数里的dateRanges配置要对应调整(现在传的是单个字符串,无需额外处理):
"dateRanges":[{"startDate": start_date, "endDate": end_date}],
二、将API响应结构化为DataFrame
你的现有代码在结果收集上存在两个问题:
lista在循环内每次都会重新初始化,最后只会保留最后一次的API结果;- 如果
print_response只是打印响应而不返回DataFrame,那df会是None,根本无法添加到列表中。
完整优化后的代码示例
假设你的print_response还没有实现响应转DataFrame的逻辑,我会帮你补充这个核心转换函数:
import pandas as pd import time # 定义响应转DataFrame的函数 def response_to_df(response): reports = response.get('reports', []) if not reports: return pd.DataFrame() report = reports[0] # 提取维度和指标的表头 dim_headers = [col['name'] for col in report.get('columnHeader', {}).get('dimensions', [])] metric_headers = [col['name'] for col in report.get('columnHeader', {}).get('metricHeader', {}).get('metricHeaderEntries', [])] all_headers = dim_headers + metric_headers # 提取每行数据 rows = [] for row in report.get('data', {}).get('rows', []): dim_values = row.get('dimensions', []) metric_values = row.get('metrics', [])[0].get('values', []) rows.append(dim_values + metric_values) return pd.DataFrame(rows, columns=all_headers) # 初始化结果列表(放在循环外面!) result_list = [] for i in f.index: # 调用修复后的API请求 api_response = get_report( config.service, start_date=f.loc[i]['date_'].strftime('%Y-%m-%d'), end_date=f.loc[i]['date_date'].strftime('%Y-%m-%d'), view_id='xxxxxxxx', metrics=[{'expression': 'ga:pageViews'}], dimensionFilterClauses= [{ "filters": [{ "dimensionName": "ga:pageTitle", "expressions": [f.loc[i]['title_']] }] }], dimensions=[{"name": "ga:pageTitle"}] ) # 转换为DataFrame并添加到列表 current_df = response_to_df(api_response) # 额外关联原数据的日期字段,让结果更完整 current_df['original_start_date'] = f.loc[i]['date_'] current_df['original_end_date'] = f.loc[i]['date_date'] result_list.append(current_df) time.sleep(2) # 合并所有小DataFrame为最终的大DataFrame final_result_df = pd.concat(result_list, ignore_index=True) print(final_result_df)
额外说明
- 如果你的
print_response原本就有返回DataFrame的逻辑,直接替换成你的函数即可; - 添加
original_start_date和original_end_date字段,能让最终结果和原输入数据关联起来,方便后续分析; - 循环中的
time.sleep(2)是合理的,能避免触发Google Analytics API的请求频率限制。
内容的提问来源于stack exchange,提问作者Othman
相关产品推荐
相关产品推荐

