proxy_fetcher 0.11.0 → 0.15.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -1
  3. data/Gemfile +4 -2
  4. data/Rakefile +3 -1
  5. data/gemfiles/nokogiri.gemfile +1 -1
  6. data/gemfiles/oga.gemfile +2 -2
  7. data/lib/proxy_fetcher.rb +42 -31
  8. data/lib/proxy_fetcher/client/request.rb +3 -3
  9. data/lib/proxy_fetcher/configuration.rb +13 -9
  10. data/lib/proxy_fetcher/document/node.rb +1 -1
  11. data/lib/proxy_fetcher/manager.rb +40 -7
  12. data/lib/proxy_fetcher/providers/base.rb +2 -1
  13. data/lib/proxy_fetcher/providers/free_proxy_list.rb +0 -21
  14. data/lib/proxy_fetcher/providers/free_proxy_list_socks.rb +58 -0
  15. data/lib/proxy_fetcher/providers/free_proxy_list_ssl.rb +1 -0
  16. data/lib/proxy_fetcher/providers/free_proxy_list_us.rb +54 -0
  17. data/lib/proxy_fetcher/providers/mtpro.rb +43 -0
  18. data/lib/proxy_fetcher/providers/proxypedia.rb +48 -0
  19. data/lib/proxy_fetcher/providers/proxyscrape_http.rb +65 -0
  20. data/lib/proxy_fetcher/providers/proxyscrape_socks4.rb +65 -0
  21. data/lib/proxy_fetcher/providers/proxyscrape_socks5.rb +65 -0
  22. data/lib/proxy_fetcher/providers/xroxy.rb +2 -2
  23. data/lib/proxy_fetcher/proxy.rb +12 -0
  24. data/lib/proxy_fetcher/utils/http_client.rb +25 -21
  25. data/lib/proxy_fetcher/utils/proxy_validator.rb +20 -8
  26. data/lib/proxy_fetcher/version.rb +2 -2
  27. data/proxy_fetcher.gemspec +6 -4
  28. data/spec/fixtures/proxies.txt +14 -0
  29. data/spec/proxy_fetcher/client/client_spec.rb +10 -5
  30. data/spec/proxy_fetcher/manager_spec.rb +18 -0
  31. data/spec/proxy_fetcher/providers/proxy_classes_spec.rb +28 -0
  32. metadata +15 -12
  33. data/lib/proxy_fetcher/providers/gather_proxy.rb +0 -50
  34. data/spec/proxy_fetcher/providers/free_proxy_list_spec.rb +0 -13
  35. data/spec/proxy_fetcher/providers/free_proxy_list_ssl_spec.rb +0 -11
  36. data/spec/proxy_fetcher/providers/gather_proxy_spec.rb +0 -11
  37. data/spec/proxy_fetcher/providers/http_tunnel_spec.rb +0 -11
  38. data/spec/proxy_fetcher/providers/proxy_list_spec.rb +0 -11
  39. data/spec/proxy_fetcher/providers/xroxy_spec.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a0d7b377ed3c25e50552e89ba76c0e73fad3923bf171e1cee2f592d777787c3
4
- data.tar.gz: 83b594e04e03c74a63146a6907c99025d50607c88f8cf94f6d5ce044795243ad
3
+ metadata.gz: 071dd5bfeaf01174bf803981de6147f999e75b99a2d03c32e034b72dd5dc7c82
4
+ data.tar.gz: 1675ce07491e0cbce401c2a113ee7eccdcba0c4cf42ba7e380ad63be988ec91a
5
5
  SHA512:
