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, Screenshot::STREAM_CHUNK

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, #mhtml, #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
62
# File 'lib/ferrum/page.rb', line 45

def initialize(target_id, browser)
  @frames = {}
  @main_frame = Frame.new(nil, self)
  @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, id_starts_with: 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



120
121
122
# File 'lib/ferrum/page.rb', line 120

def back
  history_navigate(delta: -1)
end

#bypass_csp(value = true) ⇒ Object



134
135
136
137
138
# File 'lib/ferrum/page.rb', line 134

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

#closeObject



88
89
90
91
92
# File 'lib/ferrum/page.rb', line 88

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

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



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/ferrum/page.rb', line 148

def command(method, wait: 0, slowmoable: false, **params)
  iteration = @event.reset if wait > 0
  sleep(@browser.slowmo) if slowmoable && @browser.slowmo > 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



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

def forward
  history_navigate(delta: 1)
end

#go_to(url = nil) ⇒ Object Also known as: goto



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

def go_to(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
  if @browser.pending_connection_errors
    pendings = network.traffic.select(&:pending?).map { |e| e.request.url }
    raise PendingConnectionsError.new(options[:url], pendings) unless pendings.empty?
  end
end

#on(name, &block) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/ferrum/page.rb', line 165

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



111
112
113
# File 'lib/ferrum/page.rb', line 111

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

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



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

def resize(width: nil, height: nil, fullscreen: false)
  if fullscreen
    width, height = document_size
    set_window_bounds(windowState: "fullscreen")
  else
    set_window_bounds(windowState: "normal")
    set_window_bounds(width: width, height: height)
  end

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

#set_window_bounds(bounds = {}) ⇒ Object



144
145
146
# File 'lib/ferrum/page.rb', line 144

def set_window_bounds(bounds = {})
  @browser.command("Browser.setWindowBounds", windowId: window_id, bounds: bounds)
end

#stopObject



116
117
118
# File 'lib/ferrum/page.rb', line 116

def stop
  command("Page.stopLoading", slowmoable: true)
end

#subscribed?(event) ⇒ Boolean

Returns:

  • (Boolean)


190
191
192
# File 'lib/ferrum/page.rb', line 190

def subscribed?(event)
  @client.subscribed?(event)
end

#timeoutObject



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

def timeout
  @browser.timeout
end

#wait_for_reload(sec = 1) ⇒ Object



128
129
130
131
132
# File 'lib/ferrum/page.rb', line 128

def wait_for_reload(sec = 1)
  @event.reset if @event.set?
  @event.wait(sec)
  @event.set
end

#window_idObject



140
141
142
# File 'lib/ferrum/page.rb', line 140

def window_id
  @browser.command("Browser.getWindowForTarget", targetId: @target_id)["windowId"]
end