Open API

很多同学希望能够通过程序/脚本控制花漾客户端,如:通过程序/脚本访问某个账号以打开/关闭花漾指纹浏览器等,从而方便与其它系统的整合。 基于此,花漾提供了Open API的特性,其实现原理是基于Access Key认证体系的Http请求/响应机制,理论上允许用户使用任意语言如Java、Python、C# 等与花漾客户端进行交互。

1、开启 Open API 选项并获得 Access Key

在使用 Open API 之前,首先需要开启API,请切换至“团队”主页签,并在“团队资源”处,开启 Open API:  

   

《在团队资源中开启Open API》

当 Open API 开启后,可以点击“新增”按钮,创建一个新的 Access Key,请注意,每一个Access Key都需要指定一个用户身份, 换言之,当您使用某个Access Key并通过 Open API 来操纵花漾客户端时,本质上相当于使用与此Access Key绑定的用户身份进行的操作:  

   

《创建 Access Key》

需要提醒您的是,生成的 Access Key 请务必妥善保存,以避免造成信息安全风险。

2、花漾 Open API 参考指引

目前花漾 Open API 仅提供了一些有限的接口列表,主要包括查询 RPA 任务详情、打开/关闭某个账号对应的浏览器等等。 目前花漾已经开放的API列表请参考:https://app.szdamai.com/open-api/ 。 需要提醒您的是,上述API参考既是一个在线文档,同时也是花漾 Open API 的调试工具,关于其更详细的介绍,请参考 API参考及Swagger在线调试工具

3、花漾 Open API 的调用

3.1 调用端点(Endpoint)与时间格式

花漾Open API的调用端点(Endpoint)是:https://api.szdamai.com/openapi/; 输入/输出的时间格式是:"yyyy-MM-dd'T'HH:mm:ss'Z'",采用UTC+0时区。举例,当输出"2022-09-05T11:12:28Z"时, 代表东8区(北京时间)的2022-09-05 19:12:28。

3.2 认证方式

目前仅支持OAuth Token的方式进行校验,即客户使用 AccessKeyId + AccessKeySecret,跟 Endpoint 换取一个 Token, 在后续请求中,把 Token 放入http头中:'Authorization: YOUR_Token',后续所有请求将以 Access Key 代表的用户身份进行操作。

以下举例说明:

curl -X 'GET' 'https://api.szdamai.com/openapi/token?accessKeyId=YOUR_AccessKeyId&accessKeySecret=YOUR_AccessKeySecret&expireSeconds=7200' -H 'accept: */*

其中 expireSeconds 是 Token 超时时间,单位:秒,取值范围为[120,7200];当Token超时以后,请求会失败, 建议您在Token超时之前重新获取Token。

上述http请求的返回结果如下所示:

{  
  "success": true,  "code": 0,  "message": null,  
    "data": {    
      "token": "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ0b2MiLCJqdGkiOiI2MTY1ODY4MjEyMWI0NzQ1OTNmZDBjYzVjYzAzOTk1NyIsInN1YiI6IkFLLUFLUVpQY3Z4YVRsMU85bkwwUUhjSHp0IiwiZXhwIjoxNjYyMzc2MzQ4fQ.TjG0VLwNrJrn8-XyxHz-OfhNjlLkalan3EBr92cdKc8GGaKwFNEqUpBInKiUJ6ixybIpKnYNpsjxktliw2nIbjYgTnCRbT1G7jHogx2Y_7eDigJjyrpyZwdlZ5ZEGHPn01fNWFS0RkgHqeraQoNwbgVDU3T2rbJfZtG3W5vGuhRrmYaC-_pXjkvWhXgc4ZkIDV7j-364hyyZXM9W326iIoW9aaj1BhAWuttdXt-sl8aEDsbESEZxCziBE6_Q_MdJ4BvBi8yGp9M2yhjlkh2pNjF_nkl68QwVpsR8HW--2jTwjZLdHhsOl45Fp55ELV_y8czLUuo0-X5Sp6443UBXGA", 
      "expireTime": "2022-09-05T11:12:28Z"  
    }
}

