1. 程式人生 > >Django專案實戰: Django + PyPDF2實現PDF頁面提取和PDF檔案輸出

Django專案實戰: Django + PyPDF2實現PDF頁面提取和PDF檔案輸出

在日常工作中我們經常需要從一個大的PDF文件中提取我們所需要的頁面,所以今天我們將教你用Django + PyPDF2開發個小Web應用: 使用者上傳一個PDF文件,輸入需要提取的頁面號碼,點選確定後瀏覽器會自動給使用者返回想提取的PDF頁面。如果你要練習這個專案,你首先要確保已安裝Django 2.X + Python 3.X。如果你還沒有安裝PyPDF2,可以通過pip install PyPDF2安裝好這個第三方包。如果你喜歡我們的原創文章,歡迎關注我們的微信公眾號【Python與Django大咖之路】。

專案開發總體思路

我們的開發思路是這樣子的。我們設計一個表單,讓使用者上傳PDF檔案和輸入提取頁面號碼。伺服器在收到PDF檔案後使用PyPDF2讀取使用者上傳的PDF檔案,提取我們所需要的頁面,然後通過HttpResponse將這個新生成的PDF檔案通過瀏覽器返回給客戶。

因為這個應用很簡單,我們只需要開發一個功能性頁面,也不需要建立什麼模型Models。重點要編寫的是檢視views.py, 用來處理使用者的請求。

第一步 建立專案,設計URL

在CMD終端裡輸入python manage.py startapp pdf建立一個叫pdf的app,然後把這個app加入到你的myproject/settings.pyINSTALLED_APPS去。

#myproject/settings.py


INSTALLED_APPS = [
'django.contrib.admin',
   
'django.contrib.auth',
   
'django.contrib.contenttypes'
,
   
'django.contrib.sessions',
   
'django.contrib.messages',
   
'django.contrib.staticfiles',
   
'pdf',
]

# pdf/urls.py

from django.urls import path
from . import views

# namespace
app_name = 'pdf'

urlpatterns = [
   # 上傳pdf,使用者輸入需要提取的頁面, 返回需要提取的頁面
   
path('extract/', views.pdf_extract, name='pdf_extract'),
]

同時我們應將上述urls加入到myproject/urls.py裡去。這樣當用戶通過瀏覽器訪問/pdf/extract/時,伺服器就會呼叫我們views裡的pdf_extract方法來處理使用者的請求。

from django.contrib import admin
from django.urls import path, include


# 對於處理靜態檔案如圖片,CSS和文字非常重要
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
   path('admin/', admin.site.urls),
   
path('pdf/', include('pdf.urls')),

] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

第二步 設計表單forms.py

因為我們在檢視view裡需要使用到上傳檔案的表單,所以我們這裡先設計表單。這個表單非常簡單,只有2個欄位。如下所示。

# pdf/forms.py

from django import forms


class PdfUploadForm(forms.Form):
   file = forms.FileField(label="上傳PDF檔案")
   page = forms.IntegerField(min_value=1, label="輸入抓取頁碼")

第三步 編寫檢視views.py

檢視view是本專案中最重要的部分。其總體思路,我已經在程式碼中加了很多註釋幫你理解。PyPDF2功能強大,可以提取PDF檔案裡的文字,也可以抓取PDF檔案中的某個頁面,還可以建立新的PDF檔案, 比Django文件裡提到的reportlab要好很多。

# pdf/views.py

from django.shortcuts import render
from django.http import HttpResponse
from .forms import PdfUploadForm
import PyPDF2


# Create your views here.
def pdf_extract(request):
   if request.method == 'POST':
       # 如果使用者通過POST提交
       
form = PdfUploadForm(request.POST, request.FILES)
       if form.is_valid():
           # 如表單通過驗證,獲取提取檔案頁碼
           
page_num = int(request.POST.get("page"))
           # pdf文件頁碼物件編碼是從0開始,所以減1
           
page_index = page_num - 1
           
# 獲取上傳的檔案物件
           
f = request.FILES['file']
           
           # 開啟上傳的檔案,寫入新PDF檔案
           
with open('original.pdf', 'wb+') as pdfFileObj:
               for chunk in f.chunks():
                   pdfFileObj.write(chunk)
               # 利用PyPDF2讀取新的PDF檔案
               
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)
               # 利用PyPDF2提取頁碼物件
               
pageObj = pdfReader.getPage(page_index)
               # 利用PyPDF2建立新的PDF檔案物件
               
pdfWriter = PyPDF2.PdfFileWriter()
               # 新增已讀取的頁面物件
               
pdfWriter.addPage(pageObj)
               # 將提取頁面寫入新的PDF檔案
               
with open('extracted_pages.pdf', 'wb') as pdfOutputFile:
                   pdfWriter.write(pdfOutputFile)
               # 開啟新的PDF檔案,通過HttpResponse輸出
               
with open('extracted_pages.pdf', 'rb') as pdfExtract:
                   response = HttpResponse(pdfExtract.read(), content_type='application/pdf')
                   response['Content-Disposition'] = 'attachment; filename="extracted_page_{}.pdf"'.format(page_num)
                   return response


else:
       # 如果使用者沒有通過POST,提交生成空表單
       
form = PdfUploadForm()
       return render(request, 'pdf/pdf_upload.html', {'form': form})

上述程式碼中最值得需要你注意的地方是我們如何通過HttpReponse將生成的pdf文件返回給使用者的。下行程式碼是最重要的,它不僅讀取了開啟的pdf檔案的內容,還指定了返回內容型別是pdf檔案, 否則會出現亂碼。

  • response = HttpResponse(pdfExtract.read(), content_type='application/pdf')

第四步 編寫模板template

模板檔案非常簡單,如下所示。我們在pdf資料夾裡建立了一個templates資料夾,又在裡面建立了一個新的pdf資料夾,然後把模板檔案放裡面了。至於為什麼我們這麼佈局,請閱讀Django專案推薦性的檔案與資料夾佈局

# pdf/templates/pdf/pdf_upload.html

{% block content %}
<h3>上傳pdf檔案, 輸入頁面號碼提取頁面</h3>
<form
method="post" enctype="multipart/form-data" action="">{% csrf_token %}
   {{ form.as_p }}
   <input type="submit" value="確定" />
</form>
{% endblock %}

第五步 檢視效果

現在你在CMD終端裡輸入python manage.py runserver。在瀏覽器中開啟http://127.0.0.1:8000/pdf/extract/你就可以看到如下效果了。

第六步 想想需要改進的地方

整個專案離實際應用還有許多需要改進的地方,比如:

  • 使用者輸入的頁碼超過了PDF檔案總頁數怎麼辦?

  • 如果使用者上傳的不是PDF檔案怎麼處理?

  • 如果使用者想一次提取多個檔案怎麼辦?比如1, 3, 5, 7...

這些問題就留給讀者你思考吧,如果有問題,也歡迎給我們留言。