This repository has been archived by the owner on Jul 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit cbd5929
Showing
9 changed files
with
514 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
Penny Auction Observer can record penny auctions taking place on penny auction websites. | ||
|
||
How the F do you use this thing? | ||
|
||
ruby bin/pa_auction_bot.rb -- help | ||
|
||
|
||
What the F does it do? | ||
|
||
I "observes" a live penny auction, and executes blocks of ruby code at the key events. | ||
The blocks of ruby code are stored in interchangeable hook files. | ||
The key events are: | ||
- Monitoring a new auction | ||
- New bids occur on a live auction | ||
- A timer threshold is reached | ||
- The auction ends | ||
|
||
|
||
What the F is it useful for? | ||
|
||
- Creating logs of penny auctions | ||
- Creating bots which can bid on penny auctions (not recommended by the authors of this tool) | ||
- Doing research on penny auctions | ||
|
||
|
||
Why the F did you make it? | ||
|
||
Penny auctions are an interesting thing. | ||
In my opinion they exploit weaknesses in the human psyche, much the same way gambling does. | ||
I wanted to collect data and study this phenomenon, strictly for my own fun. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
require 'optparse' | ||
#require 'rubygems' | ||
|
||
|
||
#Deal with the cmd line | ||
def parse_cmd_line | ||
options = { | ||
:hooks_file => 'bots/csv_logger.rb', | ||
:site => 'QUIBIDS', | ||
} | ||
|
||
optparse = OptionParser.new do |opts| | ||
opts.banner = %Q| | ||
Penny Auction Observer | ||
example: ruby -I lib bin/pa_auction_but.rb bots/csv_logger.rb | ||
| | ||
|
||
opts.on("-b", "--bot-file=FILE_NAME", | ||
"specify the bot file to execute, default is '#{options[:hooks_file]}'") { |filename| options[:hooks_file] = filename} | ||
|
||
opts.on("-a", "--auction-id=AUCTION_ID", | ||
"the auction id") { |id| options[:auction_id] = id } | ||
|
||
opts.on("-s", "--site=SITE", | ||
"Specify the site to use, default is '#{options[:site]}'") { |site| options[:site] = site} | ||
|
||
|
||
end | ||
optparse.parse! | ||
options | ||
end | ||
options = parse_cmd_line | ||
|
||
|
||
|
||
require 'pa_site' | ||
require 'pa_observer' | ||
|
||
#setup the object | ||
auction_id = options[:auction_id] | ||
load options[:hooks_file] | ||
pa_site = QB_Site.new options[:site].upcase | ||
pa_site.start auction_id | ||
|
||
|
||
|
||
auction_observer = QB_Observer.new pa_site | ||
|
||
|
||
auction_observer.hooks[:on_new_bids] = OnNewBids | ||
auction_observer.hooks[:on_new_auction] = OnNewAuction | ||
auction_observer.hooks[:on_auction_end] = OnAuctionEnd | ||
auction_observer.hooks[:on_timer_threshold] = OnTimerThreshold | ||
|
||
auction_observer.observe_auction |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
## Logs a QuiBids Auction to STDOUT | ||
# | ||
|
||
## NEW BIDS | ||
#data | ||
num_bids = 0 | ||
last_amt = -1.0 | ||
|
||
## AUCTION HOOKS | ||
OnNewAuction = lambda {|auction_name| | ||
last_amt = -1.0 | ||
num_bids = 0 | ||
puts "Now watching new auction: #{auction_name}" | ||
} | ||
|
||
OnAuctionEnd = lambda {|auction_name| | ||
puts "Done watching auction: #{auction_name}" | ||
} | ||
|
||
|
||
OnNewBids = lambda {|new_bids| | ||
new_bids.each do |bid| | ||
num_bids += 1 | ||
puts "NEW BID: '#{bid[:bidder]}' : '#{bid[:amt]}' : '#{bid[:type]}' : #{bid[:last_secs]} : #{last_amt}" | ||
end | ||
last_amt = new_bids.last[:amt] if new_bids.count > 0 | ||
puts "Processed #{new_bids.count} new bids" | ||
} | ||
|
||
|
||
|
||
## TIMER THRESHOLD | ||
num_hits = 0 | ||
OnTimerThreshold = lambda {|secs, browser| | ||
#browser.bid | ||
num_hits += 1 | ||
puts "TIMER THRESHOLD HIT: #{num_hits} so far" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
## Logs a QuiBids Auction to CSV | ||
# | ||
|
||
require 'bidder_model' | ||
|
||
## NEW BIDS | ||
#data | ||
num_bids = 0 | ||
num_skips = 0 | ||
last_amt = -1.0 | ||
|
||
|
||
## AUCTION HOOKS | ||
OnNewAuction = lambda {|auction_name| | ||
|
||
@model = QB_Model.new | ||
puts "Initialized '#{auction_name}'" | ||
} | ||
|
||
OnAuctionEnd = lambda {|auction_name| | ||
puts "Auction End" | ||
} | ||
|
||
|
||
OnNewBids = lambda {|new_bids| | ||
|
||
@model.process_new_bids new_bids | ||
|
||
|
||
} | ||
|
||
|
||
|
||
## TIMER THRESHOLD | ||
num_bids = 0 | ||
OnTimerThreshold = lambda {|secs, browser| | ||
if @model.would_bid | ||
#browser.bid | ||
num_bids += 1 | ||
puts "TIMER HIT: #{num_bids} so far" | ||
print "\a" | ||
else | ||
num_skips += 1 | ||
puts "SKIP: #{num_skips} so far" | ||
end | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
|
||
class QB_Model | ||
def initialize | ||
@bids = [] | ||
@bidders = {} | ||
|
||
@num_bids = 0 | ||
@last_amt = 0.00 | ||
|
||
@uniques = {:u10 => 10, :u20 => 20} | ||
@autoq = 9999 | ||
end | ||
|
||
def process_new_bids new_bids | ||
new_bids.each do |bid| | ||
|
||
@bids << bid | ||
|
||
if @bidders.has_key? bid[:bidder] | ||
@bidders[bid[:bidder]][:count] += 1 | ||
else | ||
@bidders[bid[:bidder]] = { | ||
:count => 1 | ||
} | ||
end | ||
|
||
@num_bids += 1 | ||
puts "NEW BID #{@num_bids}\t #{bid[:bidder]}\t #{bid[:amt]}\t #{bid[:type]}\t #{bid[:last_secs]}\t:: #{@bidders[bid[:bidder]][:count]} so far" | ||
end | ||
|
||
##determine unique bidders | ||
@uniques = {} | ||
bidders = @bids.reverse.map{|b| b[:bidder]} | ||
@uniques[:u10] = bidders[0, 10].uniq.length | ||
@uniques[:u20] = bidders[0, 20].uniq.length | ||
#@uniques[:u30] = bidders[0, 30].uniq.length | ||
#@uniques[:u40] = bidders[0, 40].uniq.length | ||
#@uniques[:u50] = bidders[0, 50].uniq.length | ||
|
||
puts "Uniques: #{@uniques.inspect}" | ||
|
||
|
||
##determine ratio of Auto to Manual | ||
types = @bids.reverse.map{|b| b[:type]} | ||
|
||
@autoq = 0 | ||
plus = 10 | ||
while (plus > 0) | ||
@autoq += plus if types[10-plus] == :automatic | ||
plus -= 1 | ||
end | ||
|
||
puts "AUTO Q: #{@autoq}" | ||
|
||
@last_amt = new_bids.last[:amt] if new_bids.length > 0 | ||
puts "Processed #{new_bids.length} new bids" | ||
end | ||
|
||
def would_bid | ||
|
||
return false if @num_bids < 25 | ||
return false if @uniques[:u10] > 6 | ||
return false if @uniques[:u20] > 9 | ||
return false if @autoq > 30 | ||
|
||
return true | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
## Logs a QuiBids Auction to CSV | ||
# | ||
|
||
## NEW BIDS | ||
#data | ||
num_bids = 0 | ||
last_amt = -1.0 | ||
|
||
### HELPERS | ||
def init_csv filename | ||
filename = 'csv/' + filename + '.' + Time.now.strftime("%m%d%Y_%H%M") + '.csv' | ||
@csv_writer = File.open(filename, 'w') | ||
puts "Opened csv '#{filename}'" | ||
end | ||
|
||
def write_csv line_array | ||
str = "" | ||
line_array.each {|f| str += "#{f.to_s}, "} | ||
@csv_writer.puts str.sub(/, $/,'') | ||
end | ||
|
||
|
||
## AUCTION HOOKS | ||
OnNewAuction = lambda {|auction_name| | ||
last_amt = -1.0 | ||
num_bids = 0 | ||
init_csv auction_name | ||
} | ||
|
||
OnAuctionEnd = lambda {|auction_name| | ||
@csv_writer.close | ||
puts "Closed csv" | ||
} | ||
|
||
|
||
OnNewBids = lambda {|new_bids| | ||
new_bids.each do |bid| | ||
num_bids += 1 | ||
puts "NEW BID: '#{bid[:bidder]}' : '#{bid[:amt]}' : '#{bid[:type]}' : #{bid[:last_secs]} : #{last_amt}" | ||
write_csv [num_bids, Time.now.strftime("%H:%M:%S"), bid[:amt], bid[:bidder], bid[:type], bid[:last_secs], last_amt] | ||
end | ||
last_amt = new_bids.last[:amt] if new_bids.count > 0 | ||
puts "Processed #{new_bids.count} new bids" | ||
} | ||
|
||
|
||
|
||
## TIMER THRESHOLD | ||
num_hits = 0 | ||
OnTimerThreshold = lambda {|secs, browser| | ||
#browser.bid | ||
num_hits += 1 | ||
puts "TIMER HIT: #{num_hits} so far" | ||
#print "\a" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# This class watches an auction | ||
|
||
require 'pa_site' | ||
|
||
class QB_Observer | ||
def initialize pa_site | ||
@pa_site = pa_site | ||
|
||
@hooks = {} #contains lambdas which are called in observice auction loop | ||
end | ||
|
||
attr_accessor :hooks | ||
|
||
def auction_name | ||
@pa_site.auction_name | ||
end | ||
|
||
def process_event name, *args | ||
@hooks[name].call(*args) if @hooks.has_key? name | ||
end | ||
|
||
def get_new_bids | ||
enhanced_bids = @pa_site.get_new_bids | ||
enhanced_bids.each {|b| b[:last_secs] = @last_secs } | ||
enhanced_bids | ||
end | ||
|
||
def observe_auction | ||
@pa_site.initialize_auction | ||
|
||
process_event :on_new_auction, auction_name | ||
|
||
#DATA USED IN LOOP | ||
cur_secs = 0 | ||
@last_secs = -1 | ||
secs_since_refresh = 0 | ||
|
||
while ( true ) | ||
begin | ||
cur_secs = @pa_site.seconds_left | ||
rescue | ||
puts $! | ||
break | ||
end | ||
|
||
#If the timer changed since last observation | ||
if (cur_secs != @last_secs ) | ||
|
||
#If the timer is almost out (bid) | ||
if cur_secs < 2 | ||
process_event :on_timer_threshold, cur_secs, @pa_site | ||
end | ||
|
||
puts " - " + cur_secs.to_s | ||
|
||
#If the timer went up, then we have new bids to process | ||
if (cur_secs > @last_secs ) | ||
#Need to refresh the browser periodically to prevent inactivity popups | ||
if secs_since_refresh > 900 | ||
@pa_site.refresh_auction | ||
secs_since_refresh = 0 | ||
end | ||
|
||
#keep getting new bids until there isn't any left to get, sometimes the time spent in new bid event is enough for new bids to show up... dont want to wait until another bid | ||
new_bids = get_new_bids | ||
while (new_bids.count > 0) | ||
process_event :on_new_bids, new_bids | ||
sleep 1.0 | ||
new_bids = get_new_bids | ||
end | ||
|
||
end | ||
|
||
#refresh the browser periodically to prevent innactivity popups | ||
secs_since_refresh += 1 | ||
end | ||
|
||
@last_secs = cur_secs | ||
sleep 0.05 | ||
end | ||
puts "End of Auction" | ||
process_event :on_auction_end, auction_name | ||
end | ||
|
||
end | ||
|
Oops, something went wrong.