其中,那一长串基于Base64编码的字符串,就是认证Token,而 expireTime 则是此Token的超时时间。

当认证成功获得 Token 后,我们就可以将 Token 放入到 Http头中,以调用花漾 Open API 了。

我们以查看当前用户信息这个 API 接口为例, 请求内容如下:

curl -X 'GET'  'https://api.szdamai.com/openapi/user/current'   -H 'accept: */*' 
  -H 'Authorization: eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJ0b2MiLCJqdGkiOiI2MTY1ODY4MjEyMWI0NzQ1OTNmZDBjYzVjYzAzOTk1NyIsInN1YiI6IkFLLUFLUVpQY3Z4YVRsMU85bkwwUUhjSHp0IiwiZXhwIjoxNjYyMzc2MzQ4fQ.TjG0VLwNrJrn8-XyxHz-OfhNjlLkalan3EBr92cdKc8GGaKwFNEqUpBInKiUJ6ixybIpKnYNpsjxktliw2nIbjYgTnCRbT1G7jHogx2Y_7eDigJjyrpyZwdlZ5ZEGHPn01fNWFS0RkgHqeraQoNwbgVDU3T2rbJfZtG3W5vGuhRrmYaC-_pXjkvWhXgc4ZkIDV7j-364hyyZXM9W326iIoW9aaj1BhAWuttdXt-sl8aEDsbESEZxCziBE6_Q_MdJ4BvBi8yGp9M2yhjlkh2pNjF_nkl68QwVpsR8HW--2jTwjZLdHhsOl45Fp55ELV_y8czLUuo0-X5Sp6443UBXGA'

返回结果如下所示:

{
  "success": true,
  "code": 0,
  "message": null,
  "data": {
    "id": 52394196996096,
    "tenant": null,
    "status": "ACTIVE",
    "nickname": "子非鱼",
    "createTime": "2021-08-27T07:02:51Z",
    "avatar": null,
    "gender": "UNSPECIFIC",
    "signature": "",
    "residentCity": "",
    "userType": "NORMAL",
    "partnerId": null,
    "phone": "186****2179",
    "email": "c****u@1*6.com",
    "weixin": null
  }
}

我们可以看到,通过 “https://api.szdamai.com/openapi/user/current” 接口能够成功查询当前用户的基本信息。

综上,我们已经完整的了解了如何通过Access Key获得认证Token,以及将Token放入到http头中以调用 Open API, 再通过参考花漾目前公开的API列表,理论上您可以通过任何语言/脚本来和花漾客户端进行交互了。

4、示例

4.1 通过Java调用花漾Open API

我们为您准备了一个简单的基于Java语言的示例程序,如下所示:

package com.donkey.openapi.example;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class BasicHttpClientDemo {
    static String accessKeyId = "REPLACE_WITH_YOUR_AKID";
    static String accessKeySecret = "REPLACE_WITH_YOUR_AKSECRET";
    static String endpoint = "https://api.szdamai.com/openapi";

    public static void main(String[] args) throws IOException {
        //获取认证token
        Map<String, Object> resp = request("GET", 
            String.format("/token?accessKeyId=%s&accessKeySecret=%s&expireSeconds=%d", accessKeyId, accessKeySecret, 7200), null);
        String token = (String) resp.get("token");
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", token);

        //请求当前用户信息
        Map<String, Object> userObj = request("GET", "/user/current", headers);
        System.out.println(userObj);
    }

    public static Map<String, Object> request(String method, String path, Map<String, String> headers) throws IOException {
        URL url = new URL(endpoint + path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod(method);
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                conn.setRequestProperty(entry.getKey(), entry.getValue());
            }
        }
        try {
            conn.connect();
            if (200 <= conn.getResponseCode() && conn.getResponseCode() < 300) {
                String responseJson = copy2String(conn.getInputStream());
                Map<String, Object> resp = JsonHelper.jsonDecode(responseJson);
                if (Boolean.TRUE.equals(resp.get("success"))) {
                    return (Map<String, Object>) resp.get("data");
                } else {
                    String msg = (String) resp.get("message");
                    if (msg == null) {
                        msg = conn.getResponseMessage();
                    }
                    throw new IOException("access openapi error :" + msg);
                }
            } else {
                throw new IOException("access openapi error :" + conn.getResponseCode() + " - " + conn.getResponseMessage());
            }
        } finally {
            conn.disconnect();
        }
    }

    public static String copy2String(InputStream inStream) throws IOException {
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inStream.read(buffer)) != -1) {
            result.write(buffer, 0, len);
        }
        String str = result.toString(StandardCharsets.UTF_8.name());
        return str;
    }
}

