View a markdown version of this page

Extraer y enviar texto a AWS Comprehend para su análisis - Amazon Textract

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Extraer y enviar texto a AWS Comprehend para su análisis

Amazon Textract le permite incluir la detección y el análisis del texto de los documentos en sus aplicaciones. Con Amazon Textract, puede extraer texto de una variedad de tipos de documentos diferentes mediante el procesamiento de documentos sincrónico y asincrónico. A continuación, el texto extraído puede guardarse en un archivo o base de datos, o enviarse a otro AWS servicio para su posterior procesamiento.

En este tutorial llevarás a cabo un flujo de trabajo común de principio a fin. Este flujo de trabajo implica:

  • Procesamiento de numerosos documentos de entrada con Amazon Textract

  • Proporcionar el texto extraído a Amazon Comprehend para su análisis

  • Guardar el texto analizado y los datos de análisis en un bucket de Amazon Simple Storage Service (S3)

Para este tutorial, utilizará el AWS SDK de Python. También puedes consultar el GitHub repositorio de ejemplos del SDK de AWS documentación para ver más tutoriales de Python.

Requisitos previos

Antes de empezar este tutorial, tendrás que instalar Python y completar los pasos necesarios para configurar el SDK de Python AWS . Además de esto, asegúrese de que:

Inicio de la detección asincrónica de textos en documentos

Puede extraer el texto de sus documentos y, a continuación, analizar el texto extraído con un servicio como Amazon Comprehend. Textract admite la extracción de texto de documentos de varias páginas mediante operaciones asincrónicas, que son para procesar documentos grandes de varias páginas. El procesamiento asincrónico de un archivo PDF permite a la aplicación completar otras tareas mientras espera a que finalice el proceso. En esta sección se mostrará cómo importar sus documentos desde un bucket de Amazon S3 y proporcionarlos a la operación de detección asincrónica de texto de Textract.

En este tutorial se presupone que utilizará Amazon S3 para almacenar los archivos de los que desea extraer texto. Empezará por crear una clase y funciones que detecten el texto de los documentos de entrada. Su aplicación tendrá que conectarse al cliente Textract, así como a los clientes Amazon SQS y Amazon SNS para supervisar el estado de finalización del trabajo asincrónico.

  1. Comience por escribir el código para crear un tema de Amazon SNS y una cola de Amazon SQS.

    El siguiente ejemplo de código crea una DocumentProcessor clase que se conecta a los tres servicios necesarios y, a continuación, crea una cola de Amazon SQS y un tema de Amazon SNS. El tema de Amazon SNS se utiliza para proporcionar información sobre el estado de finalización del trabajo a una cola de Amazon SQS, que se consultará para obtener el estado de finalización de un trabajo. También hay métodos para eliminar la cola de Amazon SQS y el tema de Amazon SNS una vez que el trabajo se haya completado y los recursos ya no sean necesarios.

    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. Escriba el código para llamar a la StartDocumentTextDetection operación y obtener los resultados de la operación.

    La DocumentProcessor clase también necesitará métodos para:

    • Llame a la StartDocumentTextDetection operación

    • Consulte un Amazon SQS para ver el estado de finalización del trabajo

    • Recupere los resultados del trabajo una vez que haya terminado de procesarse

    El siguiente código crea los GetResults métodos ProcessDocument y que llaman StartDocumentTextDetection y obtienen el texto extraído, respectivamente.

    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. Guarde el código anterior en un archivo llamadodetectFileAsync.py.

    Este archivo se utiliza en la siguiente sección para gestionar la detección de texto en los documentos de entrada.

Procesar sus documentos y enviar el texto a Comprehend

Su aplicación utilizará la clase que creó en la sección siguiente para:

  • leer los documentos de su bucket de Amazon S3

  • extraiga el texto de esos documentos

  • envíe el texto a Amazon Comprehend para su análisis

Empieza por crear algunas funciones que utilizan Amazon Comprehend para analizar el texto detectado en los documentos de entrada. Un tipo común de análisis de texto es el análisis de sentimientos, cuyo objetivo es captar el efecto de una afirmación (ya sea positiva, negativa o neutra). También puede detectar entidades y frases clave en los datos.

El siguiente código recoge el texto detectado e invoca la BatchDetectSentiment operación de Amazon Comprehend para llevar a cabo un análisis de opiniones.

  1. Escribe el código para realizar un análisis de opinión sobre el texto detectado.

    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

    Es posible que también desees realizar otras operaciones de análisis, como la detección de entidades o frases clave, en el texto detectado. Puede escribir las funciones para llevar a cabo estas operaciones de análisis en el texto, tal y como hizo con la operación de análisis de opiniones en curso.

  2. Escribe el código para llevar a cabo la detección de entidades en el texto detectado.

    # 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. Escribe el código para detectar frases clave en el texto detectado.

    # 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

    Debes crear una función que invoque todo el código que has creado hasta ahora. La función utilizará la DocumentProcessor clase que creó en su DetectAnalyzeFileAsync.py archivo y, a continuación, guardará el texto detectado en una variable para introducirlo en las tres funciones que utilizó Amazon Comprehend y que escribió anteriormente. La función también necesitará crear un marco de datos de Pandas, en el que se insertarán el texto y los datos de análisis detectados. Finalmente, el marco de datos de Pandas se guardará como un archivo CSV.

  4. Escribe el código para procesar tus documentos de entrada con Textract y pasa el texto detectado a 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. Escriba el código para procesar sus documentos y cargue los datos resultantes en S3. En el ejemplo de código que aparece a continuación, sustituya el valor de roleArn por el ARN del rol que configuró para usarlo con Amazon Textract. Sustituya el valor de region_name por la región en la que opera su cuenta. Por último, reemplaza el valor bucket_name por el nombre del bucket de S3 que contiene tus documentos.

    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. Coloque el código de procedimiento de la sección en un archivo de Python y ejecútelo.

Ha extraído correctamente el texto con Amazon Textract, lo ha enviado a Amazon Comprehend para su análisis y, a continuación, ha guardado los resultados en un bucket de Amazon S3.