View a markdown version of this page

提取文本并将其发送到 AWS Comprehend 进行分析 - Amazon Textract

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

提取文本并将其发送到 AWS Comprehend 进行分析

Amazon Textract 允许您在应用程序中加入文档文本检测和分析。借助 Amazon Textract,您可以使用同步和异步文档处理从各种不同的文档类型中提取文本。然后,可以将提取的文本保存到文件或数据库中,或者发送到其他 AWS 服务进行进一步处理。

在本教程中,您将执行常见的端到端工作流程。此工作流程涉及:

  • 使用 Amazon Textract 处理大量输入文档

  • 将提取的文本提供给 Amazon Comprehend 进行分析

  • 将分析的文本和分析数据保存到 Amazon Simple Storage Service 存储桶中

在本教程中,您将使用AWS 适用于 Python 的软件开发工具包。您还可以查看 AWS 文档 SDK 示例存储库,了解更多 GitHub P ython 教程。

先决条件

在开始本教程之前,你需要安装 Python 并完成设置 Python AWS 开发工具包所需的步骤。除此之外,请确保您:

启动异步文档文本检测

您可以从文档中提取文本,然后使用诸如 Amazon Comprehend 之类的服务分析提取的文本。Textract 支持通过异步操作从多页文档中提取文本,异步操作用于处理大型多页文档。异步处理 PDF 文件允许您的应用程序在等待流程完成的同时完成其他任务。本节将演示如何从 Amazon S3 存储桶导入您的文档并将其提供给 Textract 的异步文本检测操作。

