class Wraith::SaveImages

Attributes

history[R]
meta[R]
wraith[R]

Public Class Methods

new(config, history = false, yaml_passed = false) click to toggle source
# File lib/wraith/save_images.rb, line 15
def initialize(config, history = false, yaml_passed = false)
  @wraith = Wraith::Wraith.new(config, { yaml_passed: yaml_passed })
  @history = history
  @meta = SaveMetadata.new(@wraith, history)
end

Public Instance Methods

attempt_image_capture(capture_page_image, filename) click to toggle source
# File lib/wraith/save_images.rb, line 164
def attempt_image_capture(capture_page_image, filename)
  max_attempts = 5
  max_attempts.times do |i|
    run_command capture_page_image
    return true if image_was_created filename
    logger.warn "Failed to capture image #{filename} on attempt number #{i + 1} of #{max_attempts}"
  end

  fail "Unable to capture image #{filename} after #{max_attempts} attempt(s)" unless image_was_created filename
end
capture_image_selenium(screen_sizes, url, file_name, selector, global_before_capture, path_before_capture) click to toggle source
# File lib/wraith/save_images.rb, line 128
def capture_image_selenium(screen_sizes, url, file_name, selector, global_before_capture, path_before_capture)
  driver = get_driver
  driver.manage.timeouts.implicit_wait = 10;
  screen_sizes.to_s.split(",").each do |screen_size|
    for attempt in 1..3 do
      begin
        width, height = screen_size.split("x")
        new_file_name = file_name.sub('MULTI', screen_size)
        driver.manage.window.resize_to(width, height || 1500)
        driver.navigate.to url
        driver.manage.timeouts.implicit_wait = wraith.settle
        driver.execute_script(File.read(global_before_capture)) if global_before_capture
        driver.execute_script(File.read(path_before_capture)) if path_before_capture
        resize_to_fit_page(driver) unless height
        driver.save_screenshot(new_file_name)
        crop_selector(driver, selector, new_file_name) if selector && selector.length > 0
        break
      rescue Net::ReadTimeout => e
        logger.error "Got #{e} on attempt #{attempt} at screen size #{screensize}. URL = #{url}"
      end
    end
  end
  driver.quit
end
check_paths() click to toggle source
# File lib/wraith/save_images.rb, line 21
def check_paths
  if !wraith.paths
    path = File.read(wraith.spider_file)
    eval(path)
  else
    wraith.paths
  end
end
construct_command(width, url, file_name, selector, global_before_capture, path_before_capture) click to toggle source
# File lib/wraith/save_images.rb, line 153
def construct_command(width, url, file_name, selector, global_before_capture, path_before_capture)
  width    = prepare_widths_for_cli(width)
  selector = selector.gsub '#', '\#' # make sure id selectors aren't escaped in the CLI
  global_before_capture = convert_to_absolute global_before_capture
  path_before_capture   = convert_to_absolute path_before_capture

  command_to_run = "#{meta.engine} #{wraith.phantomjs_options} '#{wraith.snap_file}' '#{url}' '#{width}' '#{file_name}' '#{selector}' '#{global_before_capture}' '#{path_before_capture}'"
  logger.debug command_to_run
  command_to_run
end
create_invalid_image(filename, width, invalid_image_name) click to toggle source
# File lib/wraith/save_images.rb, line 180
def create_invalid_image(filename, width, invalid_image_name)
  logger.warn "Using fallback image instead"
  invalid = File.expand_path("../../assets/#{invalid_image_name}", File.dirname(__FILE__))
  FileUtils.cp invalid, filename

  set_image_width(filename, width)
end
crop_selector(driver, selector, image_location) click to toggle source

crop an image around the coordinates of an element

# File lib/wraith/save_images.rb, line 121
def crop_selector driver, selector, image_location
  el = driver.find_element(:css, selector)
  image = MiniMagick::Image.open(image_location)
  image.crop "#{el.rect.width}x#{el.rect.height}+#{el.rect.x}+#{el.rect.y}"
  image.write(image_location)
