自从COVID-19大流行开始以来,更多的软件工程师已经过渡到允许远程工作的角色。这意味着我们每天都在虚拟会议中花费大量的时间,而这些会议通常是由Zoom主持的。在大多数需要认真讨论和决策的Zoom电话开始时,我经常发现自己在问:"这次谈话需要的人都在吗?"
如果只有四、五个人,那就没问题。但是当有十几个利益相关者需要参与时,确定法定人数就会耗尽会议时间。
好消息是,作为软件工程师,我们都在寻找更好的方法来完成任务并使其自动化。在本教程中,我们将探索Zoom会议的API。我们将解释如何使用Python与之交互,以便回答诸如以下问题:
- "谁参加了会议?"
- "被邀请的人都来了吗?"
- 而最重要的是,"我们可以开始了吗?"
为此,我们将
- Zoom API访问要求
- 创建一个Zoom应用程序
- 获得一个JSON网络令牌(JWT)。
- 获取会议注册者的名单
- 获取会议平台的列表
- 进行Zoom考勤并开始会议
本教程中的所有代码都可以在我的 GitHub repo中找到 。准备好开始了吗?让我们开始吧。
在你开始之前,安装Zoom Attendance Python环境
为了跟上本文的代码,你可以下载并安装我们预置的 Zoom Attendance 环境,其中包含 :
- 一个版本的Python 3.10。
- 本篇文章中使用的所有依赖项,包括Windows、Mac和Linux的预建环境。
- 当你安装环境时,本帖的所有代码也将从GitHub自动安装。
为了下载这个随时可用的Python项目,你需要 创建一个免费的ActiveState Platform账户。只需使用你的GitHub凭证或你的电子邮件地址来注册。注册很简单,它可以解锁ActiveState平台的许多其他 依赖性管理的好处。
或者你也可以使用我们的State工具CLI来安装运行环境和项目代码。

对于Windows用户,在CMD提示下运行以下程序,以自动下载并安装Typosquatting Detector运行环境和项目代码到一个虚拟环境中。
powershell -Command "& $([scriptblock]::Create((New-Object Net.WebClient).DownloadString('https://platform.activestate.com/dl/cli/_pdli01/install.ps1'))) -c'state activate --default Pizza-Team/Zoom-Attendance'"
对于Linux或Mac用户,运行以下程序来自动下载并安装Typosquatting Detector运行时和项目代码到虚拟环境中。
sh <(curl -q https://platform.activestate.com/dl/cli/_pdli01/install.sh) -c'state activate --default Pizza-Team/Zoom-Attendance'
第1步 - 访问Zoom Meeting API
大多数现代网络应用程序都通过API暴露其大部分功能,Zoom也不例外。在本教程中,我们将使用 Zoom API 的第 2 版 ,并查看 会议 和 指标 API。
-
Zoom Meetings API 公开了您账户中存在的会议信息。你可以通过它来查询:
- 会议信息
- 调查
- 民意调查
- 会议邀请
- 会议注册者
-
Zoom Metrics API用于 收集会议中活跃参与者的信息。你可以查询它,以了解内部互动的细节:
- 会议
- 网络研讨会
- 分组讨论室
- 你还可以找到与Zoom会议的问题和质量有关的指标。
为了我们的目的,我们将:
- 使用 "list meeting registrants" 端点来检索所有注册参加会议的人的名单。
- 访问 "list meeting participants"端点,编制一份会议中所有活跃参与者的名单。
- 确定登记参加会议的人是否已经加入 ,以便 我们可以开始讨论。
访问要求
Zoom通过几种不同的机制实现对其API的访问,包括使用JSON Web令牌(JWT)和OAuth。在本教程中,我们将使用他们的JWT方法创建一个应用程序,这意味着我们需要使用具有开发者访问权限的付费Zoom账户。
如果你没有开发者权限,不用担心,我已经创建了一个简单的Python服务,可以模拟端点,就像你访问实际的API一样。你可以从 这个GitHub repo下载模拟服务 ,并使用Flask在本地8080端口运行它。还有一个测试用户的数据集,你可以利用它来模拟参加Zoom会议的注册人数。
第2步 - 创建一个Zoom应用程序
为了建立一个Zoom应用程序,我们需要遵循几个步骤。
- 登录 Zoom Marketplace , 在 页面右上角的Develop 下拉选择器中 选择 Build App 。

- 我们需要使用JSON网络令牌(JWT)建立一个服务器到服务器的应用程序,所以 当你准备好时,点击 JWT面板上的创建 按钮。

- 为你的应用程序输入一个名称(如 考勤),然后点击 " 创建" 来访问API密钥和API密文。确保你将密钥和秘密存储在一个安全的地方,如密码库或类似的东西。
- 点击 继续 ,Zoom将激活你的应用程序。

注意: 如果你的账户已经有了JWT凭证,你可以点击 查看这里的 链接来查看它们。每个账户只能有一套JWT凭证。

第3步 - 为Zoom生成JSON网络令牌(JWT)
让我们开始把我们需要的代码放在一起,以便为我们的会议进行考勤。我们要分析的会议有几个要求。
- 注册 必须被启用。这样我们才能知道谁应该参加我们的会议。
- 会议必须是 活跃的 或 开始的。仪表板API只返回活动会议的数据。
我们将直接访问Zoom的API。然而,如果你愿意使用一个封装器, zoomus Python封装器 提供了一个额外的抽象层,并删除了一些步骤,例如生成一个有效的JWT。但这也是乐趣的一部分啊
Zoom Attendance运行环境中的两个Python包将帮助我们完成这个项目。
- Flask:用于创建一个网络服务器,以便收集和显示我们的结果。
- PyJWT:用于创建一个JWT令牌来验证我们的请求。
认证
为了得到我们的JWT,让我们:
- 从一个叫做 credentials.py的文件开始 。
- 输入 时间 和 jwt从PyJWT包中导入库。
- 在这个文件中包括我们的Zoom API Key和API Secret作为常数。确保将下面代码中的值替换为你为Zoom账户创建的凭证。
import jwt
import time
ZOOM_KEY = '1234567890'
ZOOM_SECRET = 'abcdefghijklmnopqrstuvwxyz'
def get_token():
header = {"alg": "HS256", "typ": "JWT"}
token_payload = {"iss": ZOOM_KEY, "exp": int(time.time() + 3600)}
return jwt.encode(token_payload, ZOOM_SECRET,
algorithm="HS256", headers=header)
定义 get_token 函数,它指定了我们需要在标题变量中创建的算法和标记类型。我们还需要一个有效载荷,其中包括我们的API密钥和过期时间,它们与我们的秘钥一起被传递到 jwt.encode 函数,以及我们的秘密密钥。由此产生的字符串是一个可以被Zoom API验证的JWT。
第4步 - 获取Zoom会议注册者的列表
现在我们可以连接到Zoom API了,我们可以从Meetings API中查询登记参加会议的人的名单。
- 创建一个名为 registrants.py的文件
- 定义两个函数。
- 第一个文件查询API
- 第二部分提取用户列表
让我们首先导入 请求和 json库以及 get_token 函数,从凭证文件中导入。
import requests
import json
from credentials import get_token
def fetch_registrants(baseurl, meetingid):
url = baseurl + "/meetings/" + meetingid + "/registrants"
return requests.get(url, headers={'Authorization': 'Bearer ' + get_token()}).json()
def get_registrant_list(baseurl, meetingid):
response = fetch_registrants(baseurl, meetingid)
registrants = response['registrants']
registrant_list = {}
for registrant in registrants:
registrant_list[registrant['email']] = registrant['first_name'] + ' ' + registrant['last_name']
return registrant_list
这两个函数都需要一个 baseurl 和 meetingid的参数 。 你可以对Zoom API的URL进行硬编码,但通过它可以将请求指向一个模拟响应的Web服务,这样你就可以测试功能。
meetings//registrants 端点会返回一个JSON对象,其中包括登记参加会议的所有人的数组。我们将使用 包含JWT令 牌的授权 头 进行请求 ,该令牌是我们从 之前创建的get_token 函数中得到的 。
该 get_registrant_list函数调用fetch_registrants 函数。然后,它建立了一个以 电子邮件 为键 的 注册者列表 ,并将每个用户的名字和姓氏串联起来作为值。 电子邮件 是一个独特的字段,允许我们在下一步将注册者和参与者联系起来。
第5步 - 获取Zoom会议出席者的名单
对于下一步,我们将创建一个名为 participants.py的文件 ,并实现与上一步类似的逻辑。在这种情况下,我们将向Metrics API提交一个请求,以检索会议中的活跃参与者的列表。
和上一个文件一样,我们将 从证书文件中导入 请求 和 json 库 ,以及get_token 函数。
import requests
import json
from credentials import get_token
def fetch_participants(baseurl, meetingid):
url = baseurl + "/metrics/meetings/" + meetingid + "/participants"
response = requests.get(url, headers={'Authorization': 'Bearer ' + get_token()}).json()
return response
def get_participant_list(baseurl, meetingid):
response = fetch_participants(baseurl, meetingid)
participants = response['participants']
participant_list = []
for participant in participants:
participant_list.append(participant['email'])
return participant_list
这个文件与 registrants.py 文件 非常相似 ,只是我们向一个不同的端点发出请求,而且我们只从 参与者 数组中 提取电子邮件地址列表 。
第6步 - 确定所有的Zoom会议注册者是否出席了会议
现在我们有了计算和显示结果所需的一切。让我们开始吧。
- 创建一个 main.py 文件,暴露一个我们可以从网络浏览器调用的接口。
- 导入 请求库中的一些对象,从 flask 库,以及 模板 对象从 字符串库。
- 检索出 get_registrant_list和 get_participant_list从我们刚刚创建的文件中。
import requests
from flask import Flask, Response, request
from string import Template
from registrants import get_registrant_list
from participants import get_participant_list
app = Flask(__name__)
app.config['DEBUG'] = True
zoomUrl = "https://api.zoom.us/v2"
@app.route('/myMeeting', methods=['GET'])
def meeting():
if 'id' in request.args:
meeting_id = str(request.args['id'])
else:
return "Error: No meeting id provided."
registered = get_registrant_list(zoomUrl, meeting_id)
participating = get_participant_list(zoomUrl, meeting_id)
percentage = '{0:.0%}'.format(len(participating) / len(registered))
participant_list = ''
missing_list = ''
for registrant in registered:
if registrant in participating:
participant_list = participant_list + registered[registrant] + '<br/>'
for registrant in registered:
if registrant not in participating:
missing_list = missing_list + registered[registrant] + '<br/>'
with open('htmlTemplate.html') as file:
template = Template(file.read())
response = template.substitute(
meeting_id=meeting_id,
registered_count=str(len(registered)),
participating_count=str(len(participating)),
percentage_attending=str(percentage),
participating=participant_list,
missing=missing_list,
action_class=('ready' if percentage == '100%' else 'wait'),
action=('Let\'s Start!' if percentage == '100%' else 'Please wait...'))
return response
@app.route('/template.css', methods=['GET'])
def stylesheet():
with open('template.css') as file:
return Response(file.read(), mimetype="text/css")
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
app.run(port=8000)
请注意,我们定义了两条路线:
- /myMeeting 路由接受一个 id 参数,我们可以用它来传递我们的会议的ID。
- /template.css 路由返回一个静态的样式表,并使我们的结果看起来更好。
的 会议 函数:
- 验证会议ID的存在。
- 获取注册者和参与者的名单。
- 计算加入会议的人数与注册人数的百分比。
- 比较注册者与与会者的名单,以创建一个失踪者的名单和一个出席者的名单。
最后, 打开 一个名为 htmlTemplate.html的文件 ,并使用该 模板替换 函数来向模板传递数值。我们将返回这个文件以便在我们的浏览器中显示。
让我们快速看 一下htmlTemplate.html 和 template.css 文件。
<html>
<head>
<title>Meeting: $meeting_id</title>
<link rel="stylesheet" href="template.css"/>
<meta http-equiv="refresh" content="30">
</head>
<body>
<div class="content">
<h1>My Meeting (<i>$meeting_id</i>)</h1>
<div class="stats">
<h3>Registered: $registered_count</h3>
<h3>Participating: $participating_count</h3>
<h3>Percent Attending: $percentage_attending</h3>
<table>
<tr>
<th>Present</th>
<th>Missing</th>
</tr>
<tr>
<td>
$participating
</td>
<td>
$missing
</td>
</tr>
</table>
<h2 class="$action_class">$action</h2>
</div>
</div>
</body>
</html>
这是一个标准的HTML文件,有:
- 替换值以 $ 符号 为前缀 。
- 在 头部 部分 有一个 元 标签 ,每30秒自动刷新一次页面。这样一来,页面就会自动刷新,并在新与会者到来时给我们提供最新的会议出席情况。
- 一个 $action 参数,在 类 和 内容上决定 是否开始我们的会议。
下面的CSS文件有助于格式化我们的会议信息,使其更容易阅读:
body {
background-color: lightblue;
color: blue;
font-family: verdana;
font-size: 14px;
}
.content {
width: 700px;
margin: auto;
}
.stats {
width: 80%;
margin: auto;
}
h1 {
text-align: center;
}
table {
border: 0;
}
tr {
width: 150px;
}
td {
vertical-align: top;
padding: 15px;
min-width: 160px;
}
.ready {
color: green;
}
.wait {
color: red;
}
我们可以开始会议了吗?
当你运行 main.py时,它会启动一个运行在localhost 8000端口的服务。你可以从Zoom UI或会议邀请函中获得会议ID。在将其作为参数添加之前,请确保删除任何空格。例如,如果你的会议ID是 853 9850 8860,在浏览器中输入 http://localhost:8000/myMeeting?id=85398508860在你的浏览器中输入
希望你会看到这样的内容:

正如你所看到的,有十个人注册了我们的会议,但到目前为止只有六个人加入。我们也许应该等待其他四个人的加入:

等了一两分钟后,看起来我们期待的所有人都已经加入了。是时候开始会议了!
结论--在正确的时间开始放大电话
自从COVID-19大流行以来,感觉我们都在Zoom上生活得太多了,但不管你喜不喜欢,远程工作是要留下来的。不幸的是,像Zoom这样的应用程序一直在努力跟上其激增的用户需求,并继续缺乏关键的 "生活质量 "功能。幸运的是,Zoom的API允许开发者填补他们所缺少的功能。
在本教程中,我们仅仅通过这样一个API驱动的功能,让我们确定出席者名单是否与预期的注册者相符。你所需要做的就是
- 安装Zoom Attendance Python运行时,这也将把GitHub的代码部署到你的本地系统。
- 查看Zoom Attendance Python代码库。
为了更进一步,你可能要处理一些角落的情况,比如说:
- 如果没有人登记参加你的会议,百分比计算将失败,因为Python将尝试除以0。
- 在会议开始前进行考勤将从Dashboard API中产生一个错误响应,说会议不存在。
为了帮助处理这些用例,你可能想添加一些错误检查和验证,以便使你的实现更有弹性。
当然,这个实现只是你 使用Zoom的API收集通过Zoom安排的事件信息 的一种可能方式 。 Zoom的API文档 使用了标准的 API术语、模式和例子,使其易于理解。试一试吧,看看你是否能通过Zoom提高你的在线生活质量。