6
- metadata.gz: 1f096c2473035255eb9492297b5641ab5caee62566eb20eb40d3b2f02eea5d06fa1279a2cadeb3266c0f52ce98040185a69678faf116b6398c2c75f79d5c4ebd
7
- data.tar.gz: a9372ef8bdbb3c51c5060308cbc46c905df3819e682bceb858ba494f5f94722095f2a2bee94575606f628d091b87325425c218f8c31a2b807bcb159c59ba6e65
6
+ metadata.gz: 42037b0b55109b535e25284815a096154c79bca2f58b107311f5c53da5b9ec0242ab39a6dd9bae48ef3e863c7f43251167180266578ac177887bd3a63215ef1e
7
+ data.tar.gz: 188dd298f8ea03e5985d89e97f99a12ef5d5384eae03a78f9b77e5172c28ae5990dec64795817d52ea6895395679a6c2f2deafafa3f8617154afb32fc06bc972
data/CHANGELOG.md CHANGED
@@ -4,7 +4,38 @@ Reverse Chronological Order:
4
4
 
5
5
  ## `master`
6
6
 
7
- * Add your description here
7
+ ...
8
+
9
+ ## `0.15.1` (2021-02-17)
10
+
11
+ * Support for Ruby 3.0
12
+
13
+ ## `0.15.0` (2021-01-26)
14
+
15
+ * Removed failing providers
16
+ * Added new
17
+ * Specs refactoring
18
+
19
+ ## `0.14.0` (2020-05-11)
20
+
21
+ * Add MTPro provider
22
+ * Add Proxypedia provider
23
+
24
+ ## `0.13.0` (2020-03-09)
25
+
26
+ * Fix GatherProxy provider
27
+ * Fix XRoxy provider
28
+ * Allow ability to load proxies from files
29
+ * Fix Proxy object comparators
30
+
31
+ ## `0.12.0` (2020-01-28)
32
+
33
+ * Fix XRoxy provider
34
+ * Fix multi-threading issues with config and adapter
35
+
36
+ ## `0.11.0` (2019-10-24)
37
+
38
+ * Big gem refactoring
8
39
 
9
40
  ## `0.10.2` (2019-03-15)
10
41
 
data/Gemfile CHANGED
@@ -5,10 +5,12 @@ source "https://rubygems.org"
5
5
  gemspec
6
6
 
7
7
  gem "nokogiri", "~> 1.8"
8
- gem "oga", "~> 2.0"
9
- gem "rubocop", "~> 0.74"
8
+ gem "oga", "~> 3.2"
9
+ gem "rubocop", "~> 1.0"
10
10
 
11
11
  group :test do
12
12
  gem "coveralls", require: false
13
+ # Until I find a way to introduce other MITM proxy
14
+ gem "webrick", "1.4.2"
13
15
  gem "evil-proxy", "~> 0.2"
14
16
  end
data/Rakefile CHANGED
@@ -3,6 +3,8 @@
3
3
  require "bundler/gem_tasks"
4
4
 
5
5
  require "rspec/core/rake_task"
6
- RSpec::Core::RakeTask.new(:spec)
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.rspec_opts = '--tag "~unreliable"'
8
+ end
7
9
 
8
10
  task default: :spec
@@ -8,6 +8,6 @@ gem "nokogiri", "~> 1.8"
8
8
 
9
9
  group :test do
10
10
  gem "coveralls", require: false
11
+ gem "webrick"
11
12
  gem "evil-proxy", "~> 0.2"
12
- gem "rspec", "~> 3.6"
13
13
  end
data/gemfiles/oga.gemfile CHANGED
@@ -4,10 +4,10 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec path: "../"
6
6
 
7
- gem "oga", "~> 2.0"
7
+ gem "oga", "~> 3.0"
8
8
 
9
9
  group :test do
10
10
  gem "coveralls", require: false
11
+ gem "webrick"
11
12
  gem "evil-proxy", "~> 0.2"
12
- gem "rspec", "~> 3.6"
13
13
  end
data/lib/proxy_fetcher.rb CHANGED
@@ -4,43 +4,52 @@ require "uri"
4
4
  require "http"
5
5
  require "logger"
6
6
 
7
- require File.dirname(__FILE__) + "/proxy_fetcher/version"
7
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/version"
8
8
 
