Created
January 17, 2021 17:27
-
-
Save zaphodikus/965630feea7844f1c0a7cd6c575751aa to your computer and use it in GitHub Desktop.
Steam screenshot scrollable page with all images python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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("https://cdn2.steam.tools/emoticons/276.png?v3"); 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