Skip to content

Commit 016c2ce

Browse files
committed
Addperiodic task
1 parent d1bca86 commit 016c2ce

File tree

6 files changed

+128
-14
lines changed

6 files changed

+128
-14
lines changed

apps/storage/storage.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ def insert_one(collection_name, doc: dict, db_name="tickets"):
1010
return insert_one__(coll, doc)
1111

1212
# insert many
13-
def insert_many(collection_name, docs: list, db_name="tickets"):
13+
def insert_many(collection_name, docs: list[dict], db_name="tickets"):
14+
if len(docs) == 0:
15+
return True
1416
db = get_db_handle(db_name)
1517
coll = db[collection_name]
1618
# additional attributes

apps/ticketscraping/constants.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ def get_top_picks_url(
1313
"referer": "https://www.ticketmaster.com/"}
1414
DATABASE = {
1515
"EVENTS": "events",
16-
"TOP_PICKS": "top-picks"
16+
"TOP_PICKS": "top-picks",
17+
"BEST_AVAILABLE_SEATS": "best-available-seats",
18+
"BEST_HISTORY_SEATS": "best-history-seats"
1719
}
1820
def get_top_picks_header(): return {
1921
**BASIC_REQ_HEADER,
@@ -31,7 +33,7 @@ def get_top_picks_query_params(qty, priceInterval): return {
3133
'embed': ['area', 'offer', 'description'],
3234
'apikey': 'b462oi7fic6pehcdkzony5bxhe',
3335
'apisecret': 'pquzpfrfz7zd2ylvtz3w5dtyse',
34-
'limit': 25,
36+
'limit': 100,
3537
'offset': 0,
3638
'sort': '-quality',
3739
}

apps/ticketscraping/models/pick.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
class Pick():
2+
def __init__(self, type, selection, quality, section, row, area, maxQuantity, offer, seat_columns, _id=None, scraping_id=None):
3+
self._id = _id
4+
self.scraping_id = scraping_id
5+
self.type = type
6+
self.selection = selection
7+
self.quality = quality
8+
self.section = section
9+
self.row = row
10+
self.area = area
11+
self.maxQuantity = maxQuantity
12+
self.offer = offer
13+
self.price = offer.get('listPrice')
14+
self.seat_columns = seat_columns
15+
16+
def setScrapingId(self, scraping_id: str):
17+
self.scraping_id = scraping_id
18+
19+
def __eq__(self, other):
20+
return (self.section == other.section and self.row == other.row and
21+
((type(self.seat_columns) is list and len(
22+
self.seat_columns) > 0 and type(other.seat_columns) is list and len(
23+
other.seat_columns) > 0 and self.seat_columns[0] == other.seat_columns[0]) or
24+
(self.seat_columns is None and other.seat_columns is None)) and
25+
self.price == other.price)
26+
27+
def __hash__(self):
28+
return hash((self.section,
29+
self.row,
30+
self.seat_columns[0] if type(self.seat_columns) is list and len(
31+
self.seat_columns) > 0 else None,
32+
self.price))

apps/ticketscraping/scraping.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from threading import Semaphore
99
from .prepare_reese84token import getReese84Token
1010
from ..storage.storage import *
11-
from .seat_analysis import store_seats
11+
from .seat_analysis import format_seats
12+
from .tasks.periodic import run_periodic_task
1213

1314
class Reese84TokenUpdating():
1415
def __init__(self):
@@ -75,19 +76,25 @@ def flag_for_termination(self):
7576

7677
def ticket_scraping(self):
7778
if self.token_gen.token_semaphore._value <= 0:
78-
# retry after a delay
79+
# phase: retry after a delay
7980
self.scheduler.enter(constants.TICKET_SCRAPING_TOKEN_AWAIT_MAX_INTERVAL,
8081
constants.TICKET_SCRAPING_PRIORITY, self.ticket_scraping)
8182
return
83+
# scrape the top-picks from ticketmaster
8284
top_picks_url = constants.get_top_picks_url(self.event_id)
8385
top_picks_q_params = constants.get_top_picks_query_params(
8486
self.num_seats, self.price_range)
8587
top_picks_header = constants.get_top_picks_header()
8688
res = requests.get(top_picks_url, headers=top_picks_header, params=top_picks_q_params,
8789
cookies=dict(reese84=self.token_gen.reese84_token['token']))
8890
# print(res.json())
89-
res_obj = res.json()
90-
store_seats(res_obj, self.subscribe_id)
91+
92+
# prune and format the received picks
93+
picks_obj = format_seats(res.json(), self.subscribe_id)
94+
95+
# periodic task: update collections best_available_seats and best_history_seats
96+
run_periodic_task(picks_obj, self.subscribe_id)
97+
9198
print("Got the ticket info from TM. /", res.status_code)
9299
self.scheduler.enter(constants.TICKET_SCRAPING_INTERVAL,
93100
constants.TICKET_SCRAPING_PRIORITY, self.ticket_scraping)

apps/ticketscraping/seat_analysis.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from dateutil import parser
2-
from ..storage.storage import insert_one
3-
from ..ticketscraping import constants
2+
# from ..storage.storage import insert_one
3+
# from ..ticketscraping import constants
44

55

6-
def store_seats(data, subscriber_id):
6+
def format_seats(data, subscriber_id):
77
# prune top-picks data structure
88
pruned_picks = prune_pick_attributes(data)
99

@@ -14,10 +14,10 @@ def store_seats(data, subscriber_id):
1414
remove_embedded_field
1515
], pruned_picks, subscriber_id)
1616

