kimurai_dynamic 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.travis.yml +5 -0
  4. data/CHANGELOG.md +111 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +2038 -0
  8. data/Rakefile +10 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/exe/kimurai +6 -0
  12. data/kimurai.gemspec +48 -0
  13. data/lib/kimurai/automation/deploy.yml +54 -0
  14. data/lib/kimurai/automation/setup/chromium_chromedriver.yml +26 -0
  15. data/lib/kimurai/automation/setup/firefox_geckodriver.yml +20 -0
  16. data/lib/kimurai/automation/setup/phantomjs.yml +33 -0
  17. data/lib/kimurai/automation/setup/ruby_environment.yml +124 -0
  18. data/lib/kimurai/automation/setup.yml +45 -0
  19. data/lib/kimurai/base/saver.rb +106 -0
  20. data/lib/kimurai/base/storage.rb +54 -0
  21. data/lib/kimurai/base.rb +330 -0
  22. data/lib/kimurai/base_helper.rb +22 -0
  23. data/lib/kimurai/browser_builder/mechanize_builder.rb +154 -0
  24. data/lib/kimurai/browser_builder/poltergeist_phantomjs_builder.rb +175 -0
  25. data/lib/kimurai/browser_builder/selenium_chrome_builder.rb +199 -0
  26. data/lib/kimurai/browser_builder/selenium_firefox_builder.rb +204 -0
  27. data/lib/kimurai/browser_builder.rb +20 -0
  28. data/lib/kimurai/capybara_configuration.rb +10 -0
  29. data/lib/kimurai/capybara_ext/driver/base.rb +62 -0
  30. data/lib/kimurai/capybara_ext/mechanize/driver.rb +71 -0
  31. data/lib/kimurai/capybara_ext/poltergeist/driver.rb +13 -0
  32. data/lib/kimurai/capybara_ext/selenium/driver.rb +34 -0
  33. data/lib/kimurai/capybara_ext/session/config.rb +22 -0
  34. data/lib/kimurai/capybara_ext/session.rb +249 -0
  35. data/lib/kimurai/cli/ansible_command_builder.rb +71 -0
  36. data/lib/kimurai/cli/generator.rb +57 -0
  37. data/lib/kimurai/cli.rb +183 -0
  38. data/lib/kimurai/core_ext/array.rb +14 -0
  39. data/lib/kimurai/core_ext/hash.rb +5 -0
  40. data/lib/kimurai/core_ext/numeric.rb +19 -0
  41. data/lib/kimurai/core_ext/string.rb +7 -0
  42. data/lib/kimurai/pipeline.rb +33 -0
  43. data/lib/kimurai/runner.rb +60 -0
  44. data/lib/kimurai/template/.gitignore +18 -0
  45. data/lib/kimurai/template/Gemfile +28 -0
  46. data/lib/kimurai/template/README.md +3 -0
  47. data/lib/kimurai/template/config/application.rb +37 -0
  48. data/lib/kimurai/template/config/automation.yml +13 -0
  49. data/lib/kimurai/template/config/boot.rb +22 -0
  50. data/lib/kimurai/template/config/initializers/.keep +0 -0
  51. data/lib/kimurai/template/config/schedule.rb +57 -0
  52. data/lib/kimurai/template/db/.keep +0 -0
  53. data/lib/kimurai/template/helpers/application_helper.rb +3 -0
  54. data/lib/kimurai/template/lib/.keep +0 -0
  55. data/lib/kimurai/template/log/.keep +0 -0
  56. data/lib/kimurai/template/pipelines/saver.rb +11 -0
  57. data/lib/kimurai/template/pipelines/validator.rb +24 -0
  58. data/lib/kimurai/template/spiders/application_spider.rb +143 -0
  59. data/lib/kimurai/template/tmp/.keep +0 -0
  60. data/lib/kimurai/version.rb +3 -0
  61. data/lib/kimurai.rb +54 -0
  62. metadata +349 -0
