webshooter 0.0.3a → 0.0.4a
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.
- data/Gemfile.lock +3 -1
- data/README.txt +6 -2
- data/bin/webshooter +61 -0
- data/lib/webshooter/redirectfollower.rb +32 -3
- data/lib/webshooter/version.rb +1 -1
- data/lib/webshooter/webshotprocessor.rb +29 -9
- data/lib/webshooter.rb +2 -2
- data/webshooter.gemspec +1 -0
- metadata +33 -9
- data/bin/webshooter.rb +0 -19
data/Gemfile.lock
CHANGED
data/README.txt
CHANGED
@@ -11,10 +11,10 @@ gem install webshooter --pre
|
|
11
11
|
|
12
12
|
## From within ruby
|
13
13
|
require 'webshooter'
|
14
|
-
Webshooter.capture('http://www.jedi.be','jedi.png','
|
14
|
+
Webshooter.capture('http://www.jedi.be',{ :output => 'jedi.png', :width => '1024' , :height => '768' , :delay => '2')
|
15
15
|
|
16
16
|
## As a commandline tool
|
17
|
-
webshooter 'http://www.jedi.be'
|
17
|
+
webshooter 'http://www.jedi.be' --width=1024 --height=786 --delay=2 --output=jedi.png
|
18
18
|
|
19
19
|
# Limitations
|
20
20
|
- does not handle redirects currently
|
@@ -27,6 +27,10 @@ webshooter 'http://www.jedi.be' 'jedi.png' '1024x768'
|
|
27
27
|
This library is a compilation of various parts I found on the web
|
28
28
|
The research was done a few years ago, so unfortunatly I don't have all the references anymore
|
29
29
|
|
30
|
+
- webkit2png - http://www.paulhammond.org/webkit2png/
|
31
|
+
- http://cocoadevblog.com/webkit-screenshots-cocoa-objective-c
|
32
|
+
|
33
|
+
|
30
34
|
- Darkroom - Copyright (c) 2007 Justin Palmer.
|
31
35
|
- https://gist.github.com/34824
|
32
36
|
- https://gist.github.com/86435
|
data/bin/webshooter
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'webshooter'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
module Webshooter
|
9
|
+
class CLI
|
10
|
+
#Ruby CLI tool - http://rubylearning.com/blog/2011/01/03/how-do-i-make-a-command-line-tool-in-ruby/
|
11
|
+
def self.execute(url,options)
|
12
|
+
webshotr=Webshooter.capture(url,options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
options = {}
|
18
|
+
parser = OptionParser.new do |opts|
|
19
|
+
opts.banner = "Usage: #$0 [options] URL"
|
20
|
+
|
21
|
+
opts.on('--width=[WIDTH]', Integer, 'Force width of the screenshot') do |v|
|
22
|
+
options[:width] = v
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on('--delay=[DELAY]', Integer, "Delay") do |v|
|
26
|
+
options[:delay] = v
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on('--height=[HEIGHT]', Integer, 'Force height of screenshot') do |v|
|
30
|
+
options[:height] = v
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on('--output=[FILENAME]', String, 'Specify filename for saving') do |v|
|
34
|
+
options[:output] = v
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on_tail('--help', 'Display this message and exit') do
|
38
|
+
puts opts
|
39
|
+
exit
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.on_tail('-v', "--version", "Show version") do
|
43
|
+
puts "webshooter v"+Webshooter::VERSION
|
44
|
+
exit
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.parse!(ARGV)
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
if ARGV.size < 1
|
52
|
+
puts "You need to specify the URL as a minimum"
|
53
|
+
else
|
54
|
+
uri=ARGV.first
|
55
|
+
if (uri =~ URI::regexp).nil?
|
56
|
+
puts "You specified an invalid URL"
|
57
|
+
else
|
58
|
+
Webshooter::CLI.execute(uri, options)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
require 'net/http'
|
5
5
|
require 'net/https'
|
6
|
+
require 'nokogiri'
|
6
7
|
|
7
8
|
module Webshooter
|
8
9
|
|
@@ -27,11 +28,16 @@ class RedirectFollower
|
|
27
28
|
#http.verify_mode = OpenSSL::SSL::VERIFY_NONE # Not setting this explicitly will result in an error and the value being set anyway
|
28
29
|
end
|
29
30
|
|
31
|
+
|
30
32
|
if (uri.path=="")
|
31
|
-
request = Net::HTTP::Get.new("/")
|
33
|
+
request = Net::HTTP::Get.new("#{ '/' + (uri.query ? ('?' + uri.query) : '')}")
|
32
34
|
else
|
33
|
-
|
35
|
+
|
36
|
+
# http://intertwingly.net/blog/2006/08/19/Quack-Squared
|
37
|
+
request = Net::HTTP::Get.new(uri.path + (uri.query ? ('?' + uri.query) : '') )
|
34
38
|
end
|
39
|
+
|
40
|
+
|
35
41
|
self.response = http.start {|http| http.request(request) }
|
36
42
|
|
37
43
|
if response.kind_of?(Net::HTTPRedirection)
|
@@ -40,11 +46,34 @@ class RedirectFollower
|
|
40
46
|
|
41
47
|
puts "redirect found, headed to #{url}"
|
42
48
|
resolve
|
43
|
-
end
|
49
|
+
end
|
50
|
+
|
51
|
+
meta_link=meta_parse
|
52
|
+
if !meta_link.nil?
|
53
|
+
self.url = meta_link
|
54
|
+
self.redirect_limit -= 1
|
55
|
+
puts "metalink found, headed to #{url}"
|
56
|
+
resolve
|
57
|
+
end
|
58
|
+
|
44
59
|
return url
|
45
60
|
|
46
61
|
end
|
47
62
|
|
63
|
+
def meta_parse
|
64
|
+
# http://stackoverflow.com/questions/5003367/mechanize-how-to-follow-or-click-meta-refreshes-in-rails/5012684#5012684
|
65
|
+
html=response.body.to_s.downcase
|
66
|
+
#puts html
|
67
|
+
doc = Nokogiri::HTML(html)
|
68
|
+
meta_tag=doc.at('meta[http-equiv="refresh"]')
|
69
|
+
if !meta_tag.nil?
|
70
|
+
meta_link = meta_tag['content'][/url=(.+)/, 1]
|
71
|
+
else
|
72
|
+
meta_link=nil
|
73
|
+
end
|
74
|
+
meta_link # => "http://www.example.com/"
|
75
|
+
end
|
76
|
+
|
48
77
|
def redirect_url
|
49
78
|
if response['location'].nil?
|
50
79
|
response.body.match(/<a href=\"([^>]+)\">/i)[1]
|
data/lib/webshooter/version.rb
CHANGED
@@ -41,7 +41,7 @@ class WebShotProcessor
|
|
41
41
|
@webView.preferences.setAutosaves(false)
|
42
42
|
# Set some useful options.
|
43
43
|
@webView.preferences.setShouldPrintBackgrounds(true)
|
44
|
-
@webView.preferences.setJavaScriptCanOpenWindowsAutomatically(
|
44
|
+
@webView.preferences.setJavaScriptCanOpenWindowsAutomatically(true)
|
45
45
|
@webView.preferences.setAllowsAnimatedImages(false)
|
46
46
|
# Make sure we don't get a scroll bar.
|
47
47
|
@webView.mainFrame.frameView.setAllowsScrolling(false)
|
@@ -49,6 +49,7 @@ class WebShotProcessor
|
|
49
49
|
# This @delegate will get a message when the load completes
|
50
50
|
@delegate = SimpleLoadDelegate.alloc.init
|
51
51
|
@delegate.webshooter = self
|
52
|
+
|
52
53
|
@webView.setFrameLoadDelegate(@delegate)
|
53
54
|
|
54
55
|
# Replace the window's content @webView with the web @webView
|
@@ -56,15 +57,23 @@ class WebShotProcessor
|
|
56
57
|
@webView.release
|
57
58
|
end
|
58
59
|
|
59
|
-
def capture(uri,
|
60
|
+
def capture(uri, options )
|
61
|
+
|
62
|
+
options[:width] ||= 1024
|
63
|
+
options[:height] ||= 768
|
64
|
+
options[:output] ||= "webshot.png"
|
65
|
+
options[:delay] ||= 2
|
60
66
|
|
61
|
-
|
67
|
+
@delegate.options = options
|
68
|
+
|
69
|
+
snapshot_dimension=[ options[:width] , options[:height]]
|
62
70
|
# Tell the frame to load the URL we want
|
63
71
|
@webView.window.setContentSize(snapshot_dimension)
|
64
72
|
@webView.setFrameSize(snapshot_dimension)
|
65
73
|
|
66
74
|
final_link = RedirectFollower.new(uri).resolve
|
67
75
|
|
76
|
+
#puts "final link = #{final_link}"
|
68
77
|
myURI = URI.parse(final_link)
|
69
78
|
|
70
79
|
#Allow all https certificates
|
@@ -73,8 +82,6 @@ class WebShotProcessor
|
|
73
82
|
#puts "Getting ready for the loadRequest"+uri
|
74
83
|
@webView.mainFrame.loadRequest(NewNSURLRequest.requestWithURL(OSX::NSURL.URLWithString(final_link)))
|
75
84
|
|
76
|
-
#Wait for some pages to terminate
|
77
|
-
sleep 2
|
78
85
|
#
|
79
86
|
# Run the main event loop until the frame loads
|
80
87
|
@timeout=false
|
@@ -93,7 +100,6 @@ class WebShotProcessor
|
|
93
100
|
view.window.orderFront(nil)
|
94
101
|
#view.window.display
|
95
102
|
|
96
|
-
#puts "-------------------------------------------------"
|
97
103
|
#puts "We got success"
|
98
104
|
@docview=view.mainFrame.frameView.documentView
|
99
105
|
|
@@ -125,7 +131,8 @@ class WebShotProcessor
|
|
125
131
|
if view.bounds.size.height < 300000
|
126
132
|
view.lockFocus
|
127
133
|
bitmap = OSX::NSBitmapImageRep.alloc.initWithFocusedViewRect(view.bounds)
|
128
|
-
bitmap.representationUsingType_properties(OSX::NSPNGFileType, nil).writeToFile_atomically(
|
134
|
+
bitmap.representationUsingType_properties(OSX::NSPNGFileType, nil).writeToFile_atomically(options[:output], true)
|
135
|
+
logger.info( "Webshot for #{final_link} => '#{options[:output]}' ")
|
129
136
|
bitmap.release
|
130
137
|
view.unlockFocus
|
131
138
|
|
@@ -136,7 +143,7 @@ class WebShotProcessor
|
|
136
143
|
end
|
137
144
|
|
138
145
|
upon_failure do |error, logger|
|
139
|
-
logger.warn("Unable to load URI: #{
|
146
|
+
logger.warn("Unable to load URI: #{final_link} (#{error})")
|
140
147
|
end
|
141
148
|
|
142
149
|
|
@@ -166,7 +173,7 @@ class WebShotProcessor
|
|
166
173
|
|
167
174
|
class SimpleLoadDelegate < OSX::NSObject
|
168
175
|
|
169
|
-
attr_accessor :webshooter
|
176
|
+
attr_accessor :webshooter, :options
|
170
177
|
|
171
178
|
def stopLoop
|
172
179
|
mainLoop=OSX.CFRunLoopGetMain
|
@@ -176,10 +183,15 @@ class WebShotProcessor
|
|
176
183
|
end
|
177
184
|
|
178
185
|
def webView_didFinishLoadForFrame(sender, frame)
|
186
|
+
|
179
187
|
#This did the trick, we have to wait for the right frame to load, not other frames
|
180
188
|
if (frame == sender.mainFrame)
|
181
189
|
then
|
182
190
|
#puts "Finish Load For Frame"
|
191
|
+
#sleep 10
|
192
|
+
#puts "#{ @options[:delay]}"
|
193
|
+
sleep @options[:delay]
|
194
|
+
#puts "we got a finish"
|
183
195
|
@webshooter.load_success = true;
|
184
196
|
|
185
197
|
stopLoop
|
@@ -189,8 +201,15 @@ class WebShotProcessor
|
|
189
201
|
end
|
190
202
|
end
|
191
203
|
|
204
|
+
# keeping track of all content being loaded
|
205
|
+
# http://www.opensubscriber.com/message/webkitsdk-dev@lists.apple.com/2978556.html
|
206
|
+
def webView_didCommitLoadForFrame(sender,frame)
|
207
|
+
#puts "we got a commit"
|
208
|
+
end
|
209
|
+
|
192
210
|
def webView_didFailLoadWithError_forFrame(webview, load_error, frame)
|
193
211
|
|
212
|
+
#puts "we got a failed"
|
194
213
|
#This is trick # 2
|
195
214
|
#We have to catch this stupid error
|
196
215
|
if (load_error.code == OSX::NSURLErrorCancelled)
|
@@ -208,6 +227,7 @@ class WebShotProcessor
|
|
208
227
|
end
|
209
228
|
|
210
229
|
def webView_didFailProvisionalLoadWithError_forFrame(webview, load_error, frame)
|
230
|
+
puts "we got a provisional load"
|
211
231
|
if (load_error.code == OSX::NSURLErrorCancelled)
|
212
232
|
then
|
213
233
|
#pp "WARN: did Fail PROVISIONAL LOAD WITH ERROR For Frame"
|
data/lib/webshooter.rb
CHANGED
@@ -5,9 +5,9 @@ require 'webshooter/webshotprocessor'
|
|
5
5
|
|
6
6
|
module Webshooter
|
7
7
|
class Webshooter
|
8
|
-
def self.capture(uri,
|
8
|
+
def self.capture(uri, options )
|
9
9
|
webProcessor=WebShotProcessor.new
|
10
|
-
webProcessor.capture(uri,
|
10
|
+
webProcessor.capture(uri,options)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
data/webshooter.gemspec
CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
|
17
17
|
s.add_development_dependency "bundler", ">= 1.0.0"
|
18
18
|
#s.add_dependency "responsalizr", "~>1.0.2"
|
19
|
+
s.add_dependency "nokogiri", "~>1.4.4"
|
19
20
|
|
20
21
|
s.files = `git ls-files`.split("\n")
|
21
22
|
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
metadata
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webshooter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 58
|
5
|
+
prerelease: 5
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
|
9
|
+
- 4
|
10
|
+
- a
|
11
|
+
version: 0.0.4a
|
10
12
|
platform: ruby
|
11
13
|
authors:
|
12
14
|
- Patrick Debois
|
@@ -18,24 +20,42 @@ date: 2011-02-20 00:00:00 +01:00
|
|
18
20
|
default_executable:
|
19
21
|
dependencies:
|
20
22
|
- !ruby/object:Gem::Dependency
|
21
|
-
|
23
|
+
prerelease: false
|
24
|
+
type: :development
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
22
27
|
requirements:
|
23
28
|
- - ">="
|
24
29
|
- !ruby/object:Gem::Version
|
30
|
+
hash: 23
|
25
31
|
segments:
|
26
32
|
- 1
|
27
33
|
- 0
|
28
34
|
- 0
|
29
35
|
version: 1.0.0
|
30
|
-
requirement: *id001
|
31
36
|
name: bundler
|
37
|
+
version_requirements: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
32
39
|
prerelease: false
|
33
|
-
type: :
|
40
|
+
type: :runtime
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: 15
|
47
|
+
segments:
|
48
|
+
- 1
|
49
|
+
- 4
|
50
|
+
- 4
|
51
|
+
version: 1.4.4
|
52
|
+
name: nokogiri
|
53
|
+
version_requirements: *id002
|
34
54
|
description: This library allows you to create webshots using webkit on MacOSX. A webshot is a screenshot taken inside the browser. The advantage of this library is that it is headless and gives you the real view not a parsed view
|
35
55
|
email:
|
36
56
|
- patrick.debois@jedi.be
|
37
57
|
executables:
|
38
|
-
- webshooter
|
58
|
+
- webshooter
|
39
59
|
extensions: []
|
40
60
|
|
41
61
|
extra_rdoc_files: []
|
@@ -46,7 +66,7 @@ files:
|
|
46
66
|
- Gemfile.lock
|
47
67
|
- README.txt
|
48
68
|
- Rakefile
|
49
|
-
- bin/webshooter
|
69
|
+
- bin/webshooter
|
50
70
|
- lib/webshooter.rb
|
51
71
|
- lib/webshooter/newnsurlrequest.rb
|
52
72
|
- lib/webshooter/redirectfollower.rb
|
@@ -68,16 +88,20 @@ rdoc_options: []
|
|
68
88
|
require_paths:
|
69
89
|
- lib
|
70
90
|
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
71
92
|
requirements:
|
72
93
|
- - ">="
|
73
94
|
- !ruby/object:Gem::Version
|
95
|
+
hash: 3
|
74
96
|
segments:
|
75
97
|
- 0
|
76
98
|
version: "0"
|
77
99
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
78
101
|
requirements:
|
79
102
|
- - ">="
|
80
103
|
- !ruby/object:Gem::Version
|
104
|
+
hash: 23
|
81
105
|
segments:
|
82
106
|
- 1
|
83
107
|
- 3
|
@@ -86,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
110
|
requirements: []
|
87
111
|
|
88
112
|
rubyforge_project: webshooter
|
89
|
-
rubygems_version: 1.
|
113
|
+
rubygems_version: 1.5.2
|
90
114
|
signing_key:
|
91
115
|
specification_version: 3
|
92
116
|
summary: Create webshot using webkit on MacOSX
|
data/bin/webshooter.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
require 'webshooter'
|
6
|
-
|
7
|
-
module Webshooter
|
8
|
-
class CLI
|
9
|
-
#Ruby CLI tool - http://rubylearning.com/blog/2011/01/03/how-do-i-make-a-command-line-tool-in-ruby/
|
10
|
-
def self.execute(args)
|
11
|
-
url=args[0]
|
12
|
-
filename=args[1]
|
13
|
-
size=args[2]
|
14
|
-
webshotr=Webshooter.capture(url, filename, size )
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
Webshooter::CLI.execute(ARGV)
|