江湖小白之进阶篇 (五)实现PDF实时在线预览功能

13 篇文章 2 订阅
6 篇文章 1 订阅

      最近在抖音上看到一个卖孟婆汤的,居然卖得如火如荼,恭喜你成了那条街上最靓的女,这孟婆汤是啥味?看来地摊经济还是需要卖好的创意,不知道能火多久(羡慕嫉妒中……),哎,自己没啥好创意,做不了街上最靓的仔,那就争取做最靓的猿吧!

     接着上篇来讲,上篇我们实现了对PDF的图片提取,那这篇我们就使用websocket来实现提取的进度的实时展示吧,那如何实现websocket的服务呢,在Sanic框架中自带的方法,来,小二上代码:

@app.websocket('/feed')
async def feed(request, ws):
    while True:
        data = 'hello!'
        print('Sending: ' + data)
        await ws.send(data)
        data = await ws.recv()
        print('Received: ' + data)

这是官方给出的例子,非常简单,在前端可以利用html5的websocket配合使用,具体的实现大家可以自己操作下。

在我们创建的网站里我们只要实现的逻辑就是提取成功一页PDF就将提取的文件路径发送给前端,前端接收到信息就及时展示出来,在这个过程中我遇到了一个问题,就是我执行逻辑方法的时候是在这个服务的外部,我怎么在外部使用ws.send的方法来发送信息呢?我的想法就是在请求websocket服务的时候同时传递一个用户的链接的唯一标识,保存到全局,当任务执行结束后,自动删除此用户标识以释放资源,来,首先我们定义个全局变量:

app.ws = {}

websocket服务代码:

#PDF执行进度websocket
@app.websocket('/extract/<id>')
async def extract(request, ws, id):
    app.ws[id] = ws
    while True:
        result=await ws.recv()
        print("result",result)

你也可以这样写:

async def extract(request, ws, id):
    app.ws[id] = ws
    while True:
        result=await ws.recv()
        print("result",result)

app.add_websocket_route(extract, '/extract/<id>')

为了上下文请求写法的格式统一,我还是用第一种方式,接着我们来实现上传文件及提取PDF的方法:

#上传文件接口
@app.route('/upload',methods=["POST"])
async def upload(request):
    args = request.args if request.method == 'GET' else request.form
    uid = args.get('uid', 0)
    file = request.files.get('file')
    #放入后台执行
    app.add_task(extract_pdf(uid,file.body))
    msg={"code":200,"msg":"开始执行提取PDF"}
    return json(msg)

#执行方法
async def extract_pdf(id,stream):
    #定义Pdf类
    p = Pdf()
    doc = fitz.open('type',stream)
    for i in range(doc.pageCount):
        #await asyncio.sleep(0.1)
        filename=await asyncio.ensure_future(p.pdf2pic(doc,i))
        await app.ws[id].send(filename)
    doc.close()
    #执行完毕删除掉webscoket
    del app.ws[id]
    print("已成功删除了websocket:",id)

在异步框架中记得在方法前加上async,在执行方法中使用了asyncio.ensure_future就是将PDF的处理方法放到想协程里执行,这样就不会阻塞主线程,处理PDF的过程上篇的PDF的方法要稍做调整,因为这里要异步调用,而且我们直接将文件流传递到PDF提取的方法中,我们这样修改下:

 async def pdf2pic(self,doc,pageCount):

将这2行去掉:

#加载读取pdf文件
doc = fitz.open(filename)
#循环提取pdf页面
for i in range(doc.pageCount):

前端页面的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/app.css">
</head>
<body>
    <div class="btn_upload">
        <input type="file" name="file" id="file_1" class="inputfile">
         <label for="file_1"  data-id="{{msg.uid}}" class="m_start">本地上传</label>
    </div>

    <div class="m_con">
        <div class="m_pics">
            <ul class="m_pic_ul"></ul>
        </div>
    </div>
    <script src="/static/js/jquery.min.js"></script>
    <script>
        (function(){
            //上传图片
            $("#file_1").on("change", function() {
                //清空之前的文件
                $(".m_pic_ul").html("");
                if ("WebSocket" in window)
                {
                   // 打开一个 web socket
                   var ws = new WebSocket("ws://127.0.0.1:5000/extract/{{msg.uid}}");
                   ws.onopen = function()
                   {
                        var files = $("#file_1").get(0).files[0];
                        var uid = $(".m_start").data("id");
                        var data = new FormData();
                        data.append('file', files);
                        data.append('uid', uid);
                        $.ajax({
                            url: '/upload',
                            type: "POST",
                            processData: false,
                            contentType: false,
                            data: data,
                            success: function (data) {
                                if (data.code == 200) {
                                    console.log(data.msg);
                                }
                            }
                        })
                   };
                   ws.onmessage = function (evt)
                   {
                      var received_msg = evt.data;
                      var html='<li><img src="/files/'+received_msg+'"></li>';
                      $(".m_pic_ul").append(html);
                      console.log("数据已接收..." + received_msg);
                   };
                   ws.onclose = function()
                   {
                      // 关闭 websocket
                      console.log("连接已关闭...");
                   };
                }
                else
                {
                   // 浏览器不支持 WebSocket
                   alert("您的浏览器不支持 WebSocket!");
                }
            });

        })()
    </script>
</body>
</html>

细心的同学可以看到这里面有个msg.uid,这就是为了做唯一标识在请求首页的时候就返回的一个标识码:

#首页
@app.route('/')
async def index(request):
    msg={"name":"李大厨","sex":"男","uid":uuid.uuid4()}
    return jinja.render('index.html',request, msg=msg)

这里使用了uuid来生成,嗯,跟好节奏,来我们运行看一下结果:

这样我们就实现了在线PDF的图片提取部分,通过上面你的例子其实有很多发散的思考,比如我们还是做个进度条来展示实时进度什么的,还可以显示文件总数,正在处理,已处理个数等等,有兴趣的大家可以研究下。

好了,实现在线PDF的提取及压缩的提取部分就到这里了。

如果有需要的源代码的同学,请关注公众号回复:pdf

江湖故人,相逢何必曾相识!咱们下篇见!

关注公众号,超越平凡才能成就自我

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值