@@ -0,0 +1,199 @@
1
+ require 'capybara'
2
+ require 'selenium-webdriver'
3
+ require_relative '../capybara_configuration'
4
+ require_relative '../capybara_ext/selenium/driver'
5
+ require_relative '../capybara_ext/session'
6
+
7
+ module Kimurai::BrowserBuilder
8
+ class SeleniumChromeBuilder
9
+ class << self
10
+ attr_accessor :virtual_display
11
+ end
12
+
13
+ attr_reader :logger, :spider
14
+
15
+ def initialize(config, spider:)
16
+ @config = config
17
+ @spider = spider
18
+ @logger = spider.logger
19
+ end
20
+
21
+ def build
22
+ # Register driver
23
+ Capybara.register_driver :selenium_chrome do |app|
24
+ # Create driver options
25
+ opts = { args: %w[--disable-gpu --no-sandbox --disable-translate] }
26
+
27
+ # Provide custom chrome browser path:
28
+ if chrome_path = Kimurai.configuration.selenium_chrome_path
29
+ opts.merge!(binary: chrome_path)
30
+ end
31
+
32
+ # See all options here: https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/Chrome/Options.html
33
+ driver_options = Selenium::WebDriver::Chrome::Options.new(opts)
34
+
35
+ # Window size
36
+ if size = @config[:window_size].presence
37
+ driver_options.args << "--window-size=#{size.join(',')}"
38
+ logger.debug "BrowserBuilder (selenium_chrome): enabled window_size"
39
+ end
40
+
41
+ # Proxy
42
+ if proxy = @config[:proxy].presence
43
+ proxy_string = (proxy.class == Proc ? proxy.call : proxy).strip
44
+ ip, port, type, user, password = proxy_string.split(":")
45
+
46
+ if %w(http socks5).include?(type)
47
+ if user.nil? && password.nil?
48
+ driver_options.args << "--proxy-server=#{type}://#{ip}:#{port}"
49
+ logger.debug "BrowserBuilder (selenium_chrome): enabled #{type} proxy, ip: #{ip}, port: #{port}"
50
+ else
51
+ logger.error "BrowserBuilder (selenium_chrome): proxy with authentication doesn't supported by selenium, skipped"
52
+ end
53
+ else
54
+ logger.error "BrowserBuilder (selenium_chrome): wrong type of proxy: #{type}, skipped"
55
+ end
56
+ end
57
+
58
+ if proxy_bypass_list = @config[:proxy_bypass_list].presence
59
+ if proxy
60
+ driver_options.args << "--proxy-bypass-list=#{proxy_bypass_list.join(';')}"
61
+ logger.debug "BrowserBuilder (selenium_chrome): enabled proxy_bypass_list"
62
+ else
63
+ logger.error "BrowserBuilder (selenium_chrome): provide `proxy` to set proxy_bypass_list, skipped"
64
+ end
65
+ end
66
+
67
+ # SSL
68
+ if @config[:ignore_ssl_errors].present?
69
+ driver_options.args << "--ignore-certificate-errors"
70
+ driver_options.args << "--allow-insecure-localhost"
71
+ logger.debug "BrowserBuilder (selenium_chrome): enabled ignore_ssl_errors"
72
+ end
73
+
74
+ # Disable images
75
+ if @config[:disable_images].present?
76
+ driver_options.prefs["profile.managed_default_content_settings.images"] = 2
77
+ logger.debug "BrowserBuilder (selenium_chrome): enabled disable_images"
78
+ end
79
+
80
+ # Headers
81
+ if @config[:headers].present?
82
+ logger.warn "BrowserBuilder: (selenium_chrome): custom headers doesn't supported by selenium, skipped"
83
+ end
84
+
85
+ if user_agent = @config[:user_agent].presence
86
+ user_agent_string = (user_agent.class == Proc ? user_agent.call : user_agent).strip
87
+ driver_options.args << "--user-agent='#{user_agent_string}'"
88
+ logger.debug "BrowserBuilder (selenium_chrome): enabled custom user_agent"
89
+ end
90
+
91
+ # Headless mode
92
+ if ENV["HEADLESS"] != "false"
93
+ if @config[:headless_mode] == :virtual_display
94
+ if Gem::Platform.local.os == "linux"
95
+ unless self.class.virtual_display
96
+ require 'headless'
97
+ self.class.virtual_display = Headless.new(reuse: true, destroy_at_exit: false)
98
+ self.class.virtual_display.start
99
+ end
100
+
101
+ logger.debug "BrowserBuilder (selenium_chrome): enabled virtual_display headless_mode"
102
+ else
103
+ logger.error "BrowserBuilder (selenium_chrome): virtual_display headless_mode works only " \
104
+ "on Linux platform. Browser will run in normal mode. Set `native` mode instead."
105
+ end
106
+ else
107
+ driver_options.args << "--headless"
108
+ logger.debug "BrowserBuilder (selenium_chrome): enabled native headless_mode"
109
+ end
110
+ end
111
+
112
+ chromedriver_path = Kimurai.configuration.chromedriver_path || "/usr/local/bin/chromedriver"
113
+ service = Selenium::WebDriver::Service.chrome(path: chromedriver_path)
114
+ Capybara::Selenium::Driver.new(app, browser: :chrome, options: driver_options, service: service)
115
+ end
116
+
117
+ # Create browser instance (Capybara session)
118
+ @browser = Capybara::Session.new(:selenium_chrome)
119
+ @browser.spider = spider
120
+ logger.debug "BrowserBuilder (selenium_chrome): created browser instance"
121
+
122
+ if @config[:extensions].present?
123
+ logger.error "BrowserBuilder (selenium_chrome): `extensions` option not supported by Selenium, skipped"
124
+ end
125
+
126
+ # Cookies
127
+ if cookies = @config[:cookies].presence
128
+ @browser.config.cookies = cookies
129
+ logger.debug "BrowserBuilder (selenium_chrome): enabled custom cookies"
130
+ end
131
+
132
+ # Browser instance options
133
+ # skip_request_errors
134
+ if skip_errors = @config[:skip_request_errors].presence
135
+ @browser.config.skip_request_errors = skip_errors
136
+ logger.debug "BrowserBuilder (selenium_chrome): enabled skip_request_errors"
137
+ end
138
+
139
+ # retry_request_errors
140
+ if retry_errors = @config[:retry_request_errors].presence
141
+ @browser.config.retry_request_errors = retry_errors
142
+ logger.debug "BrowserBuilder (selenium_chrome): enabled retry_request_errors"
143
+ end
144
+
145
+ # restart_if
146
+ if requests_limit = @config.dig(:restart_if, :requests_limit).presence
147
+ @browser.config.restart_if[:requests_limit] = requests_limit
148
+ logger.debug "BrowserBuilder (selenium_chrome): enabled restart_if.requests_limit >= #{requests_limit}"
149
+ end
150
+
151
+ if memory_limit = @config.dig(:restart_if, :memory_limit).presence
152
+ @browser.config.restart_if[:memory_limit] = memory_limit
153
+ logger.debug "BrowserBuilder (selenium_chrome): enabled restart_if.memory_limit >= #{memory_limit}"
154
+ end
155
+
156
+ # before_request clear_cookies
157
+ if @config.dig(:before_request, :clear_cookies)
158
+ @browser.config.before_request[:clear_cookies] = true
159
+ logger.debug "BrowserBuilder (selenium_chrome): enabled before_request.clear_cookies"
160
+ end
161
+
162
+ # before_request clear_and_set_cookies
163
+ if @config.dig(:before_request, :clear_and_set_cookies)
164
+ if cookies = @config[:cookies].presence
165
+ @browser.config.cookies = cookies
166
+ @browser.config.before_request[:clear_and_set_cookies] = true
167
+ logger.debug "BrowserBuilder (selenium_chrome): enabled before_request.clear_and_set_cookies"
168
+ else
169
+ logger.error "BrowserBuilder (selenium_chrome): cookies should be present to enable before_request.clear_and_set_cookies, skipped"
170
+ end
171
+ end
172
+
173
+ # before_request change_user_agent
174
+ if @config.dig(:before_request, :change_user_agent)
175
+ logger.error "BrowserBuilder (selenium_chrome): before_request.change_user_agent option not supported by Selenium, skipped"
176
+ end
177
+
178
+ # before_request change_proxy
179
+ if @config.dig(:before_request, :change_proxy)
180
+ logger.error "BrowserBuilder (selenium_chrome): before_request.change_proxy option not supported by Selenium, skipped"
181
+ end
182
+
183
+ # before_request delay
184
+ if delay = @config.dig(:before_request, :delay).presence
185
+ @browser.config.before_request[:delay] = delay
186
+ logger.debug "BrowserBuilder (selenium_chrome): enabled before_request.delay"
187
+ end
188
+
189
+ # encoding
190
+ if encoding = @config[:encoding]
191
+ @browser.config.encoding = encoding
192
+ logger.debug "BrowserBuilder (selenium_chrome): enabled encoding: #{encoding}"
193
+ end
194
+
195
+ # return Capybara session instance
196
+ @browser
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,204 @@
1
+ require 'capybara'
2
+ require 'selenium-webdriver'
3
+ require_relative '../capybara_configuration'
4
+ require_relative '../capybara_ext/selenium/driver'
5
+ require_relative '../capybara_ext/session'
6
+
7
+ module Kimurai::BrowserBuilder
8
+ class SeleniumFirefoxBuilder
9
+ class << self
10
+ attr_accessor :virtual_display
11
+ end
12
+
13
+ attr_reader :logger, :spider
14
+
15
+ def initialize(config, spider:)
16
+ @config = config
17
+ @spider = spider
18
+ @logger = spider.logger
19
+ end
20
+
21
+ def build
22
+ # Register driver
23
+ Capybara.register_driver :selenium_firefox do |app|
24
+ # Create driver options
25
+ driver_options = Selenium::WebDriver::Firefox::Options.new
26
+ driver_options.profile = Selenium::WebDriver::Firefox::Profile.new
27
+ driver_options.profile["browser.link.open_newwindow"] = 3 # open windows in tabs
28
+ driver_options.profile["media.peerconnection.enabled"] = false # disable web rtc
29
+
30
+ # Proxy
31
+ if proxy = @config[:proxy].presence
32
+ proxy_string = (proxy.class == Proc ? proxy.call : proxy).strip
33
+ ip, port, type, user, password = proxy_string.split(":")
34
+
35
+ if user.nil? && password.nil?
36
+ driver_options.profile["network.proxy.type"] = 1
37
+ if type == "http"
38
+ driver_options.profile["network.proxy.http"] = ip
39
+ driver_options.profile["network.proxy.http_port"] = port.to_i
40
+ driver_options.profile["network.proxy.ssl"] = ip
41
+ driver_options.profile["network.proxy.ssl_port"] = port.to_i
42
+
43
+ logger.debug "BrowserBuilder (selenium_firefox): enabled http proxy, ip: #{ip}, port: #{port}"
44
+ elsif type == "socks5"
45
+ driver_options.profile["network.proxy.socks"] = ip
46
+ driver_options.profile["network.proxy.socks_port"] = port.to_i
47
+ driver_options.profile["network.proxy.socks_version"] = 5
48
+ driver_options.profile["network.proxy.socks_remote_dns"] = true
49
+
50
+ logger.debug "BrowserBuilder (selenium_firefox): enabled socks5 proxy, ip: #{ip}, port: #{port}"
51
+ else
52
+ logger.error "BrowserBuilder (selenium_firefox): wrong type of proxy: #{type}, skipped"
53
+ end
54
+ else
55
+ logger.error "BrowserBuilder (selenium_firefox): proxy with authentication doesn't supported by selenium, skipped"
56
+ end
57
+ end
58
+
59
+ if proxy_bypass_list = @config[:proxy_bypass_list].presence
60
+ if proxy
61
+ driver_options.profile["network.proxy.no_proxies_on"] = proxy_bypass_list.join(", ")
62
+ logger.debug "BrowserBuilder (selenium_firefox): enabled proxy_bypass_list"
63
+ else
64
+ logger.error "BrowserBuilder (selenium_firefox): provide `proxy` to set proxy_bypass_list, skipped"
65
+ end
66
+ end
67
+
68
+ # SSL
69
+ if @config[:ignore_ssl_errors].present?
70
+ driver_options.profile.secure_ssl = false
71
+ driver_options.profile.assume_untrusted_certificate_issuer = true
72
+ logger.debug "BrowserBuilder (selenium_firefox): enabled ignore_ssl_errors"
73
+ end
74
+
75
+ # Disable images
76
+ if @config[:disable_images].present?
77
+ driver_options.profile["permissions.default.image"] = 2
78
+ logger.debug "BrowserBuilder (selenium_firefox): enabled disable_images"
79
+ end
80
+
81
+ # Headers
82
+ if @config[:headers].present?
83
+ logger.warn "BrowserBuilder: (selenium_firefox): custom headers doesn't supported by selenium, skipped"
84
+ end
85
+
86
+ if user_agent = @config[:user_agent].presence
87
+ user_agent_string = (user_agent.class == Proc ? user_agent.call : user_agent).strip
88
+ driver_options.profile["general.useragent.override"] = user_agent_string
89
+ logger.debug "BrowserBuilder (selenium_firefox): enabled custom user_agent"
90
+ end
91
+
92
+ # Headless mode
93
+ if ENV["HEADLESS"] != "false"
94
+ if @config[:headless_mode] == :virtual_display
95
+ if Gem::Platform.local.os == "linux"
96
+ unless self.class.virtual_display
97
+ require 'headless'
98
+ self.class.virtual_display = Headless.new(reuse: true, destroy_at_exit: false)
99
+ self.class.virtual_display.start
100
+ end
101
+
102
+ logger.debug "BrowserBuilder (selenium_firefox): enabled virtual_display headless_mode"
103
+ else
104
+ logger.error "BrowserBuilder (selenium_firefox): virtual_display headless_mode works only " \
105
+ "on Linux platform. Browser will run in normal mode. Set `native` mode instead."
106
+ end
107
+ else
108
+ driver_options.args << "--headless"
109
+ logger.debug "BrowserBuilder (selenium_firefox): enabled native headless_mode"
110
+ end
111
+ end
112
+
113
+ Capybara::Selenium::Driver.new(app, browser: :firefox, options: driver_options)
114
+ end
115
+
116
+ # Create browser instance (Capybara session)
117
+ @browser = Capybara::Session.new(:selenium_firefox)
118
+ @browser.spider = spider
119
+ logger.debug "BrowserBuilder (selenium_firefox): created browser instance"
120
+
121
+ if @config[:extensions].present?
122
+ logger.error "BrowserBuilder (selenium_firefox): `extensions` option not supported by Selenium, skipped"
123
+ end
124
+
125
+ # Window size
126
+ if size = @config[:window_size].presence
127
+ @browser.current_window.resize_to(*size)
128
+ logger.debug "BrowserBuilder (selenium_firefox): enabled window_size"
129
+ end
130
+
131
+ # Cookies
132
+ if cookies = @config[:cookies].presence
133
+ @browser.config.cookies = cookies
134
+ logger.debug "BrowserBuilder (selenium_firefox): enabled custom cookies"
135
+ end
136
+
137
+ # Browser instance options
138
+ # skip_request_errors
139
+ if skip_errors = @config[:skip_request_errors].presence
140
+ @browser.config.skip_request_errors = skip_errors
141
+ logger.debug "BrowserBuilder (selenium_firefox): enabled skip_request_errors"
142
+ end
143
+
144
+ # retry_request_errors
145
+ if retry_errors = @config[:retry_request_errors].presence
146
+ @browser.config.retry_request_errors = retry_errors
147
+ logger.debug "BrowserBuilder (selenium_firefox): enabled retry_request_errors"
148
+ end
149
+
150
+ # restart_if
151
+ if requests_limit = @config.dig(:restart_if, :requests_limit).presence
152
+ @browser.config.restart_if[:requests_limit] = requests_limit
153
+ logger.debug "BrowserBuilder (selenium_firefox): enabled restart_if.requests_limit >= #{requests_limit}"
154
+ end
155
+
156
+ if memory_limit = @config.dig(:restart_if, :memory_limit).presence
157
+ @browser.config.restart_if[:memory_limit] = memory_limit
158
+ logger.debug "BrowserBuilder (selenium_firefox): enabled restart_if.memory_limit >= #{memory_limit}"
159
+ end
160
+
161
+ # before_request clear_cookies
162
+ if @config.dig(:before_request, :clear_cookies)
163
+ @browser.config.before_request[:clear_cookies] = true
164
+ logger.debug "BrowserBuilder (selenium_firefox): enabled before_request.clear_cookies"
165
+ end
166
+
167
+ # before_request clear_and_set_cookies
168
+ if @config.dig(:before_request, :clear_and_set_cookies)
169
+ if cookies = @config[:cookies].presence
170
+ @browser.config.cookies = cookies
171
+ @browser.config.before_request[:clear_and_set_cookies] = true
172
+ logger.debug "BrowserBuilder (selenium_firefox): enabled before_request.clear_and_set_cookies"
173
+ else
174
+ logger.error "BrowserBuilder (selenium_firefox): cookies should be present to enable before_request.clear_and_set_cookies, skipped"
175
+ end
176
+ end
177
+
178
+ # before_request change_user_agent
179
+ if @config.dig(:before_request, :change_user_agent)
180
+ logger.error "BrowserBuilder (selenium_firefox): before_request.change_user_agent option not supported by Selenium, skipped"
181
+ end
182
+
183
+ # before_request change_proxy
184
+ if @config.dig(:before_request, :change_proxy)
185
+ logger.error "BrowserBuilder (selenium_firefox): before_request.change_proxy option not supported by Selenium, skipped"
186
+ end
187
+
188
+ # before_request delay
189
+ if delay = @config.dig(:before_request, :delay).presence
190
+ @browser.config.before_request[:delay] = delay
191
+ logger.debug "BrowserBuilder (selenium_firefox): enabled before_request.delay"
192
+ end
193
+
194
+ # encoding
195
+ if encoding = @config[:encoding]
196
+ @browser.config.encoding = encoding
197
+ logger.debug "BrowserBuilder (selenium_firefox): enabled encoding: #{encoding}"
198
+ end
199
+
200
+ # return Capybara session instance
201
+ @browser
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,20 @@
1
+ module Kimurai
2
+ module BrowserBuilder
3
+ def self.build(engine, config = {}, spider:)
4
+ if config[:browser].present?
5
+ raise "++++++ BrowserBuilder: browser option is depricated. Now all sub-options inside " \
6
+ "`browser` should be placed right into `@config` hash, without `browser` parent key.\n" \
7
+ "See more here: https://github.com/vifreefly/kimuraframework/blob/master/CHANGELOG.md#breaking-changes-110 ++++++"
8
+ end
9
+
10
+ begin
11
+ require "kimurai/browser_builder/#{engine}_builder"
12
+ rescue LoadError => e
13
+ end
14
+
15
+ builder_class_name = "#{engine}_builder".classify
16
+ builder = "Kimurai::BrowserBuilder::#{builder_class_name}".constantize
17
+ builder.new(config, spider: spider).build
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ require 'capybara'
2
+
3
+ Capybara.configure do |config|
4
+ config.run_server = false
5
+ config.default_selector = :xpath
6
+ config.save_path = "tmp"
7
+ config.default_max_wait_time = 10
8
+ config.ignore_hidden_elements = false
9
+ config.threadsafe = true
10
+ end
@@ -0,0 +1,62 @@
1
+ require 'pathname'
2
+
3
+ class Capybara::Driver::Base
4
+ attr_accessor :visited
5
+ attr_writer :requests, :responses
6
+
7
+ def requests
8
+ @requests ||= 0
9
+ end
10
+
11
+ def responses
12
+ @responses ||= 0
13
+ end
14
+
15
+ def current_memory
16
+ driver_pid = pid
17
+
18
+ all = (get_descendant_processes(driver_pid) << driver_pid).uniq
19
+ all.map { |pid| get_process_memory(pid) }.sum
20
+ end
21
+
22
+ private
23
+
24
+ def get_descendant_processes(base)
25
+ descendants = Hash.new { |ht, k| ht[k] = [k] }
26
+ Hash[*`ps -eo pid,ppid`.scan(/\d+/).map(&:to_i)].each do |pid, ppid|
27
+ descendants[ppid] << descendants[pid]
28
+ end
29
+
30
+ descendants[base].flatten - [base]
31
+ end
32
+
33
+ # https://github.com/schneems/get_process_mem
34
+ # Note: for Linux takes PSS (not RSS) memory (I think PSS better fits in this case)
35
+ def get_process_memory(pid)
36
+ case @platform ||= Gem::Platform.local.os
37
+ when "linux"
38
+ begin
39
+ file = Pathname.new "/proc/#{pid}/smaps"
40
+ return 0 unless file.exist?
41
+
42
+ lines = file.each_line.select { |line| line.match(/^Pss/) }
43
+ return 0 if lines.empty?
44
+
45
+ lines.reduce(0) do |sum, line|
46
+ line.match(/(?<value>(\d*\.{0,1}\d+))\s+(?<unit>\w\w)/) do |m|
47
+ sum += m[:value].to_i
48
+ end
49
+
50
+ sum
51
+ end
52
+ rescue Errno::EACCES
53
+ 0
54
+ end
55
+ when "darwin"
56
+ mem = `ps -o rss= -p #{pid}`.strip
57
+ mem.empty? ? 0 : mem.to_i
58
+ else
59
+ raise "Can't check process memory, wrong type of platform: #{@platform}"
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,71 @@
1
+ require 'mechanize'
2
+ require_relative '../driver/base'
3
+
4
+ class Capybara::Mechanize::Driver
5
+ # Extend capybara-mechnize to support Poltergeist-like methods
6
+ # https://www.rubydoc.info/gems/poltergeist/Capybara/Poltergeist/Driver
7
+
8
+ def set_proxy(ip, port, type, user = nil, password = nil)
9
+ # type is always "http", "socks" is not supported (yet)
10
+ browser.agent.set_proxy(ip, port, user, password)
11
+ end
12
+
13
+ ###
14
+
15
+ def headers
16
+ browser.agent.request_headers
17
+ end
18
+
19
+ def headers=(headers)
20
+ browser.agent.request_headers = headers
21
+ end
22
+
23
+ def add_header(name, value)
24
+ browser.agent.request_headers[name] = value
25
+ end
26
+
27
+ ###
28
+
29
+ def get_cookies
30
+ browser.agent.cookies
31
+ end
32
+
33
+ def set_cookie(name, value, options = {})
34
+ options[:name] ||= name
35
+ options[:value] ||= value
36
+
37
+ cookie = Mechanize::Cookie.new(options.merge path: "/")
38
+ browser.agent.cookie_jar << cookie
39
+ end
40
+
41
+ def set_cookies(cookies)
42
+ cookies.each do |cookie|
43
+ set_cookie(cookie[:name], cookie[:value], cookie)
44
+ end
45
+ end
46
+
47
+ def clear_cookies
48
+ browser.agent.cookie_jar.clear!
49
+ end
50
+
51
+ ###
52
+
53
+ def quit
54
+ browser.agent.shutdown
55
+ end
56
+
57
+ ###
58
+
59
+ # Reset parent method `current_memory` for mechanize (we can't measure memory of Mechanize driver)
60
+ def current_memory
61
+ nil
62
+ end
63
+
64
+ def pid
65
+ nil
66
+ end
67
+
68
+ def port
69
+ nil
70
+ end
71
+ end
@@ -0,0 +1,13 @@
1
+ require_relative '../driver/base'
2
+
3
+ module Capybara::Poltergeist
4
+ class Driver
5
+ def pid
6
+ client_pid
7
+ end
8
+
9
+ def port
10
+ server.port
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ require_relative '../driver/base'
2
+
3
+ class Capybara::Selenium::Driver
4
+ def get_cookies
5
+ browser.manage.all_cookies
6
+ end
7
+
8
+ def set_cookie(name, value, options = {})
9
+ options[:name] ||= name
10
+ options[:value] ||= value
11
+
12
+ browser.manage.add_cookie(options)
13
+ end
14
+
15
+ def set_cookies(cookies)
16
+ cookies.each do |cookie|
17
+ set_cookie(cookie[:name], cookie[:value], cookie)
18
+ end
19
+ end
20
+
21
+ def clear_cookies
22
+ browser.manage.delete_all_cookies
23
+ end
24
+
25
+ ###
26
+
27
+ def pid
28
+ @pid ||= `lsof -i tcp:#{port} -t`.strip.to_i
29
+ end
30
+
31
+ def port
32
+ @port ||= browser.send(:bridge).instance_variable_get("@http").instance_variable_get("@server_url").port
33
+ end
34
+ end
@@ -0,0 +1,22 @@
1
+ module Capybara
2
+ class SessionConfig
3
+ attr_accessor :cookies, :proxy, :user_agent, :encoding
4
+ attr_writer :retry_request_errors, :skip_request_errors
5
+
6
+ def retry_request_errors
7
+ @retry_request_errors ||= []
8
+ end
9
+
10
+ def skip_request_errors
11
+ @skip_request_errors ||= []
12
+ end
13
+
14
+ def restart_if
15
+ @restart_if ||= {}
16
+ end
17
+
18
+ def before_request
19
+ @before_request ||= {}
20
+ end
21
+ end
22
+ end