Class: Ferrum::Page

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Frames, Screenshot
Defined in:
lib/ferrum/page.rb,
lib/ferrum/page/frames.rb,
lib/ferrum/page/screenshot.rb

Defined Under Namespace

Modules: Frames, Screenshot Classes: Event

Constant Summary collapse

GOTO_WAIT =
ENV.fetch("FERRUM_GOTO_WAIT", 0.1).to_f

Constants included from Screenshot

Screenshot::DEFAULT_PDF_OPTIONS, Screenshot::PAPEP_FORMATS

Instance Attribute Summary collapse

Attributes included from Frames

#main_frame

Instance Method Summary collapse

Methods included from Frames

#frame_by, #frames, #frames_subscribe

Methods included from Screenshot

#document_size, #pdf, #screenshot, #viewport_size

Constructor Details

#initialize(target_id, browser) ⇒ Page

Returns a new instance of Page.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/ferrum/page.rb', line 45

def initialize(target_id, browser)
  @frames = {}
  @target_id, @browser = target_id, browser
  @event = Event.new.tap(&:set)

  host = @browser.process.host
  port = @browser.process.port
  ws_url = "ws://#{host}:#{port}/devtools/page/#{@target_id}"
  @client = Browser::Client.new(browser, ws_url, 1000)

  @mouse, @keyboard = Mouse.new(self), Keyboard.new(self)
  @headers, @cookies = Headers.new(self), Cookies.new(self)
  @network = Network.new(self)

  subscribe
  prepare_page
end

Instance Attribute Details

#browserObject (readonly)

Returns the value of attribute browser.



41
42
43
# File 'lib/ferrum/page.rb', line 41

def browser
  @browser
end

#cookiesObject (readonly)

Returns the value of attribute cookies.



41
42
43
# File 'lib/ferrum/page.rb', line 41

def cookies
  @cookies
end

#document_idObject (readonly)

Returns the value of attribute document_id.



41
42
43
# File 'lib/ferrum/page.rb', line 41

def document_id
  @document_id
end

#eventObject (readonly)

Returns the value of attribute event.



41
42
43
# File 'lib/ferrum/page.rb', line 41

def event
  @event
end

#headersObject (readonly)

Returns the value of attribute headers.



41
42
43
# File 'lib/ferrum/page.rb', line 41

def headers
  @headers
end

#keyboardObject (readonly)

Returns the value of attribute keyboard.



41
42
43
# File 'lib/ferrum/page.rb', line 41

def keyboard
  @keyboard
end

#mouseObject (readonly)

Returns the value of attribute mouse.



41
42
43
# File 'lib/ferrum/page.rb', line 41

def mouse
  @mouse
end

#networkObject (readonly)

Returns the value of attribute network.



41
42
43
# File 'lib/ferrum/page.rb', line 41

def network
  @network
end

#referrerObject

Returns the value of attribute referrer.



40
41
42
# File 'lib/ferrum/page.rb', line 40

def referrer
  @referrer
end

#target_idObject (readonly)

Returns the value of attribute target_id.



41
42
43
# File 'lib/ferrum/page.rb', line 41

def target_id
  @target_id
end

Instance Method Details

#backObject



114
115
116
# File 'lib/ferrum/page.rb', line 114

def back
  history_navigate(delta: -1)
end

#bypass_csp(value = true) ⇒ Object



122
123
124
125
126
# File 'lib/ferrum/page.rb', line 122

def bypass_csp(value = true)
  enabled = !!value
  command("Page.setBypassCSP", enabled: enabled)
  enabled
end

#closeObject



84
85
86
87
88
# File 'lib/ferrum/page.rb', line 84

def close
  @headers.clear
  @browser.command("Target.closeTarget", targetId: @target_id)
  @client.close
end

#command(method, wait: 0, **params) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/ferrum/page.rb', line 128

def command(method, wait: 0, **params)
  iteration = @event.reset if wait > 0
  result = @client.command(method, params)
  if wait > 0
    @event.wait(wait) # Wait a bit after command and check if iteration has
                      # changed which means there was some network event for
                      # the main frame and it started to load new content.
    if iteration != @event.iteration
      set = @event.wait(@browser.timeout)
      raise TimeoutError unless set
    end
  end
  result
end

#forwardObject



118
119
120
# File 'lib/ferrum/page.rb', line 118

def forward
  history_navigate(delta: 1)
end

#goto(url = nil) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/ferrum/page.rb', line 67

def goto(url = nil)
  options = { url: combine_url!(url) }
  options.merge!(referrer: referrer) if referrer
  response = command("Page.navigate", wait: GOTO_WAIT, **options)
  # https://cs.chromium.org/chromium/src/net/base/net_error_list.h
  if %w[net::ERR_NAME_NOT_RESOLVED
        net::ERR_NAME_RESOLUTION_FAILED
        net::ERR_INTERNET_DISCONNECTED
        net::ERR_CONNECTION_TIMED_OUT].include?(response["errorText"])
    raise StatusError, options[:url]
  end
  response["frameId"]
rescue TimeoutError
  pendings = network.traffic.select(&:pending?).map { |e| e.request.url }
  raise StatusError.new(options[:url], pendings) unless pendings.empty?
end

#on(name, &block) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/ferrum/page.rb', line 143

def on(name, &block)
  case name
  when :dialog
    @client.on("Page.javascriptDialogOpening") do |params, index, total|
      dialog = Dialog.new(self, params)
      block.call(dialog, index, total)
    end
  when :request
    @client.on("Fetch.requestPaused") do |params, index, total|
      request = Network::InterceptedRequest.new(self, params)
      exchange = network.select(request.network_id).last
      exchange ||= network.build_exchange(request.network_id)
      exchange.intercepted_request = request
      block.call(request, index, total)
    end
  when :auth
    @client.on("Fetch.authRequired") do |params, index, total|
      request = Network::AuthRequest.new(self, params)
      block.call(request, index, total)
    end
  else
    @client.on(name, &block)
  end
end

#refreshObject Also known as: reload



109
110
111
# File 'lib/ferrum/page.rb', line 109

def refresh
  command("Page.reload", wait: timeout)
end

#resize(width: nil, height: nil, fullscreen: false) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/ferrum/page.rb', line 90

def resize(width: nil, height: nil, fullscreen: false)
  result = @browser.command("Browser.getWindowForTarget", targetId: @target_id)
  @window_id, @bounds = result.values_at("windowId", "bounds")

  if fullscreen
    width, height = document_size
    @browser.command("Browser.setWindowBounds", windowId: @window_id, bounds: { windowState: "fullscreen" })
  else
    @browser.command("Browser.setWindowBounds", windowId: @window_id, bounds: { windowState: "normal" })
    @browser.command("Browser.setWindowBounds", windowId: @window_id, bounds: { width: width, height: height, windowState: "normal" })
  end

  command("Emulation.setDeviceMetricsOverride", width: width,
                                                height: height,
                                                deviceScaleFactor: 1,
                                                mobile: false,
                                                fitWindow: false)
end

#timeoutObject



63
64
65
# File 'lib/ferrum/page.rb', line 63

def timeout
  @browser.timeout
end