17-
# store in db
18-
# print(res)
19-
insert_one(constants.DATABASE['TOP_PICKS'], res)
20-
pass
17+
# # store in db
18+
# # print(res)
19+
# insert_one(constants.DATABASE['TOP_PICKS'], res)
20+
return res
2121

2222
def pipe(fns: list, *args):
2323
out = args
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from ...storage.storage import find_many, insert_many, delete_many
2+
from ...ticketscraping import constants
3+
from ..models.pick import Pick
4+
5+
def generate_picks_set_from_picks(picks):
6+
def __helper(pick: dict):
7+
return Pick(_id=pick.get('_id'),
8+
scraping_id=pick.get('scraping_id'),
9+
type=pick['type'],
10+
selection=pick['selection'],
11+
quality=pick['quality'],
12+
section=pick['section'],
13+
row=pick['row'],
14+
area=pick['area'],
15+
maxQuantity=pick['maxQuantity'],
16+
offer=pick['offer'],
17+
seat_columns=pick['seat_columns'])
18+
19+
if type(picks) is dict:
20+
return set(map(__helper, picks['picks']))
21+
elif type(picks) is list:
22+
return set(map(__helper, picks))
23+
else:
24+
raise Exception('argument type error')
25+
26+
def get_current_best_available(scraping_id: str):
27+
return find_many(constants.DATABASE['BEST_AVAILABLE_SEATS'], {"scraping_id": scraping_id})
28+
def remove_best_seats(seats: set[Pick]):
29+
ids = []
30+
for seat in seats:
31+
ids.append(seat._id)
32+
return delete_many(constants.DATABASE['BEST_AVAILABLE_SEATS'], {"_id" : {"$in": ids}})
33+
def insert_best_seats(seats: set[Pick], scraping_id: str):
34+
for seat in seats:
35+
seat.setScrapingId(scraping_id)
36+
return insert_many(constants.DATABASE['BEST_AVAILABLE_SEATS'], list(map(lambda seat: vars(seat), seats)))
37+
def insert_history_seats(seats: set[Pick]):
38+
return insert_many(constants.DATABASE['BEST_HISTORY_SEATS'], list(map(lambda seat: vars(seat), seats)))
39+
40+
41+
42+
def run_periodic_task(picks: dict, scraping_id: str):
43+
# B the list of new best available seats
44+
new_best_avail = generate_picks_set_from_picks(picks)
45+
# A be the list of current best available seats
46+
cur_best_avail = generate_picks_set_from_picks(get_current_best_available(scraping_id))
47+
48+
# Compute C := A-B which is the seats
49+
overwritten_seats = cur_best_avail - new_best_avail
50+
51+
# Compute D := B-A which is the new seats
52+
new_seats = new_best_avail - cur_best_avail
53+
54+
print(f"size of B is {len(new_best_avail)}")
55+
print(f"size of A is {len(cur_best_avail)}")
56+
print(f"size of C is {len(overwritten_seats)}")
57+
print(f"size of D is {len(new_seats)}")
58+
59+
# Remove C from best_available_seats
60+
remove_best_seats(overwritten_seats)
61+
62+
# Insert D to best_available_seats
63+
insert_best_seats(new_seats, scraping_id)
64+
65+
# Save C to best_history_seats.
66+
insert_history_seats(overwritten_seats)
67+
68+
# TODO
69+
# Use D to invoke a handler to analyze them against the best_history_seats asynchronously.
70+
71+
pass

0 commit comments

Comments
 (0)