9
- require File.dirname(__FILE__) + "/proxy_fetcher/exceptions"
10
- require File.dirname(__FILE__) + "/proxy_fetcher/configuration"
11
- require File.dirname(__FILE__) + "/proxy_fetcher/configuration/providers_registry"
12
- require File.dirname(__FILE__) + "/proxy_fetcher/proxy"
13
- require File.dirname(__FILE__) + "/proxy_fetcher/manager"
14
- require File.dirname(__FILE__) + "/proxy_fetcher/null_logger"
9
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/exceptions"
10
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/configuration"
11
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/configuration/providers_registry"
12
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/proxy"
13
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/manager"
14
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/null_logger"
15
15
 
16
- require File.dirname(__FILE__) + "/proxy_fetcher/utils/http_client"
17
- require File.dirname(__FILE__) + "/proxy_fetcher/utils/proxy_validator"
18
- require File.dirname(__FILE__) + "/proxy_fetcher/utils/proxy_list_validator"
19
- require File.dirname(__FILE__) + "/proxy_fetcher/client/client"
20
- require File.dirname(__FILE__) + "/proxy_fetcher/client/request"
21
- require File.dirname(__FILE__) + "/proxy_fetcher/client/proxies_registry"
16
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/utils/http_client"
17
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/utils/proxy_validator"
18
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/utils/proxy_list_validator"
19
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/client/client"
20
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/client/request"
21
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/client/proxies_registry"
22
22
 
23
- require File.dirname(__FILE__) + "/proxy_fetcher/document"
24
- require File.dirname(__FILE__) + "/proxy_fetcher/document/adapters"
25
- require File.dirname(__FILE__) + "/proxy_fetcher/document/node"
26
- require File.dirname(__FILE__) + "/proxy_fetcher/document/adapters/abstract_adapter"
27
- require File.dirname(__FILE__) + "/proxy_fetcher/document/adapters/nokogiri_adapter"
28
- require File.dirname(__FILE__) + "/proxy_fetcher/document/adapters/oga_adapter"
23
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/document"
24
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/document/adapters"
25
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/document/node"
26
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/document/adapters/abstract_adapter"
27
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/document/adapters/nokogiri_adapter"
28
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/document/adapters/oga_adapter"
29
29
 
30
30
  ##
31
31
  # Ruby / JRuby lib for managing proxies
32
32
  module ProxyFetcher
33
33
  # ProxyFetcher providers namespace
34
34
  module Providers
35
- require File.dirname(__FILE__) + "/proxy_fetcher/providers/base"
36
- require File.dirname(__FILE__) + "/proxy_fetcher/providers/free_proxy_list"
37
- require File.dirname(__FILE__) + "/proxy_fetcher/providers/free_proxy_list_ssl"
38
- require File.dirname(__FILE__) + "/proxy_fetcher/providers/gather_proxy"
39
- require File.dirname(__FILE__) + "/proxy_fetcher/providers/http_tunnel"
40
- require File.dirname(__FILE__) + "/proxy_fetcher/providers/proxy_list"
41
- require File.dirname(__FILE__) + "/proxy_fetcher/providers/xroxy"
35
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/base"
36
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/free_proxy_list"
37
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/free_proxy_list_socks"
38
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/free_proxy_list_ssl"
39
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/free_proxy_list_us"
40
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/http_tunnel"
41
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/mtpro"
42
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/proxy_list"
43
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/proxypedia"
44
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/proxyscrape_http"
45
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/proxyscrape_socks4"
46
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/proxyscrape_socks5"
47
+ require "#{File.dirname(__FILE__)}/proxy_fetcher/providers/xroxy"
42
48
  end
43
49
 
50
+ @__config_access_lock__ = Mutex.new
51
+ @__config_definition_lock__ = Mutex.new
52
+
44
53
  # Main ProxyFetcher module.
45
54
  class << self
46
55
  ##
@@ -53,12 +62,14 @@ module ProxyFetcher
53
62
  # ProxyFetcher.config
54
63
  #
55
64
  # #=> #<ProxyFetcher::Configuration:0x0000000241eec8 @user_agent="Mozilla/5.0, ...", @pool_size=10,
56
- # @client_timeout=3, @proxy_validation_timeout=3, @provider_proxies_load_timeout=30,
57
- # @http_client=ProxyFetcher::HTTPClient, @proxy_validator=ProxyFetcher::ProxyValidator,
58
- # @providers=[:free_proxy_list, ...], @adapter=ProxyFetcher::Document::NokogiriAdapter>
65
+ # @client_timeout=3, @proxy_validation_timeout=3, @provider_proxies_load_timeout=30,
66
+ # @http_client=ProxyFetcher::HTTPClient, @proxy_validator=ProxyFetcher::ProxyValidator,
67
+ # @providers=[:free_proxy_list, ...], @adapter=ProxyFetcher::Document::NokogiriAdapter>
59
68
  #
60
69
  def config
61
- @config ||= ProxyFetcher::Configuration.new
70
+ @__config_definition_lock__.synchronize do
71
+ @config ||= ProxyFetcher::Configuration.new
72
+ end
62
73
  end
63
74
 
64
75
  ##
@@ -70,7 +81,7 @@ module ProxyFetcher
70
81
  # Configuration object.
71
82
  #
72
83
  def configure
73
- yield config
84
+ @__config_access_lock__.synchronize { yield config }
74
85
  end
75
86
 
76
87
  # Returns ProxyFetcher logger instance.
@@ -41,15 +41,15 @@ module ProxyFetcher
41
41
  # @return [String]
42
42
  # response body (requested resource content)
43
43
  #
44
- def self.execute(args)
45
- new(args).execute
44
+ def self.execute(**args)
45
+ new(**args).execute
46
46
  end
47
47
 
48
48
  # Initialize new HTTP request
49
49
  #
50
50
  # @return [Request]
51
51
  #
52
- def initialize(args)
52
+ def initialize(**args)
53
53
  raise ArgumentError, "args must be a Hash!" unless args.is_a?(Hash)
54
54
 
55
55
  @url = args.fetch(:url)
@@ -39,7 +39,7 @@ module ProxyFetcher
39
39
  attr_accessor :logger
40
40
 
41
41
  # @!attribute [r] adapter
42
- # @return [Object] HTML parser adapter
42
+ # @return [#to_s] HTML parser adapter
43
43
  attr_reader :adapter
44
44
 
45
45
  # @!attribute [r] http_client
@@ -51,7 +51,7 @@ module ProxyFetcher
51
51
  attr_reader :proxy_validator
52
52
 
53
53
  # @!attribute [r] providers
54
- # @return [Array<String>, Array<Symbol>] proxy providers list to be used
54
+ # @return [Array<String, Symbol>] proxy providers list to be used
55
55
  attr_reader :providers
56
56
 
57
57
  # User-Agent string that will be used by the ProxyFetcher HTTP client (to
@@ -68,6 +68,8 @@ module ProxyFetcher
68
68
  #
69
69
  DEFAULT_ADAPTER = :nokogiri
70
70
 
71
+ @__adapter_lock__ = Mutex.new
72
+
71
73
  class << self
72
74
  # Registry for handling proxy providers.
73
75
  #
@@ -93,7 +95,7 @@ module ProxyFetcher
93
95
 
94
96
  # Returns registered providers names.
95
97
  #
96
- # @return [Array<String>, Array<Symbol>]
98
+ # @return [Array<String, Symbol>]
97
99
  # registered providers names
98
100
  #
99
101
  def registered_providers
@@ -112,7 +114,7 @@ module ProxyFetcher
112
114
 
113
115
  # Sets default configuration options
114
116
  def reset!
115
- @logger = Logger.new(STDOUT)
117
+ @logger = Logger.new($stdout)
116
118
  @user_agent = DEFAULT_USER_AGENT
117
119
  @pool_size = 10
118
120
  @client_timeout = 3
@@ -131,16 +133,18 @@ module ProxyFetcher
131
133
  end
132
134
 
133
135
  def adapter_class
134
- return @adapter_class if defined?(@adapter_class)
136
+ self.class.instance_variable_get(:@__adapter_lock__).synchronize do
137
+ return @adapter_class if defined?(@adapter_class)
135
138
 
136
- @adapter_class = ProxyFetcher::Document::Adapters.lookup(adapter)
137
- @adapter_class.setup!
138
- @adapter_class
139
+ @adapter_class = ProxyFetcher::Document::Adapters.lookup(adapter)
140
+ @adapter_class.setup!
141
+ @adapter_class
142
+ end
139
143
  end
140
144
 
141
145
  # Setups collection of providers that will be used to fetch proxies.
142
146
  #
143
- # @param value [String, Symbol, Array<String>, Array<Symbol>]
147
+ # @param value [String, Symbol, Array<String, Symbol>]
144
148
  # provider names
145
149
  #
146
150
  def providers=(value)
@@ -83,7 +83,7 @@ module ProxyFetcher
83
83
  def clear(text)
84
84
  return "" if text.nil? || text.empty?
85
85
 
86
- text.strip.gsub(/[\t]/i, "")
86
+ text.strip.gsub(/\t/i, "")
87
87
  end
88
88
  end
89
89
  end
@@ -3,6 +3,16 @@
3
3
  module ProxyFetcher
4
4
  # ProxyFetcher Manager class for interacting with proxy lists from various providers.
5
5
  class Manager
6
+ REFRESHER_LOCK = Mutex.new
7
+
8
+ class << self
9
+ def from_files(files, **options)
10
+ new(**options.merge(files: Array(files)))
11
+ end
12
+
13
+ alias from_file from_files
14
+ end
15
+
6
16
  # @!attribute [r] proxies
7
17
  # @return [Array<ProxyFetcher::Proxy>] An array of proxies
8
18
  attr_reader :proxies
@@ -14,14 +24,17 @@ module ProxyFetcher
14
24
  #
15
25
  # @return [Manager]
16
26
  #
17
- def initialize(refresh: true, validate: false, filters: {})
18
- if refresh
19
- refresh_list!(filters)
27
+ def initialize(**options)
28
+ if options.fetch(:refresh, true)
29
+ refresh_list!(options.fetch(:filters, {}))
20
30
  else
21
31
  @proxies = []
22
32
  end
23
33
 
24
- cleanup! if validate
34
+ files = Array(options.fetch(:file, options.fetch(:files, [])))
35
+ load_proxies_from_files!(files) if files&.any?
36
+
37
+ cleanup! if options.fetch(:validate, false)
25
38
  end
26
39
 
27
40
  # Update current proxy list using configured providers.
@@ -30,17 +43,17 @@ module ProxyFetcher
30
43
  #
31
44
  def refresh_list!(filters = nil)
32
45
  @proxies = []
33
-
34
46
  threads = []
35
- lock = Mutex.new
36
47
 
37
48
  ProxyFetcher.config.providers.each do |provider_name|
38
49
  threads << Thread.new do
50
+ Thread.current.report_on_exception = false
51
+
39
52
  provider = ProxyFetcher::Configuration.providers_registry.class_for(provider_name)
40
53
  provider_filters = filters && filters.fetch(provider_name.to_sym, filters)
41
54
  provider_proxies = provider.fetch_proxies!(provider_filters)
42
55
 
43
- lock.synchronize do
56
+ REFRESHER_LOCK.synchronize do
44
57
  @proxies.concat(provider_proxies)
45
58
  end
46
59
  end
@@ -89,6 +102,26 @@ module ProxyFetcher
89
102
 
90
103
  alias pop! get!
91
104
 
105
+ # Loads proxies from files.
106
+ #
107
+ # @param proxy_files [String, Array<String,Pathname>]
108
+ # file path of list of files to load
109
+ #
110
+ def load_proxies_from_files!(proxy_files)
111
+ proxy_files = Array(proxy_files)
112
+ return if proxy_files.empty?
113
+
114
+ proxy_files.each do |proxy_file|
115
+ File.foreach(proxy_file, chomp: true) do |proxy_string|
116
+ addr, port = proxy_string.split(":", 2)
117
+ port = Integer(port) if port
118
+ @proxies << Proxy.new(addr: addr, port: port)
119
+ end
120
+ end
121
+
122
+ @proxies.uniq!
123
+ end
124
+
92
125
  # Clean current proxy list from dead proxies (that doesn't respond by timeout)
