部署内部调用runApp()的Shiny应用(tabulizer包场景)问题咨询
问题解决方案:Shiny线上部署时tabulizer的locate_areas无响应问题
根因说明
locate_areas()是面向本地交互场景设计的函数,运行时会在服务端本地启动一个独立的Shiny小应用。本地调试时用户与服务端为同一设备,可以直接看到弹出的交互界面;部署到线上后,该独立应用仅运行在远端服务器内部,用户浏览器无法接收到对应的交互页面,因此点击后无响应。
可行规避方案
替换locate_areas()的交互逻辑,将选区功能直接集成到你自己的Shiny应用前端,不需要调用额外的内嵌Shiny应用,具体实现逻辑如下:
- 用户上传PDF、指定页码后,后端先将目标PDF页渲染为图片传回前端显示
- 用Shiny原生的框选交互能力获取用户选中的区域坐标
- 坐标单位转换后直接传入
extract_tables()函数提取表格
修改后可直接部署的代码
library(shiny) library(tabulizer) library(pdftools) library(png) ui <- fluidPage( fileInput("report", NULL, buttonLabel = "Upload report"), numericInput("page", "Specify page number", value = 1, min = 1), actionButton("load_page", "Load PDF page"), # 用于展示PDF转成的图片并支持框选 plotOutput("pdf_preview", brush = brushOpts(id = "pdf_brush", resetOnNew = TRUE)), actionButton("extract", "Extract table from selected area"), verbatimTextOutput("data") ) server <- function(input, output, session) { # 存储PDF页面的原生尺寸信息 用于坐标转换 page_dims <- reactiveVal() # 存储PDF页转成的预览图片 page_img <- reactiveVal() # 加载指定PDF页并转成图片 observeEvent(input$load_page, { req(input$report) # 渲染PDF页为图片 dpi可根据精度需求调整 img_raw <- pdf_render_page(input$report$datapath, page = input$page, dpi = 150) img <- png::readPNG(img_raw) page_img(img) # 获取PDF原生尺寸(单位:点) dims <- get_page_dims(input$report$datapath, pages = input$page) page_dims(list(width = dims[1], height = dims[2])) }) # 渲染PDF预览图 output$pdf_preview <- renderPlot({ req(page_img()) par(mar = rep(0,4)) plot(0,0,type="n",xlim=c(0,ncol(page_img())),ylim=c(nrow(page_img()),0),axes=F,xlab="",ylab="") rasterImage(page_img(),0,0,ncol(page_img()),nrow(page_img())) }) # 提取表格逻辑 generate_data <- reactive({ req(input$pdf_brush, page_dims(), input$report) # 把前端框选的像素坐标转换为tabulizer需要的PDF点坐标 格式为c(top, left, bottom, right) img_w <- ncol(page_img()) img_h <- nrow(page_img()) scale_x <- page_dims()$width / img_w scale_y <- page_dims()$height / img_h area <- c( input$pdf_brush$ymin * scale_y, input$pdf_brush$xmin * scale_x, input$pdf_brush$ymax * scale_y, input$pdf_brush$xmax * scale_x ) table <- extract_tables( file = input$report$datapath, pages = input$page, area = list(area) ) return(table) }) %>% bindCache(input$page, input$pdf_brush) %>% bindEvent(input$extract) output$data <- renderPrint({ generate_data() }) } shinyApp(ui = ui, server = server)
部署注意事项
- 线上服务器需要提前安装Java运行环境以及tabulizer依赖的系统库
- 如果需要更高精度的框选,可以调高
pdf_render_page的dpi参数
内容的提问来源于stack exchange,提问作者Chris Oosthuizen
相关产品推荐
相关产品推荐

