#!/usr/bin/python """snipe bids on eBay wait until specified second before auction ends and place bid""" Copyright = """ bidsnipe - sneaky way to win eBay auctions Copyright (C) 2009 John Comeau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. """ import sys, os, re, pwd, time import urllib, urllib2, cookielib from BeautifulSoup import BeautifulSoup cookiejar = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar)) def findLoginForm(soup): pattern = re.compile('(?i)login') forms = soup.findAll('form') loginforms = filter(lambda node: pattern.search(node.get('action')), forms) if len(loginforms) != 1: raise Exception, 'Document does not contain one and only one login form' return loginforms[0] def getInputs(soup): inputs = soup.findAll('input') return dict([[input.get('name').encode('utf8'), input.get('value').encode('utf8')] for input in inputs]) def bidsnipe(item=11111111, maxbid=1, seconds=10): """bid on item number with max price at so many seconds before end takes those 3 arguments, gets login info from $HOME/.netrc file """ print >>sys.stderr, 'sleeping %s seconds' % seconds time.sleep(float(seconds)) ebay = 'm.ebay.com' # mobile eBay site has less garbage to sift through page = login(ebay) socket = opener.open('https://%s/Pages/ViewItem.aspx?aid=%s' % (ebay, item)) soup = BeautifulSoup(socket.read()) socket.close() socket = opener.open('https://%s/Member/Bid.aspx?btnOffer=btnOffer' % ebay) soup = BeautifulSoup(socket.read()) socket.close() bidform = soup.findAll('form')[-1] inputs = getInputs(bidform) inputs.pop('btnCancel') inputs['bid'] = maxbid action = bidform.get('action') enctype = bidform.get('enctype') loginurl = 'https://%s' % ebay + action opener.addheaders = [('content-type', enctype)] socket = opener.open(loginurl, urllib.urlencode(inputs)) soup = BeautifulSoup(socket.read()) socket.close() confirmform = soup.findAll('form')[-1] print >>sys.stderr, confirmform inputs = getInputs(confirmform) print >>sys.stderr, inputs inputs.pop('btnCancel') inputs.pop('btnBack') action = confirmform.get('action') enctype = confirmform.get('enctype') loginurl = 'https://%s' % ebay + action opener.addheaders = [('content-type', enctype)] socket = opener.open(loginurl, urllib.urlencode(inputs)) page = BeautifulSoup(socket.read()) socket.close() return page def login(ebay): pattern = '^machine\s+%s\s+login\s+(\S+)\s+password\s+(.*\S)\s*$' % ebay login_data = filter(re.compile(pattern).match, open(os.path.join( pwd.getpwuid(os.geteuid())[5], '.netrc')).readlines()) username, password = re.compile(pattern).match(login_data[-1]).groups() socket = opener.open('https://%s/' % ebay) soup = BeautifulSoup(socket.read()) socket.close() loginform = findLoginForm(soup) enctype = loginform.get('enctype') action = loginform.get('action') loginurl = 'https://%s' % ebay + action opener.addheaders = [('content-type', enctype)] socket = opener.open(loginurl, urllib.urlencode(getInputs(loginform))) soup = BeautifulSoup(socket.read()) socket.close() loginform = findLoginForm(soup) inputs = getInputs(loginform) inputs['uid'] = username inputs['upw'] = password inputs.pop('btnCancel') enctype = loginform.get('enctype') action = loginform.get('action') loginurl = 'https://%s' % ebay + action opener.addheaders = [('content-type', enctype)] socket = opener.open(loginurl, urllib.urlencode(inputs)) page = socket.read() socket.close() if username in page: sys.stderr.write('login successful\n') return page if __name__ == '__main__': item, maxbid, seconds = (sys.argv[1:] + ['', '', ''])[0:3] print bidsnipe(item, maxbid, seconds) else: # if you want something to be done on import, do it here; otherwise pass pass