93
126
  #
94
127
  # @return [Array<ProxyFetcher::Proxy>]
@@ -108,7 +108,8 @@ module ProxyFetcher
108
108
  to_proxy(*args)
109
109
  rescue StandardError => e
110
110
  ProxyFetcher.logger.warn(
111
- "Failed to build Proxy object for #{self.class.name} due to error: #{e.message}"
111
+ "Failed to build Proxy for #{self.class.name.split("::").last} " \
112
+ "due to error: #{e.message}"
112
113
  )
113
114
 
114
115
  nil
@@ -45,27 +45,6 @@ module ProxyFetcher
45
45
  #
46
46
  def parse_type(html_node)
47
47
  https = html_node.content_at("td[6]")
48
- # frozen_string_literal: true
49
- # FreeProxyList provider class.
50
- # Provider URL to fetch proxy list
51
- # [NOTE] Doesn't support filtering
52
- # Converts HTML node (entry of N tags) to <code>ProxyFetcher::Proxy</code>
53
- # object.
54
- #
55
- # @param html_node [Object]
56
- # HTML node from the <code>ProxyFetcher::Document</code> DOM model.
57
- #
58
- # @return [ProxyFetcher::Proxy]
59
- # Proxy object
60
- #
61
- # Parses HTML node to extract proxy type.
62
- #
63
- # @param html_node [Object]
64
- # HTML node from the <code>ProxyFetcher::Document</code> DOM model.
65
- #
66
- # @return [String]
67
- # Proxy type
68
- #
69
48
  https&.casecmp("yes")&.zero? ? ProxyFetcher::Proxy::HTTPS : ProxyFetcher::Proxy::HTTP
70
49
  end
71
50
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProxyFetcher
4
+ module Providers
5
+ # FreeProxyListSocks provider class.
6
+ class FreeProxyListSocks < Base
7
+ # Provider URL to fetch proxy list
8
+ def provider_url
9
+ "https://www.socks-proxy.net/"
10
+ end
11
+
12
+ # [NOTE] Doesn't support filtering
13
+ def xpath
14
+ '//table[@id="proxylisttable"]/tbody/tr'
15
+ end
16
+
17
+ # Converts HTML node (entry of N tags) to <code>ProxyFetcher::Proxy</code>
18
+ # object.
19
+ #
20
+ # @param html_node [Object]
21
+ # HTML node from the <code>ProxyFetcher::Document</code> DOM model.
22
+ #
23
+ # @return [ProxyFetcher::Proxy]
24
+ # Proxy object
25
+ #
26
+ def to_proxy(html_node)
27
+ ProxyFetcher::Proxy.new.tap do |proxy|
28
+ proxy.addr = html_node.content_at("td[1]")
29
+ proxy.port = Integer(html_node.content_at("td[2]").gsub(/^0+/, ""))
30
+ proxy.country = html_node.content_at("td[4]")
31
+ proxy.type = parse_type(html_node)
32
+ proxy.anonymity = html_node.content_at("td[6]")
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ # Parses HTML node to extract proxy type.
39
+ #
40
+ # @param html_node [Object]
41
+ # HTML node from the <code>ProxyFetcher::Document</code> DOM model.
42
+ #
43
+ # @return [String]
44
+ # Proxy type
45
+ #
46
+ def parse_type(html_node)
47
+ https = html_node.content_at("td[5]")
48
+
49
+ return ProxyFetcher::Proxy::SOCKS4 if https&.casecmp("socks4")&.zero?
50
+ return ProxyFetcher::Proxy::SOCKS5 if https&.casecmp("socks5")&.zero?
51
+
52
+ "Unknown"
53
+ end
54
+ end
55
+
56
+ ProxyFetcher::Configuration.register_provider(:free_proxy_list_socks, FreeProxyListSocks)
57
+ end
58
+ end