Using Selenium and ChromeDriver, automatically scale the size of the page on print
Question:
I’m writing a script to automatically print a set of web pages in Chrome. If I were to print them manually, I’d choose "Custom" from the Scale drop down and enter 50 into the input field below.
I can’t figure out what arguments to pass in to replicate this setting when I automatically print these pages in bulk using Selenium with ChromeDriver.
appState = { "recentDestinations": [{
"id": "Save as PDF",
"origin": "local",
"account": "",
"printing.scaling": 'Custom', # <== Does it go here?
}],
"selectedDestinationId": "Save as PDF",
"version": 2,
"printing.scaling": 'Custom', # <== Or here?
}
profile = { 'printing.print_preview_sticky_settings.appState': json.dumps(appState),
'printing.print_header_footer': False,
# So many different versions of things I have tried :-(
'printing.scaling': 'Custom',
'printing.scaling_type': 'Custom',
'print_preview.scaling': 'Custom',
'print_preview.scaling_type': 'Custom',
'printing.custom_scaling': True,
'printing.fit_to_page_scaling': 50,
'printing.page_scaling': True,
}
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option('prefs', profile)
br = webdriver.Chrome(options=chrome_options)
All of the different options shown above were guesses after reading through a lot of the Chromium source trying to get a hint.
https://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/pref_names.cc?view=markup
https://chromium.googlesource.com/chromium/src/+/master/printing/print_job_constants.cc
https://chromium.googlesource.com/chromium/src/+/master/printing/print_job_constants.h
I’m out of leads. What can I try next?
Answers:
I know it’s not exactly answer to your question but might be solution to your problem.
Have you tried instead of passing preferences, just to zoom out the page content and then print the page?
driver.execute_script("document.body.style.zoom='50%'")
# continue with printing
For me zooming out and printing with Default
scale option works like printing page with Scale
set to 50
I wound up using Shadow Root to change the scale.
This is what I did.
driver1.switch_to.window(driver1.window_handles[-2]) # THIS IS THE PRINT DIALOG WINDOW - This could be -1 depending on how many windows are opened
endTime = time.time() + 10
while True:
try: # PRESS 'More settings' TO EXPAND
expand = driver1.execute_script(
"return document.querySelector('print-preview-app').shadowRoot.querySelector('print-preview-sidebar#sidebar').shadowRoot.querySelector('div#container').querySelector('print-preview-more-settings').shadowRoot.querySelector('div').querySelector('cr-expand-button')")
if expand:
expand.click()
break
except:
pass
time.sleep(.3)
if time.time() > endTime: # passed the waiting period
driver1.switch_to.window(driver1.window_handles[0])
break
try: # SELECT SCALE METHOD 'CUSTOM'
scaling = Select(driver1.execute_script(
"return document.querySelector('print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('#container').querySelector('#moreSettings').querySelector('print-preview-scaling-settings.settings-section').shadowRoot.querySelector('print-preview-settings-section').querySelector('div').querySelector('select.md-select')"))
scaling.select_by_value('3')
except:
driver1.switch_to.window(driver1.window_handles[0])
try: # ENTER SCALE NUMBER
time.sleep(.3)
scaling_number = driver1.execute_script(
"return document.querySelector('print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('#container').querySelector('#moreSettings').querySelector('print-preview-scaling-settings').shadowRoot.querySelector('iron-collapse').querySelector('print-preview-number-settings-section').shadowRoot.querySelector('print-preview-settings-section').querySelector('#controls').querySelector('span').querySelector('#userValue').shadowRoot.querySelector('#row-container').querySelector('#input-container').querySelector('div#inner-input-container').querySelector('#input')")
scaling_number.clear()
scaling_number.send_keys('50')
except:
driver1.switch_to.window(driver1.window_handles[0])
driver1.switch_to.window(driver1.window_handles[0]) # back to main window
After much searching and trial-and-error, I’ve finally found the solution! The setting lives in the appState dictionary, and is called "scalingType" but it’s an enumeration, which annoyingly only seems to accept a number, which are defined here (Github mirror) or here (googlesource). 3 gives you custom scaling, which you can then define in the "scaling" setting (which is a string!). So my setup now looks like:
chrome_options = webdriver.ChromeOptions()
appState = {"recentDestinations": [{"id": "Save as PDF", "origin": "local", "account": ""}],
"selectedDestinationId": "Save as PDF",
"version": 2,
"isHeaderFooterEnabled": False,
"isLandscapeEnabled": True,
"scalingType": 3,
"scaling": "141"}
prefs = {'printing.print_preview_sticky_settings.appState': json.dumps(appState),
'savefile.default_directory': BASE_DIR}
chrome_options.add_experimental_option('prefs', prefs)
chrome_options.add_argument('kiosk-printing')
driver = webdriver.Chrome(f'{BASE_DIR}\chromedriver.exe', options=chrome_options)
Current options for scaling type are:
- 0: default
- 1: fit to page
- 2: fit to paper
- 3: custom
but I haven’t had any success with either of the ‘fit to’ options.
More generally, most of these settings/options can be determined by looking through this file of the chromium source and/or it’s containing folder.
I’m writing a script to automatically print a set of web pages in Chrome. If I were to print them manually, I’d choose "Custom" from the Scale drop down and enter 50 into the input field below.
I can’t figure out what arguments to pass in to replicate this setting when I automatically print these pages in bulk using Selenium with ChromeDriver.
appState = { "recentDestinations": [{
"id": "Save as PDF",
"origin": "local",
"account": "",
"printing.scaling": 'Custom', # <== Does it go here?
}],
"selectedDestinationId": "Save as PDF",
"version": 2,
"printing.scaling": 'Custom', # <== Or here?
}
profile = { 'printing.print_preview_sticky_settings.appState': json.dumps(appState),
'printing.print_header_footer': False,
# So many different versions of things I have tried :-(
'printing.scaling': 'Custom',
'printing.scaling_type': 'Custom',
'print_preview.scaling': 'Custom',
'print_preview.scaling_type': 'Custom',
'printing.custom_scaling': True,
'printing.fit_to_page_scaling': 50,
'printing.page_scaling': True,
}
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option('prefs', profile)
br = webdriver.Chrome(options=chrome_options)
All of the different options shown above were guesses after reading through a lot of the Chromium source trying to get a hint.
https://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/pref_names.cc?view=markup
https://chromium.googlesource.com/chromium/src/+/master/printing/print_job_constants.cc
https://chromium.googlesource.com/chromium/src/+/master/printing/print_job_constants.h
I’m out of leads. What can I try next?
I know it’s not exactly answer to your question but might be solution to your problem.
Have you tried instead of passing preferences, just to zoom out the page content and then print the page?
driver.execute_script("document.body.style.zoom='50%'")
# continue with printing
For me zooming out and printing with Default
scale option works like printing page with Scale
set to 50
I wound up using Shadow Root to change the scale.
This is what I did.
driver1.switch_to.window(driver1.window_handles[-2]) # THIS IS THE PRINT DIALOG WINDOW - This could be -1 depending on how many windows are opened
endTime = time.time() + 10
while True:
try: # PRESS 'More settings' TO EXPAND
expand = driver1.execute_script(
"return document.querySelector('print-preview-app').shadowRoot.querySelector('print-preview-sidebar#sidebar').shadowRoot.querySelector('div#container').querySelector('print-preview-more-settings').shadowRoot.querySelector('div').querySelector('cr-expand-button')")
if expand:
expand.click()
break
except:
pass
time.sleep(.3)
if time.time() > endTime: # passed the waiting period
driver1.switch_to.window(driver1.window_handles[0])
break
try: # SELECT SCALE METHOD 'CUSTOM'
scaling = Select(driver1.execute_script(
"return document.querySelector('print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('#container').querySelector('#moreSettings').querySelector('print-preview-scaling-settings.settings-section').shadowRoot.querySelector('print-preview-settings-section').querySelector('div').querySelector('select.md-select')"))
scaling.select_by_value('3')
except:
driver1.switch_to.window(driver1.window_handles[0])
try: # ENTER SCALE NUMBER
time.sleep(.3)
scaling_number = driver1.execute_script(
"return document.querySelector('print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('#container').querySelector('#moreSettings').querySelector('print-preview-scaling-settings').shadowRoot.querySelector('iron-collapse').querySelector('print-preview-number-settings-section').shadowRoot.querySelector('print-preview-settings-section').querySelector('#controls').querySelector('span').querySelector('#userValue').shadowRoot.querySelector('#row-container').querySelector('#input-container').querySelector('div#inner-input-container').querySelector('#input')")
scaling_number.clear()
scaling_number.send_keys('50')
except:
driver1.switch_to.window(driver1.window_handles[0])
driver1.switch_to.window(driver1.window_handles[0]) # back to main window
After much searching and trial-and-error, I’ve finally found the solution! The setting lives in the appState dictionary, and is called "scalingType" but it’s an enumeration, which annoyingly only seems to accept a number, which are defined here (Github mirror) or here (googlesource). 3 gives you custom scaling, which you can then define in the "scaling" setting (which is a string!). So my setup now looks like:
chrome_options = webdriver.ChromeOptions()
appState = {"recentDestinations": [{"id": "Save as PDF", "origin": "local", "account": ""}],
"selectedDestinationId": "Save as PDF",
"version": 2,
"isHeaderFooterEnabled": False,
"isLandscapeEnabled": True,
"scalingType": 3,
"scaling": "141"}
prefs = {'printing.print_preview_sticky_settings.appState': json.dumps(appState),
'savefile.default_directory': BASE_DIR}
chrome_options.add_experimental_option('prefs', prefs)
chrome_options.add_argument('kiosk-printing')
driver = webdriver.Chrome(f'{BASE_DIR}\chromedriver.exe', options=chrome_options)
Current options for scaling type are:
- 0: default
- 1: fit to page
- 2: fit to paper
- 3: custom
but I haven’t had any success with either of the ‘fit to’ options.
More generally, most of these settings/options can be determined by looking through this file of the chromium source and/or it’s containing folder.