Class: Rubium::Browser

Inherits:
Object
  • Object
show all
Defined in:
lib/rubium/browser.rb

Defined Under Namespace

Classes: ConfigurationError

Constant Summary collapse

MAX_CONNECT_WAIT_TIME =
2
MAX_DEFAULT_TIMEOUT =
60

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Browser

Returns a new instance of Browser.



32
33
34
35
36
37
38
39
40
41
# File 'lib/rubium/browser.rb', line 32

def initialize(options = {})
  @options = options

  if @options[:enable_logger]
    @logger = Logger.new(STDOUT)
    @logger.progname = self.class.to_s
  end

  create_browser
end

Instance Attribute Details

#clientObject (readonly)

Returns the value of attribute client.



30
31
32
# File 'lib/rubium/browser.rb', line 30

def client
  @client
end

#devtools_urlObject (readonly)

Returns the value of attribute devtools_url.



30
31
32
# File 'lib/rubium/browser.rb', line 30

def devtools_url
  @devtools_url
end

#loggerObject (readonly)

Returns the value of attribute logger.



30
31
32
# File 'lib/rubium/browser.rb', line 30

def logger
  @logger
end

#optionsObject (readonly)

Returns the value of attribute options.



30
31
32
# File 'lib/rubium/browser.rb', line 30

def options
  @options
end

#pidObject (readonly)

Returns the value of attribute pid.



30
31
32
# File 'lib/rubium/browser.rb', line 30

def pid
  @pid
end

#portObject (readonly)

Returns the value of attribute port.



30
31
32
# File 'lib/rubium/browser.rb', line 30

def port
  @port
end

#processed_requests_countObject (readonly)

Returns the value of attribute processed_requests_count.



30
31
32
# File 'lib/rubium/browser.rb', line 30

def processed_requests_count
  @processed_requests_count
end

Class Method Details

.ports_poolObject



21
22
23
# File 'lib/rubium/browser.rb', line 21

def ports_pool
  @pool ||= RandomPort::Pool.new
end

.running_pidsObject



25
26
27
# File 'lib/rubium/browser.rb', line 25

def running_pids
  @running_pids ||= []
end

Instance Method Details

#bodyObject



97
98
99
100
# File 'lib/rubium/browser.rb', line 97

def body
  response = @client.send_cmd "Runtime.evaluate", expression: 'document.documentElement.outerHTML'
  response.dig("result", "value")
end

#click(selector) ⇒ Object



136
137
138
139
140
# File 'lib/rubium/browser.rb', line 136

def click(selector)
  @client.send_cmd "Runtime.evaluate", expression: <<~js
    document.querySelector("#{selector}").click();
  js
end

#closeObject Also known as: destroy_driver!



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rubium/browser.rb', line 50

def close
  if closed?
    logger.info "Browser already has been closed" if options[:enable_logger]
  else
    Process.kill("HUP", @pid)
    self.class.running_pids.delete(@pid)
    self.class.ports_pool.release(@port)

    FileUtils.rm_rf(@data_dir) if Dir.exist?(@data_dir)
    @closed = true

    logger.info "Closed browser" if options[:enable_logger]
  end
end

#closed?Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/rubium/browser.rb', line 67

def closed?
  @closed
end

#cookiesObject



163
164
165
166
# File 'lib/rubium/browser.rb', line 163

def cookies
  response = @client.send_cmd "Network.getCookies"
  response["cookies"]
end

#current_responseObject



102
103
104
# File 'lib/rubium/browser.rb', line 102

def current_response
  Nokogiri::HTML(body)
end

#evaluate_on_new_document(script) ⇒ Object



157
158
159
# File 'lib/rubium/browser.rb', line 157

def evaluate_on_new_document(script)
  @client.send_cmd "Page.addScriptToEvaluateOnNewDocument", source: script
end

#execute_script(script) ⇒ Object



181
182
183
# File 'lib/rubium/browser.rb', line 181

def execute_script(script)
  @client.send_cmd "Runtime.evaluate", expression: script
end

#fill_in(selector, text) ⇒ Object



175
176
177
178
179
# File 'lib/rubium/browser.rb', line 175

def fill_in(selector, text)
  execute_script <<~js
    document.querySelector("#{selector}").value = "#{text}"
  js
end

#goto(url, wait: options[:max_timeout] || MAX_DEFAULT_TIMEOUT) ⇒ Object Also known as: visit



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/rubium/browser.rb', line 71

def goto(url, wait: options[:max_timeout] || MAX_DEFAULT_TIMEOUT)
  logger.info "Started request: #{url}" if options[:enable_logger]
  if options[:restart_after] && processed_requests_count >= options[:restart_after]
    restart!
  end

  response = @client.send_cmd "Page.navigate", url: url

  # By default, after Page.navigate we should wait till page will load completely
  # using Page.loadEventFired. But on some websites with Ajax navigation, Page.loadEventFired
  # will stuck forever. In this case you can provide `wait: false` option to skip waiting.
  if wait != false
    # https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameStoppedLoading
    Timeout.timeout(wait) do
      @client.wait_for do |event_name, event_params|
        event_name == "Page.frameStoppedLoading" && event_params["frameId"] == response["frameId"]
      end
    end
  end

  @processed_requests_count += 1
  logger.info "Finished request: #{url}" if options[:enable_logger]
end

#has_css?(selector, wait: 0) ⇒ Boolean

Returns:

  • (Boolean)


116
117
118
119
120
121
122
123
124
# File 'lib/rubium/browser.rb', line 116

def has_css?(selector, wait: 0)
  timer = 0
  until current_response.at_css(selector)
    return false if timer >= wait
    timer += 0.2 and sleep 0.2
  end

  true
end

#has_text?(text, wait: 0) ⇒ Boolean

Returns:

  • (Boolean)


126
127
128
129
130
131
132
133
134
# File 'lib/rubium/browser.rb', line 126

def has_text?(text, wait: 0)
  timer = 0
  until body&.include?(text)
    return false if timer >= wait
    timer += 0.2 and sleep 0.2
  end

  true
end

#has_xpath?(path, wait: 0) ⇒ Boolean

Returns:

  • (Boolean)


106
107
108
109
110
111
112
113
114
# File 'lib/rubium/browser.rb', line 106

def has_xpath?(path, wait: 0)
  timer = 0
  until current_response.at_xpath(path)
    return false if timer >= wait
    timer += 0.2 and sleep 0.2
  end

  true
end

#restart!Object



43
44
45
46
47
48
# File 'lib/rubium/browser.rb', line 43

def restart!
  logger.info "Restarting..." if options[:enable_logger]

  close
  create_browser
end

#send_key_on(selector, key) ⇒ Object



144
145
146
147
148
149
150
151
152
# File 'lib/rubium/browser.rb', line 144

def send_key_on(selector, key)
  @client.send_cmd "Runtime.evaluate", expression: <<~js
    document.querySelector("#{selector}").dispatchEvent(
      new KeyboardEvent("keydown", {
        bubbles: true, cancelable: true, keyCode: #{key}
      })
    );
  js
end

#set_cookies(cookies) ⇒ Object



169
170
171
# File 'lib/rubium/browser.rb', line 169

def set_cookies(cookies)
  @client.send_cmd "Network.setCookies", cookies: cookies
end