Skip to content

Instantly share code, notes, and snippets.

@zaphodikus
Created January 17, 2021 17:27
Show Gist options
  • Save zaphodikus/965630feea7844f1c0a7cd6c575751aa to your computer and use it in GitHub Desktop.
Save zaphodikus/965630feea7844f1c0a7cd6c575751aa to your computer and use it in GitHub Desktop.
Steam screenshot scrollable page with all images python
"""
This script uses a simplified version of the one here:
https://snipt.net/restrada/python-selenium-workaround-for-full-page-screenshot-using-chromedriver-2x/
It contains the *crucial* correction added in the comments by Jason Coutu.
"""
# system modules
import sys
from selenium import webdriver
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
# local modules
import util
class FullPageScreenshot:
""" Demonstration: Get Chrome to generate fullscreen screenshot """
def __init__(self):
path = ChromeDriverManager().install()
self.driver = webdriver.Chrome(executable_path=path)
def close(self):
self.driver.quit()
def take_screenshot(self, url):
''' Generate document-height screenshot '''
print(url)
self.driver.get(url)
# accept privacy pop-up : //*[@id="cmpwelcomebtnyes"]/a
accept_bn = util.wait_until(lambda: self.driver.find_element(by=By.XPATH, value=r'//*[@id="cmpwelcomebtnyes"]/a'),
timeout=10)
accept_bn.click()
util.fullpage_screenshot(self.driver, "test.png")
if __name__ == "__main__":
ss = FullPageScreenshot()
ss.take_screenshot(sys.argv[1])
ss.close()
import os
import time
from selenium.webdriver.common.by import By
import io
from PIL import Image
import PIL.ImageOps as ImageOps
def wait_until(somepredicate, timeout, period=0.25, *args, **kwargs):
mustend = time.time() + timeout
_error = None
while time.time() < mustend:
try:
result = somepredicate(*args, **kwargs)
if result:
return result
except Exception as ex:
_error = ex
time.sleep(period)
if _error:
return _error
return False
def fullpage_screenshot(driver, file):
print("Starting chrome full page screenshot workaround ...")
scroll_sleep = 1
debugging = False
total_width = driver.execute_script("return document.body.offsetWidth")
total_height = driver.execute_script("return document.body.parentNode.scrollHeight")
viewport_width = driver.execute_script("return document.body.clientWidth")
viewport_height = driver.execute_script("return window.innerHeight")
# force page to scroll and if height does not 'increase' twice in a row, then stop
unchanged = 0
while unchanged < 3:
last_height = total_height
script = "window.scrollTo({0}, {1})".format(0, total_height)
driver.execute_script(script)
if debugging:
print(script)
time.sleep(scroll_sleep)
total_height = driver.execute_script("return document.body.parentNode.scrollHeight")
if last_height <= total_height:
unchanged += 1
else:
unchanged = 0
# wait for all icons to load :
# <a class="emote" ng-class="{small: small}" ng-style="getStyle(e.pos)"
# ng-href="https://steamcommunity.com/market/listings/753/525920-%3Apcm17paris%3A" target="_blank"
# href="https://steamcommunity.com/market/listings/753/525920-%3Apcm17paris%3A" style="background-image:
# url(&quot;https://cdn2.steam.tools/emoticons/276.png?v3&quot;); background-position: -320px -960px;"></a>
emotes = driver.find_elements(by=By.CLASS_NAME, value='emote')
print(f"Found {len(emotes)} emotes")
# check every 8'th emote
for emote in emotes[::8]:
fn = 'img/' + emote.get_attribute('href').split('/')[-1] + '.png'
bounds = (0, 0, 0, 0)
# while it's black, keep polling
retry = 5
while retry and (bounds[2] + bounds[3] < 64*2):
raw_png = emote.screenshot_as_png
image_stream = io.BytesIO(raw_png)
emote_image = Image.open(image_stream)
emote_image = ImageOps.invert(emote_image.convert('RGB'))
bounds = emote_image.getbbox()
try:
if (bounds[2] + bounds[3]) < 64*2:
if debugging:
print('.')
except:
bounds = (0, 0, 0, 0)
finally:
script = "window.scrollTo({0}, {1})".format(0, emote.location['y'])
driver.execute_script(script)
if debugging:
print(script)
retry -= 1
if not retry:
print(f"Retried too many times on {fn} url={emote.get_attribute('href')}")
if debugging:
new_file = open(fn, "wb")
new_file.write(raw_png)
new_file.close()
print(f"Saved {fn}")
rectangles = []
print(
"Total: ({0}, {1}), Viewport: ({2},{3})".format(total_width, total_height, viewport_width, viewport_height))
i = 0
while i < total_height:
ii = 0
top_height = i + viewport_height
if top_height > total_height:
top_height = total_height
while ii < total_width:
top_width = ii + viewport_width
if top_width > total_width:
top_width = total_width
print("Appending rectangle ({0},{1},{2},{3})".format(ii, i, top_width, top_height))
rectangles.append((ii, i, top_width,top_height))
ii = ii + viewport_width
i = i + viewport_height
stitched_image = Image.new('RGB', (total_width, total_height))
previous = None
part = 0
for rectangle in rectangles:
if not previous is None:
driver.execute_script("window.scrollTo({0}, {1})".format(rectangle[0], rectangle[1]))
if debugging:
print("Scrolled To ({0},{1})".format(rectangle[0], rectangle[1]))
time.sleep(0.2)
file_name = "part_{0}.png".format(part)
print("Capturing {0} ...".format(file_name))
driver.get_screenshot_as_file(file_name)
screenshot = Image.open(file_name)
if rectangle[1] + viewport_height > total_height:
offset = (rectangle[0], total_height - viewport_height)
else:
offset = (rectangle[0], rectangle[1])
print("Adding to stitched image with offset ({0}, {1})".format(offset[0],offset[1]))
stitched_image.paste(screenshot, offset)
del screenshot
os.remove(file_name)
part = part + 1
previous = rectangle
stitched_image.save(file)
print("Finishing chrome full page screenshot workaround...")
return True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment