Как обнаружить выделенный текст из PDF с помощью Python в приложении Django?

У меня есть скрипт на Python, который успешно обнаруживает выделенный текст из PDF-файла с помощью библиотек xdotool и pyperclip. Вот сценарий:

import time
import os
import subprocess
import pyperclip  

def get_selected_text():
    subprocess.run(['xdotool', 'key', 'ctrl+c'])  
    time.sleep(1)  
    return pyperclip.paste()

if __name__ == "__main__":
    pdf_filepath = 'class3english.pdf'
    subprocess.Popen(['xdg-open', pdf_filepath])

    while True:
        selected_text = get_selected_text()
        if selected_text:
            print("Selected text:", selected_text)
        time.sleep(2)

Однако, когда я пытаюсь интегрировать этот скрипт в свое приложение Django, он не обнаруживает выделенный текст из PDF. Вместо этого он захватывает текст из буфера обмена. Я хочу иметь возможность обнаруживать текст, который пользователь активно выделил в программе просмотра PDF.

Есть ли способ добиться этого в приложении Django? Как я могу изменить свой подход, чтобы захватить только выделенный текст из PDF при работе в среде Django?

Лучший вариант, который я нашел, это:

  1. Извлеките текст из PDF-файла и отобразите его в файле шаблона, возможно, немного стилизовав. В моем примере кода я использую пакет pypdf.
  2. Копирование выделенного текста с помощью JavaScript. (Подробное описание см. в этом ответе.)

Вот как выглядел бы этот подход:

from pypdf import PdfReader

# Use `get_selected_text` as it is.

def get_selected_text_view(request):
    # Read the PDF file
    reader = PdfReader("path-to-your-file.pdf")
    document_pages = reader.pages
    extracted_text = []

    # Loop over all the pages and append the extracted text to the
    # `extracted_text` list.
    for single_page in document_pages:
        text = single_page.extract_text(extraction_mode="layout")
        extracted_text.append(text)
        
    while True:
        selected_text = get_selected_text()
        if selected_text:
            print("Selected text:", selected_text)
            time.sleep(2)
            # Pass the extracted text as context data
            return render(request, 'pyperclip.html', {"pdf_text": extracted_text})
        else:
            print("\nselected_text = ","NONE")
            time.sleep(2)
            return render(request, 'pyperclip.html', {"pdf_text": extracted_text})

Обновите свой шаблон:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>PDF Viewer</title>
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    </head>
    <body>
        <!-- Display all text extracted from the PDF -->
        <div style="width: 100%; height: 600px;">
            {% for page in pdf_text %}
                <!-- To try and render the text as it may have been laid out in the PDF,
                we use the pre tag. -->
                <pre>
                    {{ page }}
                </pre>
            {% endfor %}
        </div>
        <button id="readButton">Read</button>

        <script>
            $(document).ready(function() {
                $('#readButton').click(function() {
                    // Get the selected text.
                    let selectedText = document.getSelection().toString();
                    navigator.clipboard.writeText(selectedText);
                    $.ajax({
                        url: '{% url 'detectingWordSentences' %}', 
                        type: 'GET',
                        success: function(response) {
                        //    console.log(response);
                        },
                        error: function(xhr, status, error) {
                            // console.error(error);
                        }
                    });
                });
            });
        </script>
    </body>
</html>

Сначала извлекается текст PDF, а затем отображается, поскольку текст, выделенный во встроенном PDF (через элементы embed или iframe), не распознается функцией getSelection().

Кроме того, из-за различий в движках рендеринга, используемых разными браузерами, может оказаться невозможным надежно выделить текст. (См. этот пост.)

Другой подход, который вы можете выбрать, - это использование пакета PDF.js. По результатам моего (ограниченного) тестирования, не удается отобразить PDF как встроенный файл, даже если следовать примеру, включенному в документацию; в результате в браузере отображается картинка.
Однако, используя демо-сайт, можно получить выделенный текст в консоли с помощью getSelection(), так что, возможно, я что-то упускаю.

Вернуться на верх