python之批量打印網頁爲pdf文件

  最近實際工作中,小爬遇到這樣一個需求,小爬需要將多個流程申請表單網頁另存爲PDF文件,我們如何利用python將這個過程自動化呢?

  假定我們通過爬蟲已經拿到了這些表單的URL,且這些流程表單需要登陸後才能打開。那像那些將HTML直接轉pdf的庫,如pdfkit、wkhtmltopdf就不能很好地發揮作用了。

  比較直接的方法是使用selenium庫:pip install selenium即可快速安裝它。利用它的driver.get(URL)方法請求網站的登錄頁,利用time.sleep(seconds)方法等待用戶輸入用戶名密碼正常進入網站,之後的每個driver.get請求,就自動屬於登陸狀態了。這裏小爬傾向於使用chrome瀏覽器+chromedriver.exe配合selenium完成頁面的自動化打印。

  等網頁渲染好後,我們該如何打印呢?

  小爬之前嘗試的一種方法是,利用windows10 自帶的Microsoft Print To PDF虛擬打印機。藉助pywin32庫中win32print方法來操作.

比如自動設置系統當前默認打印機:

win32print.SetDefaultPrinter(device_name) # 設置默認打印機

  再比如,我們可以獲取當前打印機:

currentPrinter=win32print.GetDefaultPrinterW()

  藉助這兩個api,我們就可以後臺悄無聲息地更改默認打印機爲Microsoft Print To PDF來打印網頁爲pdf,用完後再悄悄還原默認打印機爲用戶一開始設定的常用打印機。

  之後就是在網頁加載好之後,調用系統的打印界面,即Ctrl+Shift+P。我們需要藉助win32api.keybd_event(vk_code[keyname],0,0,0) 來完成模擬,之後等待系統打印窗口彈出後,再借助win32api的findWindow、sendmessage方法來捕獲窗口以及完成窗口元素的點擊和編輯。由於之前的博文中已經有提及此方法,再此不再贅述。該方法的主要缺陷在於:

  1. win32api.keybd_event不穩定,當我們的窗口焦點丟失時,我們的模擬熱鍵可能會失敗;
  2. findWindow、sendmessage方法有時也會失敗。

  爲了提高程序的穩定性,我們可能不得不使用try except結合while循環來配合使用,多次調用這些window api,直至成功。也正是因爲這些,小爬最終決定使用chrome中原生的打印方法,然後調用chrome的“另存爲PDF”功能來完成 html 轉PDF。

  那麼python+selenium這條線如何來自動調用chrome的這套方法呢?

 

 

   上圖中標示的這些參數,如何通過selenium傳導給瀏覽器,告訴瀏覽器我們的打印具體配置參數需求?小爬已經提前幫大家踩坑了,示例代碼如下:

import os,json,time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

chrome_options = webdriver.ChromeOptions()

settings = {
    "recentDestinations": [{
        "id": "Save as PDF",
        "origin": "local",
        "account": ""
    }],
    "selectedDestinationId": "Save as PDF",
    "version": 2,
    "isHeaderFooterEnabled": False,

    # "customMargins": {},
    # "marginsType": 2,
    # "scaling": 100,
    # "scalingType": 3,
    # "scalingTypePdf": 3,
    "isLandscapeEnabled":True,#landscape橫向,portrait 縱向,若不設置該參數,默認縱向
    "isCssBackgroundEnabled": True,
    "mediaSize": {
        "height_microns": 297000,
        "name": "ISO_A4",
        "width_microns": 210000,
        "custom_display_name": "A4 210 x 297 mm"
    },
}

chrome_options.add_argument('--enable-print-browser')
#chrome_options.add_argument('--headless') #headless模式下,瀏覽器窗口不可見,可提高效率

prefs = {
    'printing.print_preview_sticky_settings.appState': json.dumps(settings),
    'savefile.default_directory': 'your file path' #此處填寫你希望文件保存的路徑
}
chrome_options.add_argument('--kiosk-printing') #靜默打印,無需用戶點擊打印頁面的確定按鈕
chrome_options.add_experimental_option('prefs', prefs)


driver = webdriver.Chrome("./chromedriver", options=chrome_options)
driver.get('your URL')
driver.maximize_window()
# time.sleep(7)
driver.execute_script('document.title="my_test_file1.pdf";window.print();') #利用js修改網頁的title,該title最終就是PDF文件名,利用js的window.print可以快速調出瀏覽器打印窗口,避免使用熱鍵ctrl+P
driver.close()

  代碼中的setting部分詳細註明了,如何設置打印窗口的縮放、邊距、紙張類型、打印機名、頁面佈局(橫向、縱向)等信息,供各位參考。

該方法有如下優勢:

  1. chrome原生的打印網頁爲pdf功能,支持較好;
  2. 配置參數靈活,個性化打印;
  3. 穩定,幾乎不會出錯,也不需要加sleep來提升程序的穩定性;
  4. 效率更高。

  有相同需求的你,還不趕快試試?

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章