In this quickstart, you'll use the Azure Form Recognizer REST API with Python to extract text layout information and table data from form documents.
If you don't have an Azure subscription, create a free account before you begin.
To complete this quickstart, you must have:
- Python installed (if you want to run the sample locally).
- A form document. You can download an image from the sample data set (download and extract sample_data.zip) for this quickstart.
Note
This quickstart uses a locally stored document. To use learn how to use remote files accessed by URL, see the reference documentation.
Go to the Azure portal and create a new Form Recognizer resource . In the Create pane, provide the following information:
Name | A descriptive name for your resource. We recommend using a descriptive name, for example MyNameFormRecognizer. |
Subscription | Select the Azure subscription which has been granted access. |
Location | The location of your cognitive service instance. Different locations may introduce latency, but have no impact on the runtime availability of your resource. |
Pricing tier | The cost of your resource depends on the pricing tier you choose and your usage. For more information, see the API pricing details. |
Resource group | The Azure resource group that will contain your resource. You can create a new group or add it to a pre-existing group. |
Note
Normally when you create a Cognitive Service resource in the Azure portal, you have the option to create a multi-service subscription key (used across multiple cognitive services) or a single-service subscription key (used only with a specific cognitive service). However currently Form Recognizer is not included in the multi-service subscription.
When your Form Recognizer resource finishes deploying, find and select it from the All resources list in the portal. Your key and endpoint will be located on the resource's key and endpoint page, under resource management. Save both of these to a temporary location before going forward.
To start analyzing the layout, you call the Analyze Layout API using the Python script below. Before you run the script, make these changes:
- Replace
<Endpoint>
with the endpoint that you obtained with your Form Recognizer subscription. - Replace
<path to your form>
with the path to your local form document. - Replace
<subscription key>
with the subscription key you copied from the previous step.
########### Python Form Recognizer Async Layout #############
import json
import time
from requests import get, post
# Endpoint URL
endpoint = r"<Endpoint>"
apim_key = "<Subscription Key>"
post_url = endpoint + "/formrecognizer/v2.1/layout/analyze"
source = r"<path to your form>"
headers = {
# Request headers
# Change Content-Type as appropriate
'Content-Type': 'application/pdf',
'Ocp-Apim-Subscription-Key': apim_key,
}
with open(source, "rb") as f:
data_bytes = f.read()
try:
resp = post(url = post_url, data = data_bytes, 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"]
except Exception as e:
print("POST analyze failed:\n%s" % str(e))
quit()
########### Python Form Recognizer Async Layout #############
import json
import time
from requests import get, post
# Endpoint URL
endpoint = r"<Endpoint>"
apim_key = "<Subscription Key>"
post_url = endpoint + "/formrecognizer/v2.0/Layout/analyze"
source = r"<path to your form>"
headers = {
# Request headers
# Change Content-Type as appropriate
'Content-Type': 'application/pdf',
'Ocp-Apim-Subscription-Key': apim_key,
}
with open(source, "rb") as f:
data_bytes = f.read()
try:
resp = post(url = post_url, data = data_bytes, 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"]
except Exception as e:
print("POST analyze failed:\n%s" % str(e))
quit()
- Save the code in a file with a .py extension. For example, form-recognizer-layout.py.
- Open a command prompt window.
- At the prompt, use the
python
command to run the sample. For example,python form-recognizer-layout.py
.
You'll receive a 202 (Success)
response that includes an Operation-Location header, which the script will print to the console. This header contains an operation ID that you can use to query the status of the asynchronous operation and get the results. In the following example value, the string after operations/
is the operation ID.
https://westus.api.cognitive.microsoft.com/formrecognizer/v2.1/layout/analyzeResults/a8b6a240-cb40-4c7f-8332-01d97861ac6e
https://cognitiveservice/formrecognizer/v2.0/layout/operations/54f0b076-4e38-43e5-81bd-b85b8835fdfb
After you've called the Analyze Layout API, you call the Get Analyze Layout Result API to get the status of the operation and the extracted data. Add the following code to the bottom of your Python script. This code uses the operation ID value in a new API call. This script calls the API at regular intervals until the results are available. We recommend an interval of one second or more.
n_tries = 10
n_try = 0
wait_sec = 6
while n_try < n_tries:
try:
resp = get(url = get_url, headers = {"Ocp-Apim-Subscription-Key": apim_key})
resp_json = json.loads(resp.text)
if resp.status_code != 200:
print("GET Layout results failed:\n%s" % resp_json)
quit()
status = resp_json["status"]
if status == "succeeded":
print("Layout Analysis succeeded:\n%s" % resp_json)
quit()
if status == "failed":
print("Layout Analysis failed:\n%s" % resp_json)
quit()
# Analysis still running. Wait and retry.
time.sleep(wait_sec)
n_try += 1
except Exception as e:
msg = "GET analyze results failed:\n%s" % str(e)
print(msg)
quit()
- Save the script.
- Again use the
python
command to run the sample. For example,python form-recognizer-layout.py
.
The script will print responses to the console until the Analyze Layout operation completes. Then, it will print the extracted data in JSON format. The "readResults"
node contains every line of text with its respective bounding box placement on the page. The "selectionMarks"
node (in v2.1) shows every selection mark (checkbox, radio mark) and whether its status is "selected" or "unselected". The "pageResults"
field shows every piece of text within tables, each with its row-column coordinate.
See the following invoice image and its corresponding JSON output. The output has been shortened for simplicity.
:::image type="content" source="../media/contoso-invoice.png" alt-text="Contoso project statement document with a table.":::
{
"status": "succeeded",
"createdDateTime": "2020-08-20T20:36:52Z",
"lastUpdatedDateTime": "2020-08-20T20:36:58Z",
"analyzeResult": {
"version": "2.0.0",
"readResults": [
{
"page": 1,
"language": "en",
"angle": 0,
"width": 8.5,
"height": 11,
"unit": "inch",
"lines": [
{
"boundingBox": [
0.5826,
0.4411,
2.3387,
0.4411,
2.3387,
0.7969,
0.5826,
0.7969
],
"text": "Contoso, Ltd.",
"words": [
{
"boundingBox": [
0.5826,
0.4411,
1.744,
0.4411,
1.744,
0.7969,
0.5826,
0.7969
],
"text": "Contoso,",
"confidence": 1
},
{
"boundingBox": [
1.8448,
0.4446,
2.3387,
0.4446,
2.3387,
0.7631,
1.8448,
0.7631
],
"text": "Ltd.",
"confidence": 1
}
]
},
...
]
}
],
"pageResults": [
{
"page": 1,
"tables": [
{
"rows": 5,
"columns": 5,
"cells": [
{
"rowIndex": 0,
"columnIndex": 0,
"text": "Training Date",
"boundingBox": [
0.5133,
4.2167,
1.7567,
4.2167,
1.7567,
4.4492,
0.5133,
4.4492
],
"elements": [
"#/readResults/0/lines/14/words/0",
"#/readResults/0/lines/14/words/1"
]
},
...
]
},
...
]
}
]
}
}
{
"status": "succeeded",
"createdDateTime": "2020-08-20T20:36:52Z",
"lastUpdatedDateTime": "2020-08-20T20:36:58Z",
"analyzeResult": {
"version": "2.0.0",
"readResults": [
{
"page": 1,
"language": "en",
"angle": 0,
"width": 8.5,
"height": 11,
"unit": "inch",
"lines": [
{
"boundingBox": [
0.5826,
0.4411,
2.3387,
0.4411,
2.3387,
0.7969,
0.5826,
0.7969
],
"text": "Contoso, Ltd.",
"words": [
{
"boundingBox": [
0.5826,
0.4411,
1.744,
0.4411,
1.744,
0.7969,
0.5826,
0.7969
],
"text": "Contoso,",
"confidence": 1
},
{
"boundingBox": [
1.8448,
0.4446,
2.3387,
0.4446,
2.3387,
0.7631,
1.8448,
0.7631
],
"text": "Ltd.",
"confidence": 1
}
]
},
...
]
}
],
"pageResults": [
{
"page": 1,
"tables": [
{
"rows": 5,
"columns": 5,
"cells": [
{
"rowIndex": 0,
"columnIndex": 0,
"text": "Training Date",
"boundingBox": [
0.5133,
4.2167,
1.7567,
4.2167,
1.7567,
4.4492,
0.5133,
4.4492
],
"elements": [
"#/readResults/0/lines/14/words/0",
"#/readResults/0/lines/14/words/1"
]
},
...
]
},
...
]
}
]
}
}
In this quickstart, you used the Form Recognizer REST API with Python to extract the text layout of an invoice. Next, see the reference documentation to explore the Form Recognizer API in more depth.