如何在Django应用中用Python检测PDF中的选中文本?
在Django应用中捕获PDF查看器内的选中文本
问题分析
你原有的本地脚本通过xdotool模拟Ctrl+C、pyperclip读取剪贴板能获取PDF选中文本,但集成到Django后完全失效,核心原因有两个:
- 服务器/客户端隔离:Django运行在服务器进程中,
xdotool和pyperclip操作的是服务器的桌面环境与剪贴板,和用户浏览器端的PDF查看器完全无关。 - 视图逻辑错误:Django视图必须在单次请求中返回响应,你写的
while True会阻塞请求,永远无法正常返回页面。
要实现捕获用户在PDF中主动选中的文本,必须从**客户端(浏览器)**入手,通过前端JavaScript获取选中文本后再发送到后端。
解决方案:用PDF.js实现前端文本捕获
原生<embed>标签无法获取PDF内的选中内容,推荐使用PDF.js(Mozilla开源的PDF渲染库)来渲染PDF,它允许通过JavaScript监听并获取用户选中的文本,再通过AJAX发送到Django后端。
1. 修改前端模板(viewer.html)
替换原生<embed>为PDF.js渲染容器,添加选中文本监听与AJAX发送逻辑:
{% load static %} <!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> <!-- 引入PDF.js核心库 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script> <style> #pdf-container { width: 100%; height: 600px; border: 1px solid #eee; } #selected-text-result { margin-top: 10px; padding: 8px; background: #f5f5f5; } </style> </head> <body> <div id="pdf-container"></div> <button id="readButton" style="margin-top:10px;">读取选中内容</button> <div id="selected-text-result"></div> <script> // 配置PDF.js工作线程 const pdfjsLib = window['pdfjs-dist/build/pdf']; pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js'; let pdfDoc = null; const container = document.getElementById('pdf-container'); // 渲染PDF页面 function renderPage(pageNum) { pdfDoc.getPage(pageNum).then(page => { const viewport = page.getViewport({ scale: 1.5 }); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.height = viewport.height; canvas.width = viewport.width; container.appendChild(canvas); // 渲染PDF到画布 page.render({ canvasContext: ctx, viewport }).promise.then(() => { // 监听画布上的鼠标松开事件,获取选中文本 canvas.addEventListener('mouseup', () => { const selection = window.getSelection(); if (selection.toString().trim()) { console.log('当前选中:', selection.toString()); } }); }); }); } // 加载PDF文件 pdfjsLib.getDocument('{% static "class3english.pdf" %}').promise.then(pdf => { pdfDoc = pdf; // 渲染第一页,如需多页可循环调用renderPage renderPage(1); }); // 点击按钮发送选中文本到后端 $(document).ready(() => { $('#readButton').click(() => { const selectedText = window.getSelection().toString().trim(); if (!selectedText) { alert('请先选中PDF中的文本'); return; } $.ajax({ url: '{% url "detectingWordSentences" %}', type: 'POST', data: { 'selected_text': selectedText, 'csrfmiddlewaretoken': '{{ csrf_token }}' }, success: response => { $('#selected-text-result').text('后端已接收选中文本: ' + response.received_text); }, error: (xhr, status, err) => { console.error('请求失败:', err); } }); }); }); </script> </body> </html>
2. 修改Django视图(views.py)
移除错误的循环逻辑,处理前端发送的POST请求:
from django.shortcuts import render from django.http import JsonResponse def get_selected_text_view(request): if request.method == 'POST': # 获取前端发送的选中文本 selected_text = request.POST.get('selected_text', '').strip() if selected_text: print("收到选中文本:", selected_text) # 返回响应给前端 return JsonResponse({'received_text': selected_text}) else: return JsonResponse({'error': '未提供有效选中文本'}, status=400) # GET请求返回PDF查看页面 return render(request, 'grad_school/viewer.html')
3. 配置URL路由
确保你的urls.py中添加对应的路由:
from django.urls import path from . import views urlpatterns = [ path('pdf-viewer/', views.get_selected_text_view, name='detectingWordSentences'), # 其他路由... ]
关键说明
- 所有选中文本的操作都在用户浏览器端完成,避免了服务器与客户端环境隔离的问题。
- PDF.js提供了完整的PDF渲染与交互API,支持多页渲染、文本选中、搜索等功能,比原生
<embed>更可控。 - Django视图遵循请求-响应模式,不再有阻塞性的循环逻辑,符合Web应用的运行机制。
内容的提问来源于stack exchange,提问作者kishan Kumar
相关产品推荐
相关产品推荐

