auto-bidder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 hoverlover
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,29 @@
1
+ # AutoBidder: Win without trying
2
+
3
+ This library places bids on online auction sites for you automatically while you do other important things, like walking your dog.
4
+
5
+ ## Installing
6
+
7
+ gem install auto-bidder
8
+
9
+ ## Usage
10
+
11
+ AutoBidder is intended to be ran from the command line:
12
+
13
+ Chad-Boyds-iMac:~ cboyd$ auto-bidder --help
14
+ Usage: auto-bidder [options] URL
15
+ -v, --verbose Be more verbose
16
+ -x, --max-price PRICE Maximum price you are willing to pay for the auction item
17
+ -n, --min-price [PRICE] Minimum price the auction item must reach before bidding starts
18
+ -c, --bid-cost COST How much each bid actually costs you
19
+ -u, --username USER Username of your account for the auction site
20
+ -s, --bid-seconds [SECONDS] How many seconds remaining on the clock before a bid is placed
21
+ -h, --help Display this screen
22
+
23
+ It is a gem, though. So I suppose you could use it within your own project.
24
+
25
+ AutoBidder works by utilizing [Watir](http://watir.com), an open-source library for automating web browsers. The AutoBidder library will launch a Safari window and connect to the URL you supply on the command line.
26
+
27
+ ## Notes
28
+
29
+ **Watir** supports IE, Firefox, Safari and Chrome. AutoBidder uses Safari only, however. Feel free to fork this project and implement any or all of the other browsers if you wish.
data/bin/auto-bidder ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'auto_bidder'
@@ -0,0 +1,115 @@
1
+ require 'safariwatir'
2
+ require 'optparse'
3
+ require 'auto_bidder/auction_interface'
4
+ require 'auto_bidder/bigdeal'
5
+ require 'auto_bidder/browser_interface'
6
+ require 'logger'
7
+ require 'uri'
8
+
9
+ class AutoBidder
10
+ def initialize(url, options)
11
+ @num_bids = 0
12
+
13
+ # Glean the TLD name from the host and use it to create the auction interface
14
+ host = URI.parse(url).host
15
+ begin
16
+ @auction_interface = Module.const_get(host.split(".")[-2].capitalize).new(url, options)
17
+ rescue NameError
18
+ $log.fatal "Auction site #{host} not supported"
19
+ end
20
+ end
21
+
22
+ def start
23
+ @auction_interface.connect_to_auction
24
+ @auction_interface.start_monitoring
25
+ end
26
+ end
27
+
28
+ def parse_command_line
29
+ # This hash will hold all of the options
30
+ # parsed from the command-line by
31
+ # OptionParser.
32
+ options = {}
33
+
34
+ optparse = OptionParser.new do|opts|
35
+ # Set a banner, displayed at the top
36
+ # of the help screen.
37
+ opts.banner = "Usage: auto-bidder [options] URL"
38
+
39
+ # Define the options, and what they do
40
+ options[:verbose] = false
41
+ opts.on('-v', '--verbose', 'Be more verbose') do
42
+ options[:verbose] = true
43
+ end
44
+
45
+ opts.on("-x", "--max-price PRICE", Float, 'Maximum price you are willing to pay for the auction item') do |max_price|
46
+ options[:max_price] = max_price
47
+ end
48
+
49
+ opts.on("-n", "--min-price [PRICE]", Float, 'Minimum price the auction item must reach before bidding starts') do |min_price|
50
+ options[:min_price] = min_price || 0.0
51
+ end
52
+
53
+ opts.on("-c", "--bid-cost COST", Float, 'How much each bid actually costs you') do |bid_cost|
54
+ options[:bid_cost] = bid_cost
55
+ end
56
+
57
+ opts.on("-u", "--username USER", 'Username of your account for the auction site') do |username|
58
+ options[:username] = username
59
+ end
60
+
61
+ opts.on("-s", "--bid-seconds [SECONDS]", Integer, 'How many seconds remaining on the clock before a bid is placed') do |bid_secs|
62
+ options[:bid_secs] = bid_secs || 1
63
+ end
64
+
65
+ # This displays the help screen, all programs are
66
+ # assumed to have this option.
67
+ opts.on( '-h', '--help', 'Display this screen' ) do
68
+ puts opts
69
+ exit
70
+ end
71
+ end
72
+
73
+ # Parse the command-line. Remember there are two forms
74
+ # of the parse method. The 'parse' method simply parses
75
+ # ARGV, while the 'parse!' method parses ARGV and removes
76
+ # any options found there, as well as any parameters for
77
+ # the options. What's left is the list of files to resize.
78
+ optparse.parse! ARGV
79
+
80
+ ensure_option_is_present options, :max_price, optparse
81
+ ensure_option_is_present options, :bid_cost, optparse
82
+ ensure_option_is_present options, :username, optparse
83
+
84
+ url = ARGV[0]
85
+ unless url
86
+ puts "URL must be given"
87
+ puts optparse
88
+ exit 1
89
+ end
90
+
91
+ ARGV.clear
92
+
93
+ if options[:username]
94
+ print "Auction site password:"
95
+ options[:password] = gets.chomp
96
+ end
97
+
98
+ $log = Logger.new(STDOUT)
99
+ $log.level = options[:verbose] ? Logger::DEBUG : Logger::INFO
100
+
101
+ $log.debug "Verbose logging turned on" if $log.debug?
102
+
103
+ [url, options]
104
+ end
105
+
106
+ def ensure_option_is_present(options, name, parser)
107
+ if !options.has_key? name
108
+ puts "Option #{name} is required"
109
+ puts parser
110
+ exit 1
111
+ end
112
+ end
113
+
114
+ url, options = parse_command_line
115
+ AutoBidder.new(url, options).start
@@ -0,0 +1,112 @@
1
+ module AuctionInterface
2
+
3
+ def start_monitoring
4
+ while true do
5
+ reload_if_necessary
6
+
7
+ @hours = hours
8
+ @mins = mins
9
+ @secs = secs
10
+ print_stats
11
+
12
+ if @hours == 0 && @mins == 0 && @secs == @bid_secs && ok_to_bid
13
+ place_bid
14
+ sleep 10
15
+ end
16
+ end
17
+ end
18
+
19
+ # --------------- #
20
+ # Private methods #
21
+ # --------------- #
22
+ def ok_to_bid
23
+ current_price = get_current_price
24
+ current_price >= @min_price && ((@num_bids + 1) * @bid_cost + current_price) <= @max_price
25
+ end
26
+
27
+ def reload_if_necessary
28
+ # Reload every 8-10 minutes so the website doesn't think we've gone idle. If @secs is 5 or less
29
+ # put off the reload so we don't accidentally miss a bid opportunity.
30
+ if (Time.now.to_i - @last_reload) / 60 >= @next_reload_in && @secs > 10
31
+ @browser.reload
32
+ recalculate_next_reload_time
33
+ end
34
+ end
35
+
36
+ def hours
37
+ begin
38
+ get_hours
39
+ rescue
40
+ $log.error "Could not find hours element"
41
+ @browser.reload
42
+ -1
43
+ end
44
+ end
45
+
46
+ def mins
47
+ begin
48
+ get_mins
49
+ rescue
50
+ $log.error "Could not find minutes element"
51
+ @browser.reload
52
+ -1
53
+ end
54
+ end
55
+
56
+ def secs
57
+ begin
58
+ get_secs
59
+ rescue
60
+ $log.info "Could not find seconds element"
61
+ @browser.reload
62
+ -1
63
+ end
64
+ end
65
+
66
+ def recalculate_next_reload_time
67
+ @next_reload_in = (rand(3) + 8)
68
+ end
69
+
70
+ def connect_to_auction
71
+ sign_in unless signed_in?
72
+
73
+ @last_reload = Time.now.to_i
74
+ recalculate_next_reload_time
75
+ end
76
+
77
+ def place_bid
78
+ $log.info <<-BIDDING
79
+ \n=======================================
80
+ PLACING BID
81
+ #{Time.now}
82
+ =======================================
83
+ BIDDING
84
+
85
+ begin
86
+ execute_bid
87
+ @num_bids += 1
88
+
89
+ # The server knows we're still here because we just placed a bid, so reset the next reload time.
90
+ recalculate_next_reload_time
91
+ rescue
92
+ $log.error "Error while placing bid!"
93
+ end
94
+ end
95
+
96
+ def print_stats
97
+ @last_debug ||= Time.now.to_i
98
+
99
+ # print debug every 10 seconds
100
+ if Time.now.to_i - @last_debug > 10
101
+ begin
102
+ $log.debug %(#{Time.now.strftime "%m/%d/%Y %H:%M:%S"} - #{"%02d" % @hours}:#{"%02d" % @mins}:#{"%02d" % @secs}, #{get_formatted_price})
103
+ rescue => e
104
+ $log.error "Could not print debug statement\n#{e.backtrace.join("\n")}"
105
+ end
106
+ @last_debug = Time.now.to_i
107
+ end
108
+
109
+ sleep 0.01
110
+ end
111
+ private :ok_to_bid, :reload_if_necessary, :hours, :mins, :secs, :recalculate_next_reload_time, :place_bid, :print_stats
112
+ end
@@ -0,0 +1,53 @@
1
+ class Bigdeal
2
+ include AuctionInterface
3
+
4
+ def initialize(url, options)
5
+ @auction_url = url
6
+ @auction_id = @auction_url.match(/([\d]+\Z)/)[0]
7
+ @browser = BrowserInterface.new @auction_url
8
+
9
+ @max_price = options[:max_price]
10
+ @min_price = options[:min_price]
11
+ @bid_cost = options[:bid_cost]
12
+ @bid_secs = options[:bid_secs]
13
+ @username = options[:username]
14
+ @password = options[:password]
15
+
16
+ @num_bids = 0
17
+ end
18
+
19
+ def get_current_price
20
+ @browser.span(:id, "#{@auction_id}-price").text.delete('$').to_f
21
+ end
22
+
23
+ def signed_in?
24
+ @browser.link(:text, /Logout/).exists?
25
+ end
26
+
27
+ def sign_in
28
+ @browser.link(:text, /Login/).click
29
+ @browser.text_field(:id, "userNameOrEmail").set(@username)
30
+ @browser.text_field(:id, "password").set(@password)
31
+ @browser.form(:action, /login/).submit
32
+ end
33
+
34
+ def get_hours
35
+ @browser.span(:id, "#{@auction_id}-hours_remaining").text.to_i
36
+ end
37
+
38
+ def get_mins
39
+ @browser.span(:id, "#{@auction_id}-minutes_remaining").text.to_i
40
+ end
41
+
42
+ def get_secs
43
+ @browser.span(:id, "#{@auction_id}-seconds_remaining").text.to_i
44
+ end
45
+
46
+ def execute_bid
47
+ @browser.div(:id, "#{@auction_id}-bid_button").click
48
+ end
49
+
50
+ def get_formatted_price
51
+ @browser.span(:id, @auction_id + "-price").text
52
+ end
53
+ end
@@ -0,0 +1,26 @@
1
+ class BrowserInterface < Watir::Safari
2
+
3
+ def initialize(url)
4
+ super()
5
+ @url = url
6
+
7
+ begin
8
+ goto @url
9
+ rescue
10
+ $log.error "Failed to load website. Will retry."
11
+ retry
12
+ end
13
+ end
14
+
15
+ def reload
16
+ $log.debug "reloading ..."
17
+ begin
18
+ goto @url
19
+ @last_reload = Time.now.to_i
20
+ sleep 5 # give the browser time to finish loading before continuing
21
+ rescue
22
+ $log.error "Failed to reload. Will retry."
23
+ retry
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Autobidder" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'autobidder'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: auto-bidder
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - hoverlover
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-09 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: gem for automatically placing bids on auction sites
23
+ email: hoverlover@gmail.com
24
+ executables:
25
+ - auto-bidder
26
+ - auto-bidder
27
+ extensions: []
28
+
29
+ extra_rdoc_files:
30
+ - LICENSE
31
+ - README.markdown
32
+ files:
33
+ - bin/auto-bidder
34
+ - lib/auto_bidder.rb
35
+ - lib/auto_bidder/auction_interface.rb
36
+ - lib/auto_bidder/bigdeal.rb
37
+ - lib/auto_bidder/browser_interface.rb
38
+ - LICENSE
39
+ - README.markdown
40
+ - spec/auto_bidder_spec.rb
41
+ - spec/spec_helper.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/hoverlover/auto-bidder
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ hash: 3
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.3.7
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: gem for automatically placing bids on auction sites
76
+ test_files:
77
+ - spec/auto_bidder_spec.rb
78
+ - spec/spec_helper.rb