如有需要,您可以下载 Demo程序的源码

4.2 通过Python调用花漾Open API

同时,我们也为您准备了一个简单的基于Python语言的示例程序,如下所示:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import re
import sys
import requests
import json
import os
apiEndpoint = "https://api.szdamai.com/openapi"
'''
openApi: function to access api url and post parameters
'''
def openApi(url: str, params: dict = None, headers: dict = None, method: str = "GET", contentType: str = "json", timeout: int = 10) -> dict:
    if method == "GET":
        response = requests.get(apiEndpoint + url, params=params, headers=headers, timeout=timeout)
    elif method == "POST":
        if not headers:
            headers = dict()
        if contentType == "json":
            headers["Content-Type"] = "application/json"
            params = json.dumps(params) if params else None
        response = requests.post(apiEndpoint + url, data=params, headers=headers, timeout=timeout)
    elif method == "DELETE":
        response = requests.delete(apiEndpoint + url, data=params, headers=headers, timeout=timeout)
    else:
        return None
    if not response:
        return None
    if not 200 <= response.status_code <= 299:
        return None
    result=json.loads(response.text)
    if result["success"]:
        return result["data"]
    else:
        print("openApi %s error %s"%(url,result["message"]))
        return None

def getToken(accessKeyId, accessKeySecret, expireSeconds=300):
    tokenJson = openApi(
        "/token",
        params={
            "accessKeyId": accessKeyId,
            "accessKeySecret": accessKeySecret,
            "expireSeconds": expireSeconds
        },
    )
    return tokenJson["token"]
def getCurrentUser(token):
    hostJson = openApi(
        "/user/current",
        params={},
        headers={"Authorization": token}
    )
    return hostJson

def main(args, **kwargs): 
    accessKeyId =args[0]
    accessKeySecret =args[1]
    if not accessKeyId or not accessKeySecret:
        print("AccessKeyId and AccessKeySecret are not present.\n")
        return -1
    token = getToken(accessKeyId, accessKeySecret)
    if not token:
        print("Invalid AccessKeyId and AccessKeySecret.\n")
        return -1
    user = getCurrentUser(token=token)
    if user:
        print("Current user is  %s.\n" % (user))
    else:
        print("get Current user fail\n")
if __name__ == "__main__":  
    if len(sys.argv) != 3:
        print("Usage: openapi_demo.py AccessKeyId AccessKeySecret\n")
        sys.exit(-1)
    sys.exit(main(sys.argv[1:3], **dict(arg.split('=') for arg in sys.argv[4:])))

如有需要,您可以点这里下载 Demo程序的源码

4.3 通过Python调用花漾Open API打开浏览器分身后使用selenium控制浏览器

