Last active
August 28, 2016 20:06
-
-
Save fabiomadge/8cd610b1c31a806d3e52f4e77c2fc909 to your computer and use it in GitHub Desktop.
Watches www.hotwire.com hotel prices.
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
import http.client | |
import xml.etree.ElementTree as ET | |
import csv | |
import datetime | |
import os | |
import sys | |
import time | |
APIKEY = $APIKEY | |
OUTPUTFIELDS = ['timestamp', 'price'] | |
CONFIGFIELDS = ['city', 'arrival', 'departure'] | |
CONFIG = "config.csv" | |
INTERVAL = 10 * 60 | |
# date: 07/04/2009 is July 4th 2009 | |
def getStop(city, arrival, departure, deal): | |
conn = http.client.HTTPSConnection("api.hotwire.com") | |
conn.request("GET", "/v1/" + ("deal" if deal else "search") + "/hotel" | |
+ "?dest=" + str.replace(city, ' ', '%20') + "&distance=*~4" | |
+ "&startdate=" + arrival + "&enddate=" + departure | |
+ "&starrating=4~*" | |
# + "&hwpos=de" | |
# + "&recommendation=80~*" | |
# + "&sort=price" | |
+ "&rooms=1&adults=2&children=0" | |
+ "&apikey=" + APIKEY + "&limit=100") | |
return conn.getresponse().read().decode('utf-8') | |
def stringNode(node): | |
if node == None: | |
return "None" | |
else: | |
return str(node.text) | |
def amenityString(node): | |
ret = "" | |
for code in node: | |
ret += stringNode(code) | |
return ret | |
def lastPrice(filename): | |
try: | |
with open(filename, 'r', newline='') as f: | |
reader = csv.DictReader(f, fieldnames=OUTPUTFIELDS, dialect='excel') | |
next(reader) | |
cur = -1 | |
for row in reader: | |
cur = int(float(row['price'])) | |
return cur | |
except: | |
return -1 | |
def handleStop(city, arrival, departure, deal): | |
xml = getStop(city, arrival, departure, deal) | |
try: | |
root = ET.fromstring(xml) | |
results = root[1 if deal else 2] | |
except: | |
print('parse failure ignored - ' + city + ', ' + arrival + ', ' + departure + ', ' + ('deal' if deal else 'search')) | |
print(xml) | |
return | |
dirstring = city + ',' + str.replace(arrival, '/', '_') + '-' + str.replace(departure, '/', '_') | |
if not os.path.exists(dirstring): | |
os.makedirs(dirstring) | |
for result in results: | |
ident = stringNode(result.find('NeighborhoodId')) + '_' + stringNode(result.find('StarRating')) + '_' + stringNode(result.find('RecommendationPercentage')) + '_' + ('D' if deal else amenityString(result.find('AmenityCodes')) + '_S') | |
filename = dirstring + '/' + ident + '.csv' | |
existed = os.path.isfile(filename) | |
PRICETAG = 'Price' if deal else 'SubTotal' | |
lastprice = lastPrice(filename) | |
newprice = int(float(result.find(PRICETAG).text)) | |
if lastprice != newprice: | |
with open(filename, 'a', newline='') as f: | |
writer = csv.DictWriter(f, fieldnames=OUTPUTFIELDS, dialect='excel') | |
if not existed: | |
writer.writeheader() | |
writer.writerow({'timestamp': datetime.datetime.utcnow(), 'price': result.find(PRICETAG).text}) | |
print(('new' if not existed else ('lower' if lastprice > newprice else 'higher')) + ' price in ' + filename) | |
def handleSearchStop(city, arrival, departure): | |
handleStop(city, arrival, departure, False) | |
def handleDealStop(city, arrival, departure): | |
handleStop(city, arrival, departure, True) | |
def totalRecrawl(): | |
if not os.path.isfile(CONFIG): | |
with open(CONFIG, 'w', newline='') as f: | |
writer = csv.DictWriter(f, fieldnames=CONFIGFIELDS, dialect='excel') | |
writer.writeheader() | |
print("no config - file created") | |
sys.exit() | |
with open('config.csv', 'r', newline='') as f: | |
reader = csv.DictReader(f, fieldnames=CONFIGFIELDS, dialect='excel') | |
next(reader) | |
for row in reader: | |
handleSearchStop(row[CONFIGFIELDS[0]], row[CONFIGFIELDS[1]], row[CONFIGFIELDS[2]]) | |
time.sleep(1) | |
handleDealStop(row[CONFIGFIELDS[0]], row[CONFIGFIELDS[1]], row[CONFIGFIELDS[2]]) | |
time.sleep(1) | |
while True: | |
totalRecrawl() | |
time.sleep(INTERVAL) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment