教程:使用 Azure Functions 和 Python 处理存储的文档

可以使用文档智能作为通过 Azure Functions 生成的自动化数据处理管道的一部分。 本指南将介绍如何使用 Azure Functions 来处理已上传到 Azure Blob 存储容器的文档。 此工作流使用文档智能布局模型从存储的文档中提取表数据,然后将表数据以 .csv 文件形式保存到 Azure 中。 然后,你可以使用 Power BI(本文未介绍)来显示数据。

Azure 服务工作流示意图的屏幕截图

在本教程中,你将了解如何执行以下操作:

  • 创建 Azure 存储帐户。
  • 创建 Azure Functions 项目。
  • 从上传的表单中提取布局数据。
  • 将提取的布局数据上传到 Azure 存储。

先决条件

创建 Azure 存储帐户

  1. 在 Azure 门户中创建常规用途 v2 Azure 存储帐户。 如果不知道如何使用存储容器创建 Azure 存储帐户,请按照以下快速入门操作:

    • 创建存储帐户。 创建存储帐户时,在“实例详细信息”>“性能”字段中选择“标准”性能 。
    • 创建容器。 创建容器时,在“新建容器”窗口中将“公共访问级别”设置为“容器(对容器和文件进行匿名读取访问)”。
  2. 在左侧窗格中选择“资源共享(CORS)”选项卡,并删除现有的 CORS 策略(如果有)。

  3. 部署存储帐户后,创建名为 input 和 output 的两个空 Blob 存储容器。

创建 Azure Functions 项目

  1. 创建名为 functions-app 的新文件夹以包含项目,然后选择“选择”。

  2. 打开 Visual Studio Code,然后打开命令面板 (Ctrl+Shift+P)。 搜索并选择“Python: 选择解释器” → 选择版本为 3.6.x、3.7.x、3.8.x 或 3.9.x 的已安装 Python 解释器。 此选择将你所选的 Python 解释器路径添加到项目。

  3. 从左侧导航窗格中选择 Azure 徽标。

    • 你将在“资源”视图中看到现有的 Azure 资源。

    • 选择要用于此项目的 Azure 订阅,然后在下面会看到 Azure 函数应用。

      一个列表的屏幕截图,其中以单个统一的视图显示 Azure 资源。

  4. 选择位于列出的资源下的“工作区(本地)”部分。 选择加号,然后选择“创建函数”按钮。

    显示要开始创建 Azure 函数的位置的屏幕截图。

  5. 出现提示时,选择“新建项目”并导航到 Function-app 目录。 选择“选择” 。

  6. 系统将提示你配置一些设置:

    • 选择语言 → 选择 Python。

    • 选择 Python 解释器来创建虚拟环境 → 选择前面设置为默认值的解释器。

    • 选择模板 → 选择“Azure Blob 存储触发器”,并为触发器指定名称或接受默认名称。 按 Enter 以确认。

    • 选择设置 → 从下拉菜单中选择“➕创建新的本地应用设置”。

    • 选择订阅 → 选择包含你创建的存储帐户的 Azure 订阅 → 选择存储帐户 → 然后选择存储输入容器的名称(在本例中为 input/{name})。 按 Enter 以确认。

    • 选择要用于打开项目的方式 → 从下拉菜单中选择“在当前窗口中打开项目”。

  7. 完成这些步骤后,VS Code 将使用一个 __init__.py Python 脚本添加新的 Azure 函数项目。 将文件上传到 input 存储容器时将触发此脚本:

import logging

import azure.functions as func


def main(myblob: func.InputStream):
    logging.info(f"Python blob trigger function processed blob \n"
                 f"Name: {myblob.name}\n"
                 f"Blob Size: {myblob.length} bytes")

测试函数

  1. 按 F5 运行基本函数。 VS Code 将提示你选择要对接到的存储帐户。

  2. 选择创建的存储帐户,然后继续操作。

  3. 打开 Azure 存储资源管理器并将示例 PDF 文档上传到 input 容器。 然后查看 VS Code 终端。 该脚本应会记录它已由 PDF 上传操作触发。

    上传新文档后 VS Code 终端的屏幕截图。

  4. 在继续操作之前停止脚本。

添加文档处理代码

接下来,将你自己的代码添加到 Python 脚本,以调用文档智能服务,并使用文档智能布局模型分析上传的文档。

  1. 在 VS Code 中导航到函数的 requirements.txt 文件。 此文件定义脚本的依赖项。 将以下 Python 包添加到该文件:

    cryptography
    azure-functions
    azure-storage-blob
    azure-identity
    requests
    pandas
    numpy
    
  2. 然后打开 __init__.py 脚本。 添加以下 import 语句:

    import logging
    from azure.storage.blob import BlobServiceClient
    import azure.functions as func
    import json
    import time
    from requests import get, post
    import os
    import requests
    from collections import OrderedDict
    import numpy as np
    import pandas as pd
    
  3. 可将生成的 main 函数保留原样。 稍后你要将自己的自定义代码添加到此函数中。

    # This part is automatically generated
    def main(myblob: func.InputStream):
        logging.info(f"Python blob trigger function processed blob \n"
        f"Name: {myblob.name}\n"
        f"Blob Size: {myblob.length} bytes")
    
  4. 以下代码块针对上传的文档调用文档智能分析布局 API。 填写终结点和密钥值。

    # This is the call to the Document Intelligence endpoint
        endpoint = r"Your Document Intelligence Endpoint"
        apim_key = "Your Document Intelligence Key"
        post_url = endpoint + "/formrecognizer/v2.1/layout/analyze"
        source = myblob.read()
    
        headers = {
        # Request headers
        'Content-Type': 'application/pdf',
        'Ocp-Apim-Subscription-Key': apim_key,
            }
    
        text1=os.path.basename(myblob.name)
    

    重要

    完成后,请记住将密钥从代码中删除,并且永远不要公开发布该密钥。 对于生产来说,请使用安全的方式存储和访问凭据,例如 Azure Key Vault。 有关详细信息,请参阅 Azure AI 服务安全性

  5. 接下来,添加代码以查询服务并获取返回的数据。

    resp = requests.post(url=post_url, data=source, headers=headers)
    
    if resp.status_code != 202:
        print("POST analyze failed:\n%s" % resp.text)
        quit()
    print("POST analyze succeeded:\n%s" % resp.headers)
    get_url = resp.headers["operation-location"]
    
    wait_sec = 25
    
    time.sleep(wait_sec)
    # The layout API is async therefore the wait statement
    
    resp = requests.get(url=get_url, headers={"Ocp-Apim-Subscription-Key": apim_key})
    
    resp_json = json.loads(resp.text)
    
    status = resp_json["status"]
    
    if status == "succeeded":
        print("POST Layout Analysis succeeded:\n%s")
        results = resp_json
    else:
        print("GET Layout results failed:\n%s")
        quit()
    
    results = resp_json
    
    
  6. 添加以下代码以连接到 Azure 存储的 output 容器。 填写你自己的存储帐户名称和密钥值。 可以在 Azure 门户中你的存储资源的“访问密钥”选项卡上获得该密钥。

    # This is the connection to the blob storage, with the Azure Python SDK
        blob_service_client = BlobServiceClient.from_connection_string("DefaultEndpointsProtocol=https;AccountName="Storage Account Name";AccountKey="storage account key";EndpointSuffix=core.chinacloudapi.cn")
        container_client=blob_service_client.get_container_client("output")
    

    以下代码分析返回的文档智能响应,构造一个 .csv 文件,然后将其上传到 output 容器。

    重要

    你可能需要编辑此代码,使之与你自己的文档结构相符。

        # The code below extracts the json format into tabular data.
        # Please note that you need to adjust the code below to your form structure.
        # It probably won't work out-of-the-box for your specific form.
        pages = results["analyzeResult"]["pageResults"]
    
        def make_page(p):
            res=[]
            res_table=[]
            y=0
            page = pages[p]
            for tab in page["tables"]:
                for cell in tab["cells"]:
                    res.append(cell)
                    res_table.append(y)
                y=y+1
    
            res_table=pd.DataFrame(res_table)
            res=pd.DataFrame(res)
            res["table_num"]=res_table[0]
            h=res.drop(columns=["boundingBox","elements"])
            h.loc[:,"rownum"]=range(0,len(h))
            num_table=max(h["table_num"])
            return h, num_table, p
    
        h, num_table, p= make_page(0)
    
        for k in range(num_table+1):
            new_table=h[h.table_num==k]
            new_table.loc[:,"rownum"]=range(0,len(new_table))
            row_table=pages[p]["tables"][k]["rows"]
            col_table=pages[p]["tables"][k]["columns"]
            b=np.zeros((row_table,col_table))
            b=pd.DataFrame(b)
            s=0
            for i,j in zip(new_table["rowIndex"],new_table["columnIndex"]):
                b.loc[i,j]=new_table.loc[new_table.loc[s,"rownum"],"text"]
                s=s+1
    
    
  7. 最后,最后一个代码块将提取的表和文本数据上传到 Blob 存储元素。

        # Here is the upload to the blob storage
        tab1_csv=b.to_csv(header=False,index=False,mode='w')
        name1=(os.path.splitext(text1)[0]) +'.csv'
        container_client.upload_blob(name=name1,data=tab1_csv)
    

运行函数

  1. 再次按 F5 运行函数。

  2. 使用 Azure 存储资源管理器将一个示例 PDF 表单上传到 input 存储容器。 此操作应会触发脚本的运行,然后 output 容器中应会显示生成的 .csv 文件(以表的形式显示)。

可将此容器连接到 Power BI,以便为其包含的数据创建丰富的可视化效果。

后续步骤

在本教程中,你已学习如何使用一个以 Python 编写的 Azure 函数来自动处理上传的 PDF 文档,并以一种更易于阅读数据的格式输出其内容。 接下来,请学习如何使用 Power BI 显示数据。