如何用Python进行缩放考勤(详细指南)

182 阅读5分钟

自从COVID-19大流行开始以来,更多的软件工程师已经过渡到允许远程工作的角色。这意味着我们每天都在虚拟会议中花费大量的时间,而这些会议通常是由Zoom主持的。在大多数需要认真讨论和决策的Zoom电话开始时,我经常发现自己在问:"这次谈话需要的人都在吗?"

如果只有四、五个人,那就没问题。但是当有十几个利益相关者需要参与时,确定法定人数就会耗尽会议时间。

好消息是,作为软件工程师,我们都在寻找更好的方法来完成任务并使其自动化。在本教程中,我们将探索Zoom会议的API。我们将解释如何使用Python与之交互,以便回答诸如以下问题:

  • "谁参加了会议?"
  • "被邀请的人都来了吗?"
  • 而最重要的是,"我们可以开始了吗?"

为此,我们将

  1. Zoom API访问要求
  2. 创建一个Zoom应用程序
  3. 获得一个JSON网络令牌(JWT)。
  4. 获取会议注册者的名单
  5. 获取会议平台的列表
  6. 进行Zoom考勤并开始会议

本教程中的所有代码都可以在我的 GitHub repo中找到 。准备好开始了吗?让我们开始吧。

在你开始之前,安装Zoom Attendance Python环境

为了跟上本文的代码,你可以下载并安装我们预置的 Zoom Attendance 环境,其中包含 :

  • 一个版本的Python 3.10。
  • 本篇文章中使用的所有依赖项,包括Windows、Mac和Linux的预建环境。
  • 当你安装环境时,本帖的所有代码也将从GitHub自动安装。

为了下载这个随时可用的Python项目,你需要 创建一个免费的ActiveState Platform账户。只需使用你的GitHub凭证或你的电子邮件地址来注册。注册很简单,它可以解锁ActiveState平台的许多其他 依赖性管理的好处

或者你也可以使用我们的State工具CLI来安装运行环境和项目代码。

Runtime

对于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会议的问题和质量有关的指标。

为了我们的目的,我们将:

  1. 使用 "list meeting registrants" 端点来检索所有注册参加会议的人的名单。
  2. 访问 "list meeting participants"端点,编制一份会议中所有活跃参与者的名单。
  3. 确定登记参加会议的人是否已经加入 ,以便 我们可以开始讨论。

访问要求

Zoom通过几种不同的机制实现对其API的访问,包括使用JSON Web令牌(JWT)和OAuth。在本教程中,我们将使用他们的JWT方法创建一个应用程序,这意味着我们需要使用具有开发者访问权限的付费Zoom账户。

如果你没有开发者权限,不用担心,我已经创建了一个简单的Python服务,可以模拟端点,就像你访问实际的API一样。你可以从 这个GitHub repo下载模拟服务 ,并使用Flask在本地8080端口运行它。还有一个测试用户的数据集,你可以利用它来模拟参加Zoom会议的注册人数。

第2步 - 创建一个Zoom应用程序

为了建立一个Zoom应用程序,我们需要遵循几个步骤。

  1. 登录 Zoom Marketplace , 在 页面右上角的Develop 下拉选择器中 选择 Build App

Create App

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

Generate API Key

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

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

Activate App

第3步 - 为Zoom生成JSON网络令牌(JWT)

让我们开始把我们需要的代码放在一起,以便为我们的会议进行考勤。我们要分析的会议有几个要求。

  • 注册 必须被启用。这样我们才能知道谁应该参加我们的会议。
  • 会议必须是 活跃的开始的。仪表板API只返回活动会议的数据。

我们将直接访问Zoom的API。然而,如果你愿意使用一个封装器, zoomus Python封装器 提供了一个额外的抽象层,并删除了一些步骤,例如生成一个有效的JWT。但这也是乐趣的一部分啊

Zoom Attendance运行环境中的两个Python包将帮助我们完成这个项目。

  • Flask:用于创建一个网络服务器,以便收集和显示我们的结果。
  • PyJWT:用于创建一个JWT令牌来验证我们的请求。

认证

为了得到我们的JWT,让我们:

  1. 从一个叫做 credentials.py的文件开始 。
  2. 输入 时间jwt从PyJWT包中导入库。
  3. 在这个文件中包括我们的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中查询登记参加会议的人的名单。

  1. 创建一个名为 registrants.py的文件
  2. 定义两个函数。
    1. 第一个文件查询API
    2. 第二部分提取用户列表

让我们首先导入 请求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

这两个函数都需要一个 baseurlmeetingid的参数 你可以对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会议注册者是否出席了会议

现在我们有了计算和显示结果所需的一切。让我们开始吧。

  1. 创建一个 main.py 文件,暴露一个我们可以从网络浏览器调用的接口。
  2. 导入 请求库中的一些对象,从 flask 库,以及 模板 对象从 字符串库。
  3. 检索出 get_registrant_listget_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.htmltemplate.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在你的浏览器中输入

希望你会看到这样的内容:

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

Meeting Kickoff
等了一两分钟后,看起来我们期待的所有人都已经加入了。是时候开始会议了!

结论--在正确的时间开始放大电话

自从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提高你的在线生活质量。