end
define_individual_job(label, settings, width) click to toggle source
# File lib/wraith/save_images.rb, line 51
def define_individual_job(label, settings, width)
  base_file_name    = meta.file_names(width, label, meta.base_label)
  compare_file_name = meta.file_names(width, label, meta.compare_label)

  jobs = []
  jobs << [label, settings.path, prepare_widths_for_cli(width), settings.base_url,    base_file_name,    settings.selector, wraith.before_capture, settings.before_capture, 'invalid1.jpg']
  jobs << [label, settings.path, prepare_widths_for_cli(width), settings.compare_url, compare_file_name, settings.selector, wraith.before_capture, settings.before_capture, 'invalid2.jpg'] unless settings.compare_url.nil?

  jobs
end
define_jobs() click to toggle source
# File lib/wraith/save_images.rb, line 35
def define_jobs
  jobs = []
  check_paths.each do |label, options|
    settings = CaptureOptions.new(options, wraith)

    if settings.resize
      jobs += define_individual_job(label, settings, wraith.widths)
    else
      wraith.widths.each do |width|
        jobs += define_individual_job(label, settings, width)
      end
    end
  end
  jobs
end
get_driver() click to toggle source

currently only chrome headless at 1x scaling

# File lib/wraith/save_images.rb, line 95
def get_driver
  case meta.engine
  when "chrome"
    options = Selenium::WebDriver::Chrome::Options.new
    [
      'disable-gpu',
      'headless',
      'no-sandbox',
      'device-scale-factor=1',
      'force-device-scale-factor',
      'window-size=1200,1500',
      'hide-scrollbars',
      'ignore-certificate-errors'
    ].each { |arg| options.add_argument("--#{arg}") }
    Selenium::WebDriver.for :chrome, options: options
  end
end
image_was_created(filename) click to toggle source
# File lib/wraith/save_images.rb, line 175
def image_was_created(filename)
   # @TODO - need to check if the image was generated even if in resize mode
  wraith.resize or File.exist? filename
end
parallel_task(jobs) click to toggle source
# File lib/wraith/save_images.rb, line 78
def parallel_task(jobs)
  Parallel.each(jobs, :in_threads => wraith.threads) do |_label, _path, width, url, filename, selector, global_before_capture, path_before_capture|
    begin
      if meta.engine == "chrome"
        capture_image_selenium(width, url, filename, selector, global_before_capture, path_before_capture)
      else
        command = construct_command(width, url, filename, selector, global_before_capture, path_before_capture)
        attempt_image_capture(command, filename)
      end
    rescue => e
      logger.error "#{e}\n  URL = #{url}"
      create_invalid_image(filename, width, invalid_image_name)
    end
  end
end
prepare_widths_for_cli(width) click to toggle source
# File lib/wraith/save_images.rb, line 62
def prepare_widths_for_cli(width)
  # prepare for the command line. [30,40,50] => "30,40,50"
  width = width.join(",") if width.is_a? Array
  width
end
resize_to_fit_page(driver) click to toggle source

resize to fit entire page

# File lib/wraith/save_images.rb, line 114
def resize_to_fit_page driver
  width  = driver.execute_script("return Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth);")
  height = driver.execute_script("return Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);")
  driver.manage.window.resize_to(width, height)
end
run_command(command) click to toggle source
# File lib/wraith/save_images.rb, line 68
def run_command(command)
  output = []
  command.gsub!(/'/, '')
  IO.popen(command).each do |line|
    logger.info line
    output << line.chomp!
  end.close
  output
end
save_images() click to toggle source
# File lib/wraith/save_images.rb, line 30
def save_images
  jobs = define_jobs
  parallel_task(jobs)
end
set_image_width(image, width) click to toggle source
# File lib/wraith/save_images.rb, line 188
def set_image_width(image, width)
  `convert #{image.shellescape} -background none -extent #{width}x0 #{image.shellescape}`
end