Selenium + ChromeDriver 打印成 PDF

11
有没有办法从python + selenium调用chromedriver的Page.printToPDF()方法?PhantomJS有一个类似的render()方法,可以直接保存为pdf,但只能在phantomjs的特权客户端REPL中使用。 这个SO答案展示了如何修补正在运行的selenium驱动程序以调用它,使用自定义的phantomjs webdriver命令(/session/$sessionId/phantom/execute)来调用this.render()
是否有类似于phantomjs的execute命令的东西,允许调用devtools方法;或者通过自定义驱动程序命令直接调用printToPDF的方法?
(注意:我正在尝试呈现POST的结果是HTML,因此无法使用wkhtmltopdf等备选解决方案。我可以退回到使用selenium的屏幕截图->png,但这对于存储目的来说是繁琐的)。
2个回答

11
调用 DevTool API 中的 Page.printToPDF 可以实现。但是该命令是实验性的,不适用于所有平台:
from selenium import webdriver
import json, base64

def send_devtools(driver, cmd, params={}):
  resource = "/session/%s/chromium/send_command_and_get_result" % driver.session_id
  url = driver.command_executor._url + resource
  body = json.dumps({'cmd': cmd, 'params': params})
  response = driver.command_executor._request('POST', url, body)
  if response['status']:
    raise Exception(response.get('value'))
  return response.get('value')

def save_as_pdf(driver, path, options={}):    
  # https://timvdlippe.github.io/devtools-protocol/tot/Page#method-printToPDF
  result = send_devtools(driver, "Page.printToPDF", options)
  with open(path, 'wb') as file:
    file.write(base64.b64decode(result['data']))


options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--disable-gpu")

driver = webdriver.Chrome(chrome_options=options)
driver.get("https://www.google.co.uk/")

save_as_pdf(driver, r'page.pdf', { 'landscape': False })

谢谢,这正是我在寻找的!但是我收到了一个“PrintToPDF未实现”的错误。我需要做些什么才能启用实验性功能吗?(Selenium报告它正在连接到Chrome 62.0.3202.62,ChromeDriver 2.32,平台=Linux)。从我所知道的情况来看,那个版本应该(?)支持printToPDF。 - Eli Collins
请尝试使用金丝雀版本或最新版本的woolyss(64.0.3249.0)。 - Florent B.
3
找到了。根据 puppeteer 的 printToPDF 文档,这个功能目前只在无头模式下可用。一旦开启了无头模式,一切都能完美运行。 - Eli Collins

4

好的,仅供参考,以下是我在2019年解决问题时的方法,没有产生异常:

def send_devtools(driver, cmd, params={}):
    resource = "/session/%s/chromium/send_command_and_get_result" % driver.session_id
    url = driver.command_executor._url + resource
    body = json.dumps({'cmd': cmd, 'params': params})
    response = driver.command_executor._request('POST', url, body)
    #print (response)
    if (response.get('value') is not None):
        return response.get('value')
    else:
        return None

def save_as_pdf(driver, path, options={}):
    # https://timvdlippe.github.io/devtools-protocol/tot/Page#method-printToPDF
    result = send_devtools(driver, "Page.printToPDF", options)
    if (result is not None):
        with open(path, 'wb') as file:
            file.write(base64.b64decode(result['data']))
        return True
    else:
        return False

欢迎来到SO!请编辑您的答案并解释一下上下文,以及为什么它可以工作。如需更多指导,请参阅https://stackoverflow.com/help/how-to-answer。 - B--rian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接