pincers 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/pincers/chenso/backend.rb +162 -0
- data/lib/pincers/chenso/browsing_context.rb +76 -0
- data/lib/pincers/chenso/browsing_manager.rb +67 -0
- data/lib/pincers/chenso/factory.rb +27 -0
- data/lib/pincers/chenso/html_form_request.rb +7 -0
- data/lib/pincers/chenso/html_page_request.rb +27 -0
- data/lib/pincers/{backend/base.rb → core/base_backend.rb} +18 -8
- data/lib/pincers/{factories/base.rb → core/base_factory.rb} +2 -2
- data/lib/pincers/core/helpers/form.rb +106 -0
- data/lib/pincers/core/{query.rb → helpers/query.rb} +3 -4
- data/lib/pincers/core/replicas/form.rb +43 -0
- data/lib/pincers/core/replicas/link.rb +18 -0
- data/lib/pincers/core/root_context.rb +25 -6
- data/lib/pincers/core/search_context.rb +24 -3
- data/lib/pincers/errors.rb +4 -1
- data/lib/pincers/extension/labs.rb +3 -0
- data/lib/pincers/factory.rb +9 -4
- data/lib/pincers/http/base_document.rb +20 -0
- data/lib/pincers/http/client.rb +134 -0
- data/lib/pincers/{support → http}/cookie.rb +1 -1
- data/lib/pincers/{support → http}/cookie_jar.rb +4 -3
- data/lib/pincers/http/errors.rb +26 -0
- data/lib/pincers/http/request.rb +62 -0
- data/lib/pincers/http/response_document.rb +24 -0
- data/lib/pincers/http/session.rb +99 -0
- data/lib/pincers/http/utils.rb +43 -0
- data/lib/pincers/nokogiri/backend.rb +151 -0
- data/lib/pincers/{factories/nokogiri.rb → nokogiri/factory.rb} +5 -5
- data/lib/pincers/version.rb +1 -1
- data/lib/pincers/{backend/webdriver.rb → webdriver/backend.rb} +22 -31
- data/lib/pincers/{factories/webdriver.rb → webdriver/factory.rb} +5 -5
- data/lib/pincers/webdriver/http_document.rb +23 -0
- metadata +42 -13
- data/lib/pincers/backend/nokogiri.rb +0 -66
- data/lib/pincers/core/download.rb +0 -14
- data/lib/pincers/support/http_client.rb +0 -123
data/lib/pincers/version.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'selenium-webdriver'
|
2
|
+
require 'pincers/core/base_backend'
|
3
|
+
require 'pincers/http/client'
|
4
|
+
require 'pincers/webdriver/http_document'
|
5
5
|
|
6
|
-
module Pincers::
|
7
|
-
|
8
|
-
class Webdriver < Base
|
6
|
+
module Pincers::Webdriver
|
7
|
+
class Backend < Pincers::Core::BaseBackend
|
9
8
|
|
10
9
|
DOM_PROPERTIES = [:selected, :disabled, :checked, :value, :required]
|
11
10
|
|
12
|
-
|
11
|
+
attr_reader :driver
|
12
|
+
|
13
|
+
alias :document :driver
|
13
14
|
|
14
15
|
def initialize(_driver)
|
15
|
-
|
16
|
+
@driver = _driver
|
16
17
|
end
|
17
18
|
|
18
19
|
def javascript_enabled?
|
@@ -143,6 +144,11 @@ module Pincers::Backend
|
|
143
144
|
actions.drag_and_drop(_element, _on).perform
|
144
145
|
end
|
145
146
|
|
147
|
+
def submit_form(_element)
|
148
|
+
_element = ensure_element _element
|
149
|
+
_element.submit
|
150
|
+
end
|
151
|
+
|
146
152
|
def switch_to_frame(_element)
|
147
153
|
driver.switch_to.frame _element
|
148
154
|
end
|
@@ -151,10 +157,13 @@ module Pincers::Backend
|
|
151
157
|
driver.switch_to.default_content
|
152
158
|
end
|
153
159
|
|
154
|
-
def
|
155
|
-
|
156
|
-
|
157
|
-
|
160
|
+
def as_http_client
|
161
|
+
session = Pincers::Http::Session.new
|
162
|
+
session.headers['User-Agent'] = user_agent
|
163
|
+
session.proxy = proxy_address
|
164
|
+
driver.manage.all_cookies.each { |c| session.cookie_jar.set c }
|
165
|
+
|
166
|
+
Pincers::Http::Client.new session, HttpDocument.new(self)
|
158
167
|
end
|
159
168
|
|
160
169
|
private
|
@@ -200,16 +209,6 @@ module Pincers::Backend
|
|
200
209
|
_element
|
201
210
|
end
|
202
211
|
|
203
|
-
def as_http_client
|
204
|
-
Pincers::Support::HttpClient.new({
|
205
|
-
proxy: proxy_address,
|
206
|
-
cookies: cookie_jar,
|
207
|
-
headers: {
|
208
|
-
'User-Agent' => user_agent
|
209
|
-
}
|
210
|
-
})
|
211
|
-
end
|
212
|
-
|
213
212
|
def user_agent
|
214
213
|
driver.execute_script("return navigator.userAgent;")
|
215
214
|
end
|
@@ -218,13 +217,5 @@ module Pincers::Backend
|
|
218
217
|
proxy = driver.capabilities.proxy
|
219
218
|
proxy.nil? ? nil : (proxy.http || proxy.ssl)
|
220
219
|
end
|
221
|
-
|
222
|
-
def cookie_jar
|
223
|
-
jar = Pincers::Support::CookieJar.new
|
224
|
-
driver.manage.all_cookies.each { |c| jar.set c }
|
225
|
-
jar
|
226
|
-
end
|
227
|
-
|
228
220
|
end
|
229
|
-
|
230
221
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'pincers/
|
2
|
-
require 'pincers/backend
|
1
|
+
require 'pincers/core/base_factory'
|
2
|
+
require 'pincers/webdriver/backend'
|
3
3
|
|
4
|
-
module Pincers::
|
5
|
-
class
|
4
|
+
module Pincers::Webdriver
|
5
|
+
class Factory < Pincers::Core::BaseFactory
|
6
6
|
|
7
7
|
DEFAULT_SETUP = {
|
8
8
|
page_timeout: 60000
|
@@ -17,7 +17,7 @@ module Pincers::Factories
|
|
17
17
|
setup_driver driver, _options
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
Pincers::Webdriver::Backend.new driver
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'pincers/http/utils'
|
2
|
+
|
3
|
+
module Pincers::Webdriver
|
4
|
+
class HttpDocument
|
5
|
+
|
6
|
+
def initialize(_backend)
|
7
|
+
@backend = _backend
|
8
|
+
end
|
9
|
+
|
10
|
+
def uri
|
11
|
+
Pincers::Http::Utils.parse_uri @backend.document_url
|
12
|
+
end
|
13
|
+
|
14
|
+
def content_type
|
15
|
+
'text/html'
|
16
|
+
end
|
17
|
+
|
18
|
+
def content
|
19
|
+
@backend
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pincers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ignacio Baixas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -206,6 +206,20 @@ dependencies:
|
|
206
206
|
- - ~>
|
207
207
|
- !ruby/object:Gem::Version
|
208
208
|
version: '1.6'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: webmock
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ~>
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '1.22'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ~>
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '1.22'
|
209
223
|
description: Web automation DSL on top of webdriver and nokogiri
|
210
224
|
email:
|
211
225
|
- ignacio@platan.us
|
@@ -214,12 +228,19 @@ extensions: []
|
|
214
228
|
extra_rdoc_files: []
|
215
229
|
files:
|
216
230
|
- lib/pincers.rb
|
217
|
-
- lib/pincers/backend
|
218
|
-
- lib/pincers/
|
219
|
-
- lib/pincers/
|
231
|
+
- lib/pincers/chenso/backend.rb
|
232
|
+
- lib/pincers/chenso/browsing_context.rb
|
233
|
+
- lib/pincers/chenso/browsing_manager.rb
|
234
|
+
- lib/pincers/chenso/factory.rb
|
235
|
+
- lib/pincers/chenso/html_form_request.rb
|
236
|
+
- lib/pincers/chenso/html_page_request.rb
|
237
|
+
- lib/pincers/core/base_backend.rb
|
238
|
+
- lib/pincers/core/base_factory.rb
|
220
239
|
- lib/pincers/core/cookies.rb
|
221
|
-
- lib/pincers/core/
|
222
|
-
- lib/pincers/core/query.rb
|
240
|
+
- lib/pincers/core/helpers/form.rb
|
241
|
+
- lib/pincers/core/helpers/query.rb
|
242
|
+
- lib/pincers/core/replicas/form.rb
|
243
|
+
- lib/pincers/core/replicas/link.rb
|
223
244
|
- lib/pincers/core/root_context.rb
|
224
245
|
- lib/pincers/core/search_context.rb
|
225
246
|
- lib/pincers/css/parser.rb
|
@@ -228,16 +249,24 @@ files:
|
|
228
249
|
- lib/pincers/extension/actions.rb
|
229
250
|
- lib/pincers/extension/labs.rb
|
230
251
|
- lib/pincers/extension/queries.rb
|
231
|
-
- lib/pincers/factories/base.rb
|
232
|
-
- lib/pincers/factories/nokogiri.rb
|
233
|
-
- lib/pincers/factories/webdriver.rb
|
234
252
|
- lib/pincers/factory.rb
|
253
|
+
- lib/pincers/http/base_document.rb
|
254
|
+
- lib/pincers/http/client.rb
|
255
|
+
- lib/pincers/http/cookie.rb
|
256
|
+
- lib/pincers/http/cookie_jar.rb
|
257
|
+
- lib/pincers/http/errors.rb
|
258
|
+
- lib/pincers/http/request.rb
|
259
|
+
- lib/pincers/http/response_document.rb
|
260
|
+
- lib/pincers/http/session.rb
|
261
|
+
- lib/pincers/http/utils.rb
|
262
|
+
- lib/pincers/nokogiri/backend.rb
|
263
|
+
- lib/pincers/nokogiri/factory.rb
|
235
264
|
- lib/pincers/support/configuration.rb
|
236
|
-
- lib/pincers/support/cookie.rb
|
237
|
-
- lib/pincers/support/cookie_jar.rb
|
238
|
-
- lib/pincers/support/http_client.rb
|
239
265
|
- lib/pincers/support/xpath_builder.rb
|
240
266
|
- lib/pincers/version.rb
|
267
|
+
- lib/pincers/webdriver/backend.rb
|
268
|
+
- lib/pincers/webdriver/factory.rb
|
269
|
+
- lib/pincers/webdriver/http_document.rb
|
241
270
|
homepage: https://github.com/platanus/pincers
|
242
271
|
licenses:
|
243
272
|
- MIT
|
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'pincers/backend/base'
|
2
|
-
|
3
|
-
module Pincers::Backend
|
4
|
-
|
5
|
-
class Nokogiri < Base
|
6
|
-
|
7
|
-
BOOL_PROPERTIES = [:selected, :disabled, :checked, :required]
|
8
|
-
|
9
|
-
def document_root
|
10
|
-
[document]
|
11
|
-
end
|
12
|
-
|
13
|
-
def document_title
|
14
|
-
document.title
|
15
|
-
end
|
16
|
-
|
17
|
-
def close_document
|
18
|
-
# no closing needed
|
19
|
-
end
|
20
|
-
|
21
|
-
def search_by_css(_element, _selector, _limit)
|
22
|
-
# nokogiri does not do any query level optimization when searching just one node
|
23
|
-
_element.css _selector
|
24
|
-
end
|
25
|
-
|
26
|
-
def search_by_xpath(_element, _selector, _limit)
|
27
|
-
# nokogiri does not do any query level optimization when searching just one node
|
28
|
-
_element.xpath _selector
|
29
|
-
end
|
30
|
-
|
31
|
-
def extract_element_tag(_element)
|
32
|
-
_element.name
|
33
|
-
end
|
34
|
-
|
35
|
-
def extract_element_text(_element)
|
36
|
-
_element.content
|
37
|
-
end
|
38
|
-
|
39
|
-
def extract_element_html(_element)
|
40
|
-
_element.to_html
|
41
|
-
end
|
42
|
-
|
43
|
-
def extract_element_attribute(_element, _name)
|
44
|
-
_name = _name.to_sym
|
45
|
-
value = _element[_name]
|
46
|
-
|
47
|
-
if BOOL_PROPERTIES.include? _name
|
48
|
-
value = !value.nil?
|
49
|
-
elsif _name == :value
|
50
|
-
value = checkbox_value_fix _element, value
|
51
|
-
end
|
52
|
-
|
53
|
-
value
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def checkbox_value_fix(_element, _value)
|
59
|
-
if _value.nil? and _element.name.downcase == 'input' and ['checkbox', 'radio'].include? _element[:type].downcase
|
60
|
-
'on'
|
61
|
-
else _value end
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module Pincers::Core
|
2
|
-
|
3
|
-
class Download < Struct.new(:mime, :data)
|
4
|
-
|
5
|
-
def self.from_http_response(_response)
|
6
|
-
self.new _response['Content-Type'] || 'text/plain', _response.body
|
7
|
-
end
|
8
|
-
|
9
|
-
def store(_path)
|
10
|
-
File.write _path, data
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
@@ -1,123 +0,0 @@
|
|
1
|
-
require "uri"
|
2
|
-
require "pincers/support/cookie_jar"
|
3
|
-
|
4
|
-
module Pincers::Support
|
5
|
-
class HttpClient
|
6
|
-
|
7
|
-
class HttpRequestError < StandardError
|
8
|
-
extend Forwardable
|
9
|
-
|
10
|
-
def_delegators :@response, :code, :body
|
11
|
-
|
12
|
-
attr_reader :response
|
13
|
-
|
14
|
-
def initialize(_response)
|
15
|
-
@response = _response
|
16
|
-
super _response.message
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class MaximumRedirectsError < StandardError
|
21
|
-
def initialize
|
22
|
-
super 'Redirection loop detected!'
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
attr_reader :proxy_addr, :proxy_port, :cookies
|
27
|
-
|
28
|
-
def initialize(_options={})
|
29
|
-
if _options[:proxy]
|
30
|
-
@proxy_addr, @proxy_port = _options[:proxy].split ':'
|
31
|
-
end
|
32
|
-
|
33
|
-
@cookies = if _options[:cookies]
|
34
|
-
_options[:cookies].copy
|
35
|
-
else
|
36
|
-
CookieJar.new
|
37
|
-
end
|
38
|
-
|
39
|
-
@default_headers = _options[:headers]
|
40
|
-
end
|
41
|
-
|
42
|
-
def get(_url, _query={}, _headers={})
|
43
|
-
# TODO: append query string?
|
44
|
-
perform_request Net::HTTP::Get, URI(_url), _headers
|
45
|
-
end
|
46
|
-
|
47
|
-
def post(_url, _data, _headers={})
|
48
|
-
perform_request Net::HTTP::Post, URI(_url), _headers do |req|
|
49
|
-
req.body = prepare_data(_data)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def put(_url, _data, _headers={})
|
54
|
-
perform_request Net::HTTP::Put, URI(_url), _headers do |req|
|
55
|
-
req.body = prepare_data(_data)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def delete(_url)
|
60
|
-
perform_request Net::HTTP::Delete, URI(_url), _headers
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def perform_request(_req_type, _uri, _headers, _limit=10)
|
66
|
-
|
67
|
-
raise MaximumRedirectsError.new if _limit == 0
|
68
|
-
|
69
|
-
request = _req_type.new(_uri.request_uri.empty? ? '/' : _uri.request_uri)
|
70
|
-
build_headers(request, _headers)
|
71
|
-
set_cookies(request, _uri)
|
72
|
-
yield request if block_given?
|
73
|
-
|
74
|
-
response = build_client(_uri).request request
|
75
|
-
|
76
|
-
case response
|
77
|
-
when Net::HTTPSuccess then
|
78
|
-
update_cookies(_uri, response)
|
79
|
-
response
|
80
|
-
when Net::HTTPRedirection then
|
81
|
-
location = response['location']
|
82
|
-
perform_request(_req_type, URI.parse(location), _headers, _limit - 1)
|
83
|
-
else
|
84
|
-
handle_error_response response
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def build_client(uri)
|
89
|
-
client = Net::HTTP.new uri.host, uri.port || 80, proxy_addr, proxy_port
|
90
|
-
client.use_ssl = true if uri.scheme == 'https'
|
91
|
-
client.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
92
|
-
client
|
93
|
-
end
|
94
|
-
|
95
|
-
def handle_error_response(_response)
|
96
|
-
raise HttpRequestError.new _response
|
97
|
-
end
|
98
|
-
|
99
|
-
def prepare_data(_data)
|
100
|
-
if _data.is_a? Hash
|
101
|
-
_data.keys.map { |k| "#{k}=#{_data[k]}" }.join '&'
|
102
|
-
else _data end
|
103
|
-
end
|
104
|
-
|
105
|
-
def build_headers(_request, _headers)
|
106
|
-
copy_headers _request, @default_headers if @default_headers
|
107
|
-
copy_headers _request, _headers
|
108
|
-
end
|
109
|
-
|
110
|
-
def set_cookies(_request, _uri)
|
111
|
-
_request['Cookie'] = @cookies.for_origin_as_header _uri
|
112
|
-
end
|
113
|
-
|
114
|
-
def update_cookies(_uri, _response)
|
115
|
-
cookies = _response.get_fields('set-cookie')
|
116
|
-
cookies.each { |raw| @cookies.set_raw _uri, raw } if cookies
|
117
|
-
end
|
118
|
-
|
119
|
-
def copy_headers(_request, _headers)
|
120
|
-
_headers.keys.each { |k| _request[k] = _headers[k] }
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|