本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
提取文本并将其发送到 AWS Comprehend 进行分析
Amazon Textract 允许您在应用程序中加入文档文本检测和分析。借助 Amazon Textract,您可以使用同步和异步文档处理从各种不同的文档类型中提取文本。然后,可以将提取的文本保存到文件或数据库中,或者发送到其他 AWS 服务进行进一步处理。
在本教程中,您将执行常见的端到端工作流程。此工作流程涉及:
-
使用 Amazon Textract 处理大量输入文档
-
将提取的文本提供给 Amazon Comprehend 进行分析
-
将分析的文本和分析数据保存到 Amazon Simple Storage Service 存储桶中
在本教程中,您将使用AWS 适用于 Python 的软件开发工具包
先决条件
在开始本教程之前,你需要安装 Python 并完成设置 Python AWS 开发工具包
-
将 Amazon Textract 配置为异步处理,复制您配置为与亚马逊 Textract 一起使用的 IAM 角色的亚马逊资源编号 (ARN)
-
为文本目的选择了几个文档, extraction/analysis 并将该文档上传到 Amazon S3。确保您选择进行分析的文件采用亚马逊 Textract 支持的格式。
启动异步文档文本检测
您可以从文档中提取文本,然后使用诸如 Amazon Comprehend 之类的服务分析提取的文本。Textract 支持通过异步操作从多页文档中提取文本,异步操作用于处理大型多页文档。异步处理 PDF 文件允许您的应用程序在等待流程完成的同时完成其他任务。本节将演示如何从 Amazon S3 存储桶导入您的文档并将其提供给 Textract 的异步文本检测操作。
本教程假设您将使用 Amazon S3 存储要从中提取文本的文件。首先,您将创建一个类和函数来检测输入文档中的文本。您的应用程序需要连接到 Textract 客户端,以及亚马逊 SQS 和亚马逊 SNS 客户端,才能监控异步任务的完成状态。
-
首先编写代码,创建亚马逊 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) -
编写代码以调用
StartDocumentTextDetection操作并获取操作结果。该
DocumentProcessor类还需要方法来:-
调用该
StartDocumentTextDetection操作 -
向 Amazon SQS 投票,了解任务完成状态
-
任务处理完成后检索其结果
以下代码创建了
ProcessDocument和GetResults方法,分别调用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 -
-
将上述代码保存在名为的文件中
detectFileAsync.py。在下一节中,您将使用此文件来处理输入文档中文本的检测。
处理您的文档并将文本发送给 Comprehend
您的应用程序将使用您在上一节中创建的类来:
-
读取您的 Amazon S3 存储桶中的文档
-
提取这些文档中的文本
-
将文本发送到亚马逊 Comprehend 进行分析
首先,您需要创建一些函数,这些函数利用 Amazon Comprehend 来分析在输入文档中检测到的文本。一种常见的文本分析是情感分析,它旨在捕捉陈述的影响(无论是正面、负面还是中立)。您还可以对数据进行实体检测和关键短语检测。
以下代码接收检测到的文本,并从 Amazon Comprehend 调用该BatchDetectSentiment操作以进行情绪分析。
-
编写代码,对检测到的文本进行情感分析。
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您可能还想对检测到的文本执行其他分析操作,例如实体检测或关键短语检测。你可以编写函数来对文本执行这些分析操作,就像你为正在进行的情感分析操作所做的那样。
-
编写代码以对检测到的文本进行实体检测。
# 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 -
编写代码以对检测到的文本进行关键短语检测。
# 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 文件。 -
编写代码以使用 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 -
编写代码以处理您的文档并将生成的数据上传到 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() -
将该部分中的后续代码放入 Python 文件中并运行。
您已成功使用 Amazon Textract 提取文本,将文本发送到 Amazon Comprehend 进行分析,然后将结果保存在 Amazon S3 存储桶中。