本教程假设您将使用 Amazon S3 存储要从中提取文本的文件。首先,您将创建一个类和函数来检测输入文档中的文本。您的应用程序需要连接到 Textract 客户端,以及亚马逊 SQS 和亚马逊 SNS 客户端,才能监控异步任务的完成状态。

  1. 首先编写代码,创建亚马逊 SNS 主题和亚马逊 SQS 队列。

    以下代码示例创建了一个连接到三种必需服务的DocumentProcessor类,然后创建了 Amazon SQS 队列和 Amazon SNS 主题。Amazon SNS 主题用于向 Amazon SQS 队列提供有关任务完成状态的信息,将对该队列进行轮询以获取任务的完成状态。还有一些方法可以在任务完成且不再需要资源后删除 Amazon SQS 队列和 Amazon SNS 主题。

    import boto3 import json import sys import time class DocumentProcessor: jobId = '' region_name = '' roleArn = '' bucket = '' document = '' sqsQueueUrl = '' snsTopicArn = '' processType = '' def __init__(self, role, bucket, document, region): self.roleArn = role self.bucket = bucket self.document = document self.region_name = region # Instantiates necessary AWS clients session = boto3.Session(profile_name='profile-name', region_name='self.region_name') self.textract = session.client('textract', region_name=self.region_name) self.sqs = session.client('sqs', region_name=self.region_name) self.sns = session.client('sns', region_name=self.region_name) def CreateTopicandQueue(self): millis = str(int(round(time.time() * 1000))) # Create SNS topic snsTopicName = "AmazonTextractTopic" + millis topicResponse = self.sns.create_topic(Name=snsTopicName) self.snsTopicArn = topicResponse['TopicArn'] # create SQS queue sqsQueueName = "AmazonTextractQueue" + millis self.sqs.create_queue(QueueName=sqsQueueName) self.sqsQueueUrl = self.sqs.get_queue_url(QueueName=sqsQueueName)['QueueUrl'] attribs = self.sqs.get_queue_attributes(QueueUrl=self.sqsQueueUrl, AttributeNames=['QueueArn'])['Attributes'] sqsQueueArn = attribs['QueueArn'] # Subscribe SQS queue to SNS topic self.sns.subscribe( TopicArn=self.snsTopicArn, Protocol='sqs', Endpoint=sqsQueueArn) # Authorize SNS to write SQS queue policy = """{{ "Version": "2012-10-17", "Statement":[ {{ "Sid":"MyPolicy", "Effect":"Allow", "Principal" : {{"AWS" : "*"}}, "Action":"SQS:SendMessage", "Resource": "{}", "Condition":{{ "ArnEquals":{{ "aws:SourceArn": "{}" }} }} }} ] }}""".format(sqsQueueArn, self.snsTopicArn) response = self.sqs.set_queue_attributes( QueueUrl=self.sqsQueueUrl, Attributes={ 'Policy': policy }) def DeleteTopicandQueue(self): self.sqs.delete_queue(QueueUrl=self.sqsQueueUrl) self.sns.delete_topic(TopicArn=self.snsTopicArn)
  2. 编写代码以调用StartDocumentTextDetection操作并获取操作结果。

    DocumentProcessor类还需要方法来:

    • 调用该StartDocumentTextDetection操作

    • 向 Amazon SQS 投票,了解任务完成状态

    • 任务处理完成后检索其结果

    以下代码创建了ProcessDocumentGetResults方法,分别调用StartDocumentTextDetection和获取提取的文本。

    def ProcessDocument(self): # Checks if job found jobFound = False # Starts the text detection operation on the documents in the provided bucket # Sends status to supplied SNS topic arn response = self.textract.start_document_text_detection( DocumentLocation={'S3Object': {'Bucket': self.bucket, 'Name': self.document}}, NotificationChannel={'RoleArn': self.roleArn, 'SNSTopicArn': self.snsTopicArn}) print('Processing type: Detection') print('Start Job Id: ' + response['JobId']) dotLine = 0 while jobFound == False: sqsResponse = self.sqs.receive_message(QueueUrl=self.sqsQueueUrl, MessageAttributeNames=['ALL'], MaxNumberOfMessages=10) # Waits until messages are found in the SQS queue if sqsResponse: if 'Messages' not in sqsResponse: if dotLine < 40: print('.', end='') dotLine = dotLine + 1 else: print() dotLine = 0 sys.stdout.flush() time.sleep(5) continue # Checks for a completed job that matches the jobID in the response from # StartDocumentTextDetection for message in sqsResponse['Messages']: notification = json.loads(message['Body']) textMessage = json.loads(notification['Message']) if str(textMessage['JobId']) == response['JobId']: print('Matching Job Found:' + textMessage['JobId']) jobFound = True text_data = self.GetResults(textMessage['JobId']) self.sqs.delete_message(QueueUrl=self.sqsQueueUrl, ReceiptHandle=message['ReceiptHandle']) return text_data else: print("Job didn't match:" + str(textMessage['JobId']) + ' : ' + str(response['JobId'])) # Delete the unknown message. Consider sending to dead letter queue self.sqs.delete_message(QueueUrl=self.sqsQueueUrl, ReceiptHandle=message['ReceiptHandle']) print('Done!') # gets the results of the completed text detection job # checks for pagination tokens to determine if there are multiple pages in the input doc def GetResults(self, jobId): maxResults = 1000 paginationToken = None finished = False while finished == False: response = None if paginationToken == None: response = self.textract.get_document_text_detection(JobId=jobId, MaxResults=maxResults) else: response = self.textract.get_document_text_detection(JobId=jobId, MaxResults=maxResults, NextToken=paginationToken) blocks = response['Blocks'] # List to hold detected text detected_text = [] # Display block information and add detected text to list for block in blocks: if 'Text' in block and block['BlockType'] == "LINE": detected_text.append(block['Text']) # If response contains a next token, update pagination token if 'NextToken' in response: paginationToken = response['NextToken'] else: finished = True return detected_text
  3. 将上述代码保存在名为的文件中detectFileAsync.py

    在下一节中,您将使用此文件来处理输入文档中文本的检测。

处理您的文档并将文本发送给 Comprehend

您的应用程序将使用您在上一节中创建的类来:

  • 读取您的 Amazon S3 存储桶中的文档

  • 提取这些文档中的文本

  • 将文本发送到亚马逊 Comprehend 进行分析

首先,您需要创建一些函数,这些函数利用 Amazon Comprehend 来分析在输入文档中检测到的文本。一种常见的文本分析是情感分析,它旨在捕捉陈述的影响(无论是正面、负面还是中立)。您还可以对数据进行实体检测和关键短语检测。

以下代码接收检测到的文本,并从 Amazon Comprehend 调用该BatchDetectSentiment操作以进行情绪分析。

  1. 编写代码,对检测到的文本进行情感分析。

    from detectFileAsync import DocumentProcessor import boto3 import pandas as pd # Detect sentiment def sentiment_analysis(detected_text, lang): comprehend = boto3.client("comprehend") detect_sent_response = comprehend.batch_detect_sentiment( TextList=detected_text, LanguageCode=lang) # Lists to hold sentiment labels and sentiment scores sentiments = [] pos_score = [] neg_score = [] neutral_score = [] mixed_score = [] # for all results add the Sentiment label and sentiment scores to lists for res in detect_sent_response['ResultList']: sentiments.append(res['Sentiment']) print(res['SentimentScore']) print(type(res['SentimentScore'])) for key, val in res['SentimentScore'].items(): if key == "Positive": pos_score.append(val) if key == "Negative": neg_score.append(val) if key == "Neutral": neutral_score.append(val) if key == "Mixed": mixed_score.append(val) return sentiments, pos_score, neg_score, neutral_score, mixed_score

    您可能还想对检测到的文本执行其他分析操作,例如实体检测或关键短语检测。你可以编写函数来对文本执行这些分析操作,就像你为正在进行的情感分析操作所做的那样。

  2. 编写代码以对检测到的文本进行实体检测。

    # detect entities def entity_detection(detected_text, lang): comprehend = boto3.client("comprehend") # convert and handle string here # do string handling detect_ent_response = comprehend.batch_detect_entities( TextList=detected_text, LanguageCode=lang) # To fold detected entities and entity types ents = [] types = [] # Get detected entities and types from the response returned by Comprehend for i in detect_ent_response['ResultList']: if len(i['Entities']) == 0: ents.append("N/A") types.append("N/A") else: sentence_ents = [] sentence_types = [] for entities in i['Entities']: sentence_ents.append(entities['Text']) sentence_types.append(entities['Type']) ents.append(sentence_ents) types.append(sentence_types) return ents, types
  3. 编写代码以对检测到的文本进行关键短语检测。

    # Detect key phrases def key_phrases_detection(detected_text, lang): comprehend = boto3.client("comprehend") key_phrases = [] detect_phrases_response = comprehend.batch_detect_key_phrases( TextList=detected_text, LanguageCode=lang) for i in detect_phrases_response['ResultList']: if len(i['KeyPhrases']) == 0: key_phrases.append("N/A") else: phrases = [] for phrase in i['KeyPhrases']: phrases.append(phrase['Text']) key_phrases.append(phrases) return key_phrases

    你需要创建一个函数来调用你到目前为止创建的所有代码。该函数将使用您在DetectAnalyzeFileAsync.py文件中创建的DocumentProcessor类,然后将检测到的文本保存到变量中,以便使用您之前编写的 Amazon Comprehend 输入到三个函数中。该函数还需要构造一个 Pandas 数据框,将检测到的文本和分析数据插入其中。最后,Pandas 数据框将保存为 CSV 文件。

  4. 编写代码以使用 Textract 处理您的输入文档,并将检测到的文本传递给 Comprehend。

    def process_document(roleArn, bucket, document, region_name): # Create analyzer class from DocumentProcessor, create a topic and queue, use Textract to get text, # then delete topica and queue analyzer = DocumentProcessor(roleArn, bucket, document, region_name) analyzer.CreateTopicandQueue() extracted_text = analyzer.ProcessDocument() analyzer.DeleteTopicandQueue() # detect dominant language comprehend = boto3.client("comprehend") response = comprehend.detect_dominant_language(Text=str(extracted_text[:10])) print(response) print(type(response)) lang = "" for i in response['Languages']: lang = i['LanguageCode'] print(lang) # or you can enter language code below # lang = "en" print("Lines in detected text:" + str(len(extracted_text))) sliced_list = [] start = 0 end = 24 while end < len(extracted_text): sliced_list.append(extracted_text[start:end]) start += 25 end += 25 print(sliced_list) # Create lists to hold analytics data, these will be turned into columns all_sents = [] all_scores = [] all_ents = [] all_types = [] all_key_phrases = [] all_pos_ratings = [] all_neg_ratings = [] all_neutral_ratings = [] all_mixed_ratings = [] # For every slice, get sentiment analysis, entity detection and key phrases, append results to lists for slice in sliced_list: slice_labels, pos_ratings, neg_ratings, neutral_ratings, mixed_ratings = sentiment_analysis(slice, lang) all_sents.append(slice_labels) all_pos_ratings.append(pos_ratings) all_neg_ratings.append(neg_ratings) all_neutral_ratings.append(neutral_ratings) all_mixed_ratings.append(mixed_ratings) slice_ents, slice_types = entity_detection(slice, lang) all_ents.append(slice_ents) all_types.append(slice_types) key_phrases = key_phrases_detection(slice, lang) all_key_phrases.append(key_phrases) # List comprehension to flatten multiple lists into a single list extracted_text = [line for sublist in sliced_list for line in sublist] all_sents = [sent for sublist in all_sents for sent in sublist] all_scores = [score for sublist in all_scores for score in sublist] all_ents = [ents for sublist in all_ents for ents in sublist] all_types = [types for sublist in all_types for types in sublist] all_key_phrases = [kp for sublist in all_key_phrases for kp in sublist] all_mixed_ratings = [kp for sublist in all_mixed_ratings for kp in sublist] all_pos_ratings = [kp for sublist in all_pos_ratings for kp in sublist] all_neg_ratings = [kp for sublist in all_neg_ratings for kp in sublist] all_neutral_ratings = [kp for sublist in all_neutral_ratings for kp in sublist] print(len(extracted_text)) print(len(all_sents)) print(len(all_ents)) print(len(all_types)) print(len(all_key_phrases)) print("List of Recognized Entities:") # Create dataframe and save as CSV df = pd.DataFrame({'Sentences':extracted_text, 'Sentiment':all_sents, 'SentPosScore':all_pos_ratings, 'SentNegScore':all_neg_ratings, 'SentNeutralScore':all_neutral_ratings, 'SentMixedRatings':all_mixed_ratings, 'Entities':all_ents, 'EntityTypes':all_types,'KeyPhrases:':all_key_phrases}) analysis_results = str(document.replace(".","_") + "_" + "analysis" + ".csv") df.to_csv(analysis_results, index=False) print(df) print("Data written to file!") return extracted_text, analysis_results
  5. 编写代码以处理您的文档并将生成的数据上传到 S3。在下面的代码示例中,将的值替换为您配置的roleArn用于 Amazon Textract 的角色的 ARN。将的region_name值替换为您的账户运营所在的区域。最后,将该值bucket_name替换为包含您的文档的 S3 存储桶的名称。

    def main(): # Initialize S3 client and set RoleArn, region name, and bucket name s3 = boto3.client("s3") roleArn = '' region_name = '' bucket_name = '' # initialize global corpus full_corpus = [] # to hold all docs in bucket docs_list = [] # loop through docs in bucket, get names of all docs s3_resource = boto3.resource("s3") bucket = s3_resource.Bucket(bucket_name) for bucket_object in bucket.objects.all(): docs_list.append(bucket_object.key) print(docs_list) # For all the docs in the bucket, invoke document processing function, # add detected text to corpus of all text in batch docs, # and save CSV of comprehend analysis data and textract detected to S3 for i in docs_list: detected_text, analysis_results = process_document(roleArn, bucket_name, i, region_name) full_corpus.append(detected_text) print("Uploading file: {}".format(str(analysis_results))) name_of_file = str(analysis_results) s3.upload_file(name_of_file, bucket_name, name_of_file) # print the global corpus print(full_corpus) if __name__ == "__main__": main()
  6. 将该部分中的后续代码放入 Python 文件中并运行。

您已成功使用 Amazon Textract 提取文本,将文本发送到 Amazon Comprehend 进行分析,然后将结果保存在 Amazon S3 存储桶中。