使用PyPDF2嵌入JS到PDF时遇'_VirtualList'不可调用错误求助
问题
我尝试编写Python代码将JavaScript嵌入PDF文件,该JavaScript需实现以下功能:
- 检查ID为"mac-address"的span是否存在。
- 若不存在,创建一个ID为"mac-address"的隐藏span,并填入打开PDF的设备MAC地址。
- 若存在,检查其值是否与打开PDF的设备MAC地址匹配。
- 匹配则显示提示弹窗。
- 不匹配则显示提示弹窗并删除PDF文件。
以下是我的代码:
import os import subprocess import PyPDF2 import uuid # Get MAC address of device mac_address = hex(uuid.getnode()) # Create JavaScript to be embedded in PDF js_code = """ var mac_address_span = this.getField("mac-address"); if (mac_address_span == null) { var new_span = this.addField("mac-address", "text", 0, [0, 0, 0, 0]); new_span.value = "%s"; new_span.display = display.hidden; app.alert("MAC address span created with value: " + new_span.value); } else { if (mac_address_span.value == "%s") { app.alert("MAC address span exists with matching value: " + mac_address_span.value); } else { app.alert("MAC address span exists with non-matching value: " + mac_address_span.value); this.closeDoc(true); } } """ % (mac_address, mac_address) # Open PDF with open("example.pdf", mode="rb") as f: pdf_reader = PyPDF2.PdfReader(f) pdf_writer = PyPDF2.PdfWriter() # Embed JavaScript pdf_catalog = pdf_reader.trailer["/Root"] #pdf_catalog = pdf_reader.catalog pdf_catalog_js = pdf_catalog.get_object() pdf_catalog_js.update({ PyPDF2.generic.NameObject('/Names'): PyPDF2.generic.DictionaryObject({ PyPDF2.generic.NameObject('/JavaScript'): PyPDF2.generic.DictionaryObject({ PyPDF2.generic.NameObject('/Names'): PyPDF2.generic.ArrayObject([ PyPDF2.generic.TextStringObject('mac-address'), PyPDF2.generic.IndirectObject(len(pdf_writer._objects)+1, 0, pdf_writer) ]) }) }) }) # Add JavaScript action to document open event js_name = 'mac-address.js' js_action = pdf_writer.add_js(js_code) if js_action: pdf_writer._add_object(js_action) else: print("Failed to create JavaScript action object") pdf_open_action = PyPDF2.generic.DictionaryObject({ PyPDF2.generic.NameObject('/S'): PyPDF2.generic.NameObject('/JavaScript'), PyPDF2.generic.NameObject('/JS'): PyPDF2.generic.NameObject(js_name) }) pdf_catalog_js.update({ PyPDF2.generic.NameObject('/OpenAction'): pdf_open_action }) pdf_catalog_js.update({ PyPDF2.generic.NameObject('/OpenAction'): pdf_open_action }) # Add all pages to output PDF for page in range(pdf_reader.pages()): pdf_writer.addPage(pdf_reader.getPage(page)) # Save output PDF with open("output.pdf", mode="wb") as output_file: pdf_writer.write(output_file) # Open output PDF if os.name == 'nt': # for Windows OS os.startfile("output.pdf") else: # for Mac OS subprocess.call(["open", "output.pdf"])
运行时遇到以下错误:
for page in range(pdf_reader.pages()): TypeError: '_VirtualList' object is not callable
解决方案
错误原因
在PyPDF2的新版本中,pdf_reader.pages是一个属性而非方法,不需要加括号调用。写成pdf_reader.pages()会把它当成方法执行,直接触发类型错误。此外还有两处API调用的版本兼容问题需要修正:
- 添加页面的方法在新版本中是
add_page()而非旧版的addPage() - 获取单页的方式改为直接通过
pdf_reader.pages[索引]访问,而非getPage()方法
修正后的完整代码
import os import subprocess import PyPDF2 import uuid # 获取设备MAC地址 mac_address = hex(uuid.getnode()) # 编写要嵌入PDF的JavaScript代码 js_code = """ var mac_address_span = this.getField("mac-address"); if (mac_address_span == null) { var new_span = this.addField("mac-address", "text", 0, [0, 0, 0, 0]); new_span.value = "%s"; new_span.display = display.hidden; app.alert("MAC地址已写入隐藏字段: " + new_span.value); } else { if (mac_address_span.value == "%s") { app.alert("MAC地址匹配,验证通过"); } else { app.alert("MAC地址不匹配,文件将被关闭"); this.closeDoc(true); } } """ % (mac_address, mac_address) # 打开源PDF文件 with open("example.pdf", mode="rb") as f: pdf_reader = PyPDF2.PdfReader(f) pdf_writer = PyPDF2.PdfWriter() # 嵌入JavaScript到PDF目录 pdf_catalog = pdf_reader.trailer["/Root"] pdf_catalog_js = pdf_catalog.get_object() pdf_catalog_js.update({ PyPDF2.generic.NameObject('/Names'): PyPDF2.generic.DictionaryObject({ PyPDF2.generic.NameObject('/JavaScript'): PyPDF2.generic.DictionaryObject({ PyPDF2.generic.NameObject('/Names'): PyPDF2.generic.ArrayObject([ PyPDF2.generic.TextStringObject('mac-address'), PyPDF2.generic.IndirectObject(len(pdf_writer._objects)+1, 0, pdf_writer) ]) }) }) }) # 添加JavaScript到文档打开事件 js_name = 'mac-address.js' js_action = pdf_writer.add_js(js_code) if js_action: pdf_writer._add_object(js_action) else: print("创建JavaScript动作对象失败") pdf_open_action = PyPDF2.generic.DictionaryObject({ PyPDF2.generic.NameObject('/S'): PyPDF2.generic.NameObject('/JavaScript'), PyPDF2.generic.NameObject('/JS'): PyPDF2.generic.NameObject(js_name) }) pdf_catalog_js.update({ PyPDF2.generic.NameObject('/OpenAction'): pdf_open_action }) # 将所有页面添加到输出PDF for page in pdf_reader.pages: pdf_writer.add_page(page) # 保存输出PDF with open("output.pdf", mode="wb") as output_file: pdf_writer.write(output_file) # 打开生成的PDF if os.name == 'nt': # Windows系统 os.startfile("output.pdf") else: # macOS系统 subprocess.call(["open", "output.pdf"])
内容的提问来源于stack exchange,提问作者the_nathan_x
相关产品推荐
相关产品推荐

