WhatsApp Business 开放平台提供的工具可自动发送、接收消息以及处理传入消息,让商家能够与其受众更密切地交流。例如,如果使用自动发消息功能,系统可在新客户于非营业时间与您联系时欢迎他们,或向他们发送通知。
本文介绍如何集成 Meta 托管的云端 API,从而实现 WhatsApp Business 开放平台与 Python 应用程序的集成,以支持发送和管理 WhatsApp 消息。
我们来深入探索一下如何从头开始创建支持 WhatsApp 消息功能的 Python 网页应用。如果您想预览最终成果,可以下载完整的应用程序代码。
若要使用测试电话号码发送和接收消息,请按设置开发者资产和开放平台访问权限教程操作,确保完成以下步骤:
在 Meta 开发者中注册一个免费的开发者帐户。
为帐户启用双重验证:
创建 Meta 应用。本文稍后将使用应用编号和应用密钥。
关联 Meta 应用与 WhatsApp 产品。
关联应用与商务管理平台。
在应用面板上,打开“WhatsApp”>“开始”菜单,然后配置收信人电话号码。您的应用需要使用该号码作为 WhatsApp 消息的收信人。本文稍后将使用此号码。
为业务帐户创建系统用户。
在“系统用户”页面上,为新系统用户生成新口令,分配 WhatsApp 应用和所有可用权限。本文稍后将使用此口令。
在“系统用户”页面上,为系统用户配置资产,分配 WhatsApp 应用的完全控制权。请记得点击“保存更改”按钮。
最后要强调的是,如果尚未下载和安装 Python,请执行此操作。
我们的小应用程序示例将用作线上机票预订服务应用。此应用程序将使用 API 为用户提供比邮件交流更个性化的互动体验。当用户登录时,此应用程序通过 WhatsApp 消息向他们发出问候。然后,在用户购买机票后,他们将收到确认购买机票的消息。
本版块将帮助您正常运行新的 Python 项目。我们将使用 Jinja(轻型模板引擎)和 Flask(微网页框架)。
首先,打开一个终端,并为您的项目创建一个文件夹。然后执行以下命令:
python3 -m venv venv
此命令将为 Python 项目创建虚拟布景。
然后,执行以下命令:
$ mkdir myproject $ cd myproject $ python3 -m venv venv
随后激活虚拟布景。
$ . venv/bin/activate
现在,安装 Flask:
pip install flask[async]
使用以下内容在项目根目录下创建 app.py 文件:
from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>"
运行应用:
$ flask run
然后,您将看到应用在本地端口 5000 运行:
* Serving Flask app 'app.py' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
现在,访问 http://127.0.0.1:5000/,您将看到采用 Python 和 Flask 的入门级应用程序的首页:
若要开始使用机票应用程序,可创建一个登录表单示例作为首页。您需要调用 render_template 函数来渲染单独的 HTML 文件中的视图。打开 app.py 文件进行修改,以导入 render_template 函数:
from flask import Flask, render_template
然后将 hello_world 替换为索引函数,如下所示:
def index(): return render_template('index.html', name=__name__)
新建名为“templates”的文件夹,然后新建名为“index.html”的文件:
\templates |--- index.html
随后,打开 index.html 文件,并添加以下 HTML 内容。在此创建的登录示例附带登录占位符和密码。这样,无需提供这些内容即可使用此应用程序。
对于网页应用前端,我们使用 Bootstrap。此资源库很受欢迎,可帮助您构建一致的响应式轻型用户界面,以便在不同设备上轻松运行应用,而不必考虑 CSS 规则:
<!DOCTYPE html> <html> <head> <title>Flight Confirmation Demo for Python</title> <h1 class="text-center">Flight Confirmation Demo for Python</h1> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" /> </head> <body> <div class="d-flex flex-row justify-content-center align-items-center"> <div class="border px-3"> <div class="row"> <div class="col-sm-6 d-none d-sm-block"> <img src="https://images.unsplash.com/photo-1530521954074-e64f6810b32d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8NHx8YWlyJTIwdHJhdmVsfGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=500&q=60" alt="Login image" class="w-100 vh-50 pt-3 pb-3" style="object-fit: cover; object-position: left" /> </div> <div class="col-sm-6 text-black"> <div class="px-5 ms-xl-4"> <i class="fas fa-crow fa-2x me-3 pt-5 mt-xl-4" style="color: #709085" ></i> </div> <div class="d-flex align-items-center h-custom-2"> <form class="w-100" method="post" action="/welcome"> <div class="form-outline mb-4"> <input type="text" value="this_is_a_demo@email.com" disabled class="form-control form-control-md text-muted" /> </div> <div class="form-outline mb-4"> <input type="text" value="••••••••••••••••" disabled id="form2Example28" class="form-control form-control-md text-muted" /> </div> <div class="pt-1 mb-4"> <input type="submit" class="btn btn-info btn-lg btn-block" value="Login"/> </div> </form> </div> </div> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> </body> </html>
然后,再次运行应用,您将看到新登录页面:
> flask run
Python 应用程序需要使用本文开始部分创建的 Meta 开发者帐户中的特定数据。在开发期间,为便于将所有配置保存在一个位置,而不是将其分散在代码之间,请将其置于一个文件中。
使用以下设置,在项目根目录下创建 config.json 文件,并将所有占位符替换为 WhatsApp Business 商业帐号面板中的详细信息:
{ "APP_ID": "<<YOUR-WHATSAPP-BUSINESS-APP_ID>>", "APP_SECRET": "<<YOUR-WHATSAPP-BUSINESS-APP_SECRET>>", "RECIPIENT_WAID": "<<YOUR-RECIPIENT-TEST-PHONE-NUMBER>>", "VERSION": "v13.0", "PHONE_NUMBER_ID": "<<YOUR-WHATSAPP-BUSINESS-PHONE-NUMBER-ID>>", "ACCESS_TOKEN": "<<YOUR-SYSTEM-USER-ACCESS-TOKEN>>" }
执行登录表单操作后,应用将向 /welcome 线路发出 POST 请求。因此,您将需要使用新路由器执行以下操作:
现在,打开 app.py 文件,并将其内容替换为以下代码,以加入 /welcome 端点:
import json from flask import Flask, render_template import flask from message_helper import get_text_message_input, send_message app = Flask(__name__) with open('config.json') as f: config = json.load(f) app.config.update(config) @app.route("/") def index(): return render_template('index.html', name=__name__) @app.route('/welcome', methods=['POST']) async def welcome(): data = get_text_message_input(app.config['RECIPIENT_WAID'] , 'Welcome to the Flight Confirmation Demo App for Python!'); await send_message(data) return flask.redirect(flask.url_for('index'))
现在,安装 aiohttp 以使应用执行异步 HTTP 请求:
pip install aiohttp[speedups]
随后,您需要使用函数封装通过 API 发送文本型消息的代码。使用以下代码,在项目根目录下新建 message_helper.py 文件:
import aiohttp import json from flask import current_app async def send_message(data): headers = { "Content-type": "application/json", "Authorization": f"Bearer {current_app.config['ACCESS_TOKEN']}", } async with aiohttp.ClientSession() as session: url = 'https://graph.facebook.com' + f"/{current_app.config['VERSION']}/{current_app.config['PHONE_NUMBER_ID']}/messages" try: async with session.post(url, data=data, headers=headers) as response: if response.status == 200: print("Status:", response.status) print("Content-type:", response.headers['content-type']) html = await response.text() print("Body:", html) else: print(response.status) print(response) except aiohttp.ClientConnectorError as e: print('Connection Error', str(e)) def get_text_message_input(recipient, text): return json.dumps({ "messaging_product": "whatsapp", "preview_url": False, "recipient_type": "individual", "to": recipient, "type": "text", "text": { "body": text } })
使用上述代码,可通过 graph.facebook.com 的 Meta 图谱 API 向 /messages 端点发出 HTTP POST 请求,传递以下内容:
另请注意,get_text_message_input 函数将返回发送基本短信所需的特定数据结构。
最后,再次运行应用:
> flask run
然后点击登录按钮。您将看到屏幕上弹出 WhatsApp 通知:
点击该通知以打开 WhatsApp 应用,您将看到 Python 应用程序所发送的基本短信:
目前,您已可以使用 WhatsApp 发送简单消息。之后,您将能够使用模板发送更复杂的消息。
首先,您将创建可售票航班的目录及其详细信息,以便线上客户购票。此数据将存储在单独的文件中。使用以下内容,新建 \flights.py 文件:
def get_flights(): return [{ "flight_id": 1, "document": 'https://github.com/marcelooliveira/flight-confirmation-python/raw/main/FlightConfirmation.pdf', "thumbnail": 'https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Aerial_view_of_Bajra_Sandhi_Monument_Denpasar_Bali_Indonesia.jpg/250px-Aerial_view_of_Bajra_Sandhi_Monument_Denpasar_Bali_Indonesia.jpg', "origin": 'Singapore (SIN)', "destination": 'Denpasar (DPS)', "time": 'June 24, 2022 - 8:25 PM' }, { "flight_id": 2, "document": 'https://github.com/marcelooliveira/flight-confirmation-python/raw/main/FlightConfirmation.pdf', "thumbnail": 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Parliament_at_Sunset.JPG/275px-Parliament_at_Sunset.JPG', "origin": 'New York (JFK)', "destination": 'London (LHR)', "time": 'June 25, 2022 - 9:15 PM' }, { "flight_id": 3, "document": 'https://github.com/marcelooliveira/flight-confirmation-python/raw/main/FlightConfirmation.pdf', "thumbnail": 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Sydney_Australia._%2821339175489%29.jpg/250px-Sydney_Australia._%2821339175489%29.jpg', "origin": 'Beijing (PEK)', "destination": 'Sydney (SYD)', "time": 'June 25, 2022 - 5:30 AM' }, { "flight_id": 4, "document": 'https://github.com/marcelooliveira/flight-confirmation-python/raw/main/FlightConfirmation.pdf', "thumbnail": 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a5/Mouth_of_Miami_River_20100211.jpg/220px-Mouth_of_Miami_River_20100211.jpg', "origin": 'São Paulo (GRU)', "destination": 'Miami (MIA)', "time": 'June 25, 2022 - 9:25 AM' }]
现在需要为用户设置新线路来访问航班目录页面。打开 app.py 文件,并导入 get_flight 函数:
from flights import get_flights
然后,在 app.py 文件中添加目录函数:
@app.route("/catalog") def catalog(): return render_template('catalog.html', title='Flight Confirmation Demo for Python', flights=get_flights())
修改欢迎函数,以重定向至目录页面,而非索引页面:
return flask.redirect(flask.url_for('catalog'))
最后,使用以下内容,在 templates\catalog.html 中新建文件:
<!DOCTYPE html> <html> <head> <title>{{title}}</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> </head> <body> <h1 class="text-center">{{title}}</h1> <p class="text-center">Welcome to {{title}}</p> <div class="container"> <div class="row"> {% for flight in flights %} <div class="col col-3"> <div class="card"> <img src="{{ flight.thumbnail }}" class="card-img-top" alt="{{flight.origin}}"/> <div class="card-body"> <p class="card-text"><b>origin:</b> {{ flight.origin }}</p> <p class="card-text"><b>destination:</b> {{ flight.destination }}</p> <p class="card-text"><b>time:</b> {{ flight.time }}</p> <p> <form method="POST" action="/buy-ticket"> <div class="container"> <input type="hidden" name="id" value="{{flight.flight_id}}"/> <div class="row gx-5"> <input type="submit" value="🎫 Buy" class="col col-5"/> </div> </div> </form> </p> </div> </div> </div> {% endfor %} </div> </div> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> </body> </html>
再次运行应用,然后点击登录按钮。这样,系统将向您的 WhatsApp 号码发送欢迎消息。此外,还会将您重定向至 /catalog 视图:
> flask run
请注意,上方屏幕上显示的每个航班都有一个购票按钮。随后,您将配置应用程序以处理购票事务。
必须使用消息模板才能开启商家发起的对话。这些对话可以是客户服务消息,也可以是预约提醒、支付或配送更新、提醒等。
打开 app.py 文件,并添加导入的 get_templated_message_input 和请求函数:
from flask import Flask, render_template, request from message_helper import get_templated_message_input, get_text_message_input, send_message
然后,使用以下内容为 /buy-ticket 线路添加新函数:
@app.route("/buy-ticket", methods=['POST']) async def buy_ticket(): flight_id = int(request.form.get("id")) flights = get_flights() flight = next(filter(lambda f: f['flight_id'] == flight_id, flights), None) data = get_templated_message_input(app.config['RECIPIENT_WAID'], flight) await send_message(data) return flask.redirect(flask.url_for('catalog'))
随后,打开 message_helper.py 文件,并加入 get_templated_message_input 函数:
def get_templated_message_input(recipient, flight): return json.dumps({ "messaging_product": "whatsapp", "to": recipient, "type": "template", "template": { "name": "sample_flight_confirmation", "language": { "code": "en_US" }, "components": [ { "type": "header", "parameters": [ { "type": "document", "document": { "filename": "FlightConfirmation.pdf", "link": flight['document'] } } ] }, { "type": "body", "parameters": [ { "type": "text", "text": flight['origin'] }, { "type": "text", "text": flight['destination'] }, { "type": "text", "text": flight['time'] } ] } ] } })
请注意,我们在上面的代码中使用了 sample_flight_confirmation
模板,其中提供了航班文档 PDF 文件、航班始发地、目的地和日期/时间。您可以使用其他可用模板实验,也可以通过访问消息模板页面新建模板。
最后,再次运行应用,然后点击其中一个“购买”按钮。这样,应用将通过 WhatsApp 向测试电话号码发送模板消息:
> flask run
现在,打开 WhatsApp 应用,您将看到此模板消息。
就是这么简单!
如您所见,使用 Python 代码发送消息很简单。但请注意以下集成 WhatsApp 与应用程序的技巧和最佳实践:
本文介绍了如何通过集成 Python 应用与 WhatsApp Business 商业帐号,在此 Python 应用中添加发消息功能。
从头开始创建简单的 Python 应用程序后,添加登录页面示例,并配置应用程序以通过云端 API 向用户发送基本欢迎消息。最后,添加目录页面,并配置该页面,以发送提供航班确认详细信息的模板消息。
本文介绍的配置内容只是冰山一角。想要了解如何在应用程序中配置 Webhooks,配置有关发送和接收客户消息及业务帐户信息的通知吗?请查看 WhatsApp Business 开放平台文档,了解此内容以及更多信息。