PyInstaller打包Google Analytics依赖时出现UnknownApiNameOrVersion错误
问题描述
使用以下导入语句:
from apiclient import discovery from oauth2client.service_account import ServiceAccountCredentials
尝试用PyInstaller将脚本打包为单文件exe,命令如下:
pyinstaller --onefile -w --icon=icon.ico --add-data client_secrets.json;. main.py --collect-data "google-api-python-client" --collect-data "oauth2client";
也试过:
pyinstaller --onefile -w --icon=icon.ico --add-data client_secrets.json;. main.py --collect-data google-api-python-client --collect-data oauth2client;
但运行生成的exe时出现错误:
Failed to execute script 'main' due to unhandled exception: name analytics version: v3 File "main.py", line 81, in <module> File "main.py", line 32, in get_service File "googleapiclient\_helpers.py", line 130, in positional_wrapper File "googleapiclient\discovery.py", line 287, in build File "googleapiclient\discovery.py", line 404, in _retrieve_discovery_doc googleapiclient.errors.UnknownApiNameOrVersion: name: analytics version: v3
原Python脚本运行正常,复现代码如下:
from apiclient import discovery from oauth2client.service_account import ServiceAccountCredentials import os dir_path = os.path.dirname(os.path.realpath(__file__)) def get_service(api_name, api_version, scopes, key_file_location): credentials = ServiceAccountCredentials.from_json_keyfile_name( key_file_location, scopes=scopes) # Build the service object. # service = build(api_name, api_version, credentials=credentials) service = discovery.build(api_name, api_version, credentials=credentials) return service if __name__ == '__main__': scope = 'https://www.googleapis.com/auth/analytics.edit' # client_secret from console.cloud.google.com key_file_location = f'{dir_path}/client_secrets.json' # Authenticate and construct service. service = get_service( api_name='analytics', api_version='v3', scopes=[scope], key_file_location=key_file_location)
解决方法
这个错误核心是PyInstaller打包时未完整包含Google API客户端的发现文档——discovery.build默认依赖本地缓存或网络获取的API描述文件,打包后的单文件exe无法正常访问这些资源。以下是几种可靠的解决方式:
方法1:改用--collect-all强制完整打包依赖
--collect-data可能没覆盖到google-api-python-client的所有必要文件,用--collect-all强制收集整个依赖包的全部内容:
pyinstaller --onefile -w --icon=icon.ico --add-data "client_secrets.json;." --collect-all google-api-python-client --collect-all oauth2client main.py
方法2:手动使用本地发现文档构建服务
- 获取Analytics v3的API发现文档JSON,保存为
analytics_v3.json,放在脚本同级目录。 - 修改代码,让
discovery.build读取本地文档而非发起网络请求:
def get_service(api_name, api_version, scopes, key_file_location): credentials = ServiceAccountCredentials.from_json_keyfile_name( key_file_location, scopes=scopes) # 读取本地的Analytics v3发现文档 import json with open(f'{dir_path}/analytics_v3.json', 'r') as f: discovery_doc = json.load(f) # 基于本地文档构建服务对象 service = discovery.build_from_document(discovery_doc, credentials=credentials) return service
- 打包时将新增的JSON文件也加入资源列表:
pyinstaller --onefile -w --icon=icon.ico --add-data "client_secrets.json;." --add-data "analytics_v3.json;." main.py
方法3:确保缓存路径可访问(备选)
先运行一次脚本,让Google API客户端将发现文档缓存到本地默认路径,然后打包时将缓存目录的文件加入--add-data,同时在代码中设置discovery.build的cache_discovery=True。这种方法依赖系统缓存路径,稳定性不如前两种,优先推荐方法1或2。
内容的提问来源于stack exchange,提问作者squidg
相关产品推荐
相关产品推荐