在4.2 Python示例程序的基础上,您可以通过调用花漾Open API打开浏览器分身,并使用selenium进行控制。 这里有几点需要注意:

  1. 可以通过api指定控制端口,比如下面的程序中指定的控制端口是9222;
  2. 可以通过api的browserSwitches参数指定启动浏览器的参数;
  3. accountId指的是分身ID,获取方式见 这里
  4. 需要在本地准备好对应版本的chromedriver,您可以这里下载 chromedriver ,或者直接使用我们提供的 chromedriver
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from time import sleep
# 示例代码中用的selenium是3.141.0
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

import sys
import requests
import json
apiEndpoint = "https://api.szdamai.com/openapi"
'''
openApi: function to access api url and post parameters
'''

def openApi(url: str, params: dict = None, headers: dict = None, method: str = "GET", contentType: str = "json", timeout: int = 10) -> dict:
    if method == "GET":
        response = requests.get(
            apiEndpoint + url, params=params, headers=headers, timeout=timeout)
    elif method == "POST":
        if not headers:
            headers = dict()
        if contentType == "json":
            headers["Content-Type"] = "application/json"
            params = json.dumps(params) if params else None
        response = requests.post(
            apiEndpoint + url, data=params, headers=headers, timeout=timeout)
    elif method == "DELETE":
        response = requests.delete(
            apiEndpoint + url, data=params, headers=headers, timeout=timeout)
    else:
        return None
    if not response:
        return None
    if not 200 <= response.status_code <= 299:
        return None
    result = json.loads(response.text)
    if result["success"]:
        return result["data"]
    else:
        print("openApi %s error %s" % (url, result["message"]))
        return None


def getToken(accessKeyId, accessKeySecret, expireSeconds=300):
    tokenJson = openApi(
        "/token",
        params={
            "accessKeyId": accessKeyId,
            "accessKeySecret": accessKeySecret,
            "expireSeconds": expireSeconds
        },
    )
    return tokenJson["token"]


def getCurrentUser(token):
    hostJson = openApi(
        "/user/current",
        params={},
        headers={"Authorization": token}
    )
    return hostJson


def openSession(token, accountId):
    browserSwitches = "--window-size=700,600\n--window-position=100,50"
    hostJson = openApi(
        "/session/openV2",
        params={
            "accountId": accountId,
            "remoteDebugPort": 9222,
            "browserSwitches": browserSwitches,
        },
        method="POST",
        headers={"Authorization": token}
    )
    return hostJson


def useSelenium():
    chrome_options = Options()

    chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")

    # chromedriver.exe可以在这里下载,必须是对应花漾的内核版本:
    # http://chromedriver.storage.googleapis.com/index.html?path=111.0.5563.41/
    driver = webdriver.Chrome('d:/chromedriver.exe', options=chrome_options)

    # 打开网站
    driver.get('https://www.baidu.com')  # 指定要打开的网站 URL
    sleep(1)
    print(driver.title)


def main(args, **kwargs):
    accessKeyId = args[0]
    accessKeySecret = args[1]
    accountId = args[2]
    if not accessKeyId or not accessKeySecret:
        print("AccessKeyId and AccessKeySecret are not present.\n")
        return -1
    token = getToken(accessKeyId, accessKeySecret)
    if not token:
        print("Invalid AccessKeyId and AccessKeySecret.\n")
        return -1
    user = getCurrentUser(token=token)
    if user:
        print("Current user is  %s.\n" % (user))
        rs = openSession(token, accountId)
        print(rs)
        sleep(10)
        useSelenium()
    else:
        print("get Current user fail\n")


if __name__ == "__main__":
    if len(sys.argv) != 4:
        print("Usage: python SeleniumTest.py AccessKeyId AccessKeySecret accountId\n")
        sys.exit(-1)
    sys.exit(main(sys.argv[1:4], **dict(arg.split('=')
             for arg in sys.argv[5:])))

如有需要,您可以点这里下载 Demo程序的源码

4.4 其它

如果您有新的 API 方面的诉求,或者还希望我们提供其它语言的的Demo,请通过在 在线客服 联络我们。

最后更新于 2023-10-31 10:04
回到顶部