Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # coding: utf-8
- # In[1]:
- import requests
- import os
- import json
- import math
- import multiprocessing
- import itertools as it
- from pprint import pprint
- if os.name == 'nt':
- import win32api, win32process, win32con
- pid = win32api.GetCurrentProcessId()
- handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
- win32process.SetPriorityClass(handle, win32process.BELOW_NORMAL_PRIORITY_CLASS)
- # In[2]:
- auction_data_path = "D:\\AuctionData"
- os.makedirs(auction_data_path, exist_ok=True)
- # In[4]:
- # realm_list = []
- # connected_realm_index_response = requests.get(
- # f'https://us.api.blizzard.com/data/wow/connected-realm/index?namespace=dynamic-us&locale=en_US&access_token={access_token}'
- # )
- # for connected_realm in connected_realm_index_response.json()['connected_realms']:
- # connected_realm_response = requests.get(connected_realm['href'] + f'&locale=en_US&access_token={access_token}')
- # connected_realms = sorted(realm['slug'] for realm in connected_realm_response.json()['realms'])
- # realm_list.append(connected_realms[0])
- # realm_list.sort()
- # print(realm_list)
- # In[5]:
- realm_list = ['aegwynn', 'aerie-peak', 'agamaggan', 'aggramar', 'akama', 'alexstrasza', 'alleria', 'altar-of-storms', 'alterac-mountains', 'amanthul', 'andorhal', 'antonidas', 'anubarak', 'anvilmar', 'arathor', 'area-52', 'argent-dawn', 'arthas', 'arygos', 'auchindoun', 'azgalor', 'azjolnerub', 'azralon', 'azuremyst', 'baelgun', 'barthilas', 'black-dragonflight', 'blackhand', 'blackrock', 'blackwater-raiders', 'blackwing-lair', 'bladefist', 'blades-edge', 'bleeding-hollow', 'blood-furnace', 'bloodhoof', 'bloodscalp', 'borean-tundra', 'bronzebeard', 'burning-blade', 'caelestrasz', 'cairne', 'cenarion-circle', 'cenarius', 'coilfang', 'dalaran', 'darkspear', 'darrowmere', 'dathremar', 'dawnbringer', 'deathwing', 'dentarg', 'draenor', 'dragonblight', 'draka', 'drakkari', 'draktharon', 'drakthul', 'dreadmaul', 'durotan', 'earthen-ring', 'eitrigg', 'eldrethalas', 'elune', 'emerald-dream', 'eonar', 'eredar', 'exodar', 'farstriders', 'feathermoon', 'frostmane', 'frostmourne', 'frostwolf', 'gallywix', 'garona', 'garrosh', 'ghostlands', 'gnomeregan', 'goldrinn', 'greymane', 'grizzly-hills', 'gundrak', 'hellscream', 'hydraxis', 'hyjal', 'icecrown', 'illidan', 'kargath', 'kelthuzad', 'kiljaeden', 'kilrogg', 'kirin-tor', 'korgath', 'lightbringer', 'lightninghoof', 'malfurion', 'malganis', 'misha', 'moknathal', 'moon-guard', 'muradin', 'nazgrel', 'nemesis', 'proudmoore', 'queldorei', 'quelthalas', 'ragnaros', 'ravencrest', 'ravenholdt', 'runetotem', 'sargeras', 'saurfang', 'stormrage', 'stormreaver', 'thrall', 'tichondrius', 'turalyon', 'wyrmrest-accord', 'zuljin']
- # In[6]:
- def get_data_path(realm):
- return os.path.join(auction_data_path, f'{realm}.json')
- def get_data(realm):
- with open(get_data_path(realm), 'r') as f:
- return json.load(f)
- def set_data(realm, data):
- with open(get_data_path(realm), 'w') as f:
- json.dump(data, f)
- def get_mtime_path(realm):
- return os.path.join(auction_data_path, f'{realm}.mtime')
- def get_mtime(realm):
- try:
- with open(get_mtime_path(realm), 'r') as f:
- return int(f.read())
- except FileNotFoundError:
- return 0
- def set_mtime(realm, mtime):
- with open(get_mtime_path(realm), 'w') as f:
- f.write(str(mtime))
- def update_realm(realm, access_token):
- realm_response = requests.get(
- f'https://us.api.blizzard.com/wow/auction/data/{realm}?locale=en_US&access_token={access_token}'
- )
- metadata = realm_response.json()['files'][0]
- new_mtime = metadata['lastModified']
- if new_mtime > get_mtime(realm):
- data_response = requests.get(metadata['url'])
- set_data(realm, data_response.json()['auctions'])
- set_mtime(realm, new_mtime)
- return True
- else:
- return False
- # In[7]:
- def do_update_realm(param):
- (realm, access_token) = param
- try:
- if update_realm(realm, access_token):
- print(f'realm {realm} updated')
- else:
- print(f'realm {realm} already up to date')
- return True
- except Exception as e:
- print(f'realm {realm} update failed: {e}')
- return False
- # def update_all_realms(realm_list):
- # realms_left = set(realm_list)
- # max_attempts = 10
- # for attempt_idx in range(max_attempts):
- # if not realms_left:
- # break
- # print(f'attempt {attempt_idx+1}/{max_attempts}, {len(realms_left)} realms left')
- # for realm in realms_left.copy():
- # try:
- # if update_realm(realm):
- # print(f'realm {realm} updated')
- # else:
- # print(f'realm {realm} already up to date')
- # realms_left.remove(realm)
- # except Exception as e:
- # print(f'realm {realm} update failed: {e}')
- # print('done')
- # In[8]:
- def get_item_bonuses(auc):
- if 'bonusLists' not in auc:
- return
- for b in auc['bonusLists']:
- yield b['bonusListId']
- def parse_item_bonuses(bonuses):
- item_level = 430
- warforge = 0
- socketed = False
- corruption = None
- for b in bonuses:
- if b == 4822: # Nya normal
- item_level = 445
- elif b == 4823: # Nya heroic
- item_level = 460
- elif b == 4824: # Nya mythic
- item_level = 475
- elif b == 4802 or b == 1808:
- socketed = True
- elif b in corruption_table:
- corruption = corruption_table[ b ]
- item_level += warforge
- return item_level, socketed, corruption
- def get_buyout_price(auc):
- if 'buyout' not in auc or auc['buyout'] <= 0:
- return math.inf
- return 0.0001 * auc['buyout']
- def search_realm_for_items(realm, items):
- auctions = get_data(realm)
- for auc in auctions:
- if auc['item'] in items:
- bonuses = get_item_bonuses(auc)
- item_level, socketed, corruption = parse_item_bonuses(bonuses)
- buyout = get_buyout_price(auc)
- yield {
- 'item': auc['item'],
- 'realm': realm,
- 'item_level': item_level,
- 'socketed': socketed,
- 'corruption': corruption,
- # 'owner': auc['owner'],
- 'buyout': buyout,
- 'time_left': auc['timeLeft']
- }
- def do_search_realm_for_item(param):
- (realm, items) = param
- return list(search_realm_for_items(realm, items))
- def get_access_token():
- token_response = requests.post(
- 'https://us.battle.net/oauth/token',
- data={'grant_type': 'client_credentials'},
- auth=('6e207de394fb4083a5ed10219cbf2626', '8Z4m1BDpgs62U4mqi3JTuNWdQg78YDcz') # add your API credentials here; https://develop.battle.net/documentation/guides/getting-started
- )
- return token_response.json()['access_token']
- def update_all_realms(pool, access_token):
- realms_left = set(realm_list)
- for attempt in range(10):
- params = ((realm, access_token) for realm in realms_left)
- results = pool.imap_unordered(do_update_realm, params)
- realms_left = {realm for (realm, success) in zip(realm_list, results) if not success}
- if realms_left:
- print(f'{len(realms_left)} updates failed: {realms_left}')
- else:
- print(f'all updates succeeded')
- def search_all_realms_for_items(items):
- best_prices = {item: {} for item in items}
- params = [(realm, items) for realm in realm_list]
- results = pool.imap_unordered(do_search_realm_for_item, params)
- for r in it.chain.from_iterable(results):
- if r['corruption'] in interesting_corruptions:
- bp = best_prices[r['item']]
- eilvl = r['item_level'] + (10 if r['socketed'] else 0)
- if eilvl not in bp:
- bp[eilvl] = []
- bp[eilvl].append(r)
- for bp in best_prices.values():
- for rs in bp.values():
- rs.sort(key=lambda r: r['buyout'])
- return best_prices
- # uncomment the pieces and corruptions that you are looking for
- interesting_items = [
- # (175004, "Legwraps of Horrifying Figments"), # cloth pants
- # (175005, "Belt of Concealed Intent"), # mail belt
- #(175006, "Gauntlets of Nightmare Manifest"), # plate gloves
- # (175007, "Footpads of Terrible Delusions"), # leather boots
- (175008, "Lurking Schemer's Band"), # ring
- # (175009, "Zealous Ritualist's Reverie"), # off hand
- # (175010, "Maddened Adherent's Bulwark"), # shield
- ]
- corruption_table = {
- # 6474 : 'Expedient I',
- # 6475 : 'Expedient II',
- # 6476 : 'Expedient III',
- # 6471 : 'Masterful I',
- # 6472 : 'Masterful II',
- # 6473 : 'Masterful III',
- # 6480 : 'Severe I',
- # 6481 : 'Severe II',
- # 6482 : 'Severe III',
- # 6477 : 'Versatile I',
- # 6478 : 'Versatile II',
- # 6479 : 'Versatile III',
- # 6437 : 'Strikethrough I',
- # 6438 : 'Strikethrough II',
- # 6439 : 'Strikethrough III',
- # 6555 : 'Racing Pulse I',
- # 6559 : 'Racing Pulse II',
- # 6560 : 'Racing Pulse III',
- # 6556 : 'Deadly Momentum I',
- # 6561 : 'Deadly Momentum II',
- # 6562 : 'Deadly Momentum III',
- # 6558 : 'Surging Vitality I',
- # 6565 : 'Surging Vitality II',
- # 6566 : 'Surging Vitality III',
- # 6557 : 'Honed Mind I',
- # 6563 : 'Honed Mind II',
- # 6564 : 'Honed Mind III',
- # 6549 : 'Echoing Void I',
- # 6550 : 'Echoing Void II',
- # 6551 : 'Echoing Void III',
- # 6552 : 'Infinite Stars I',
- # 6553 : 'Infinite Stars II',
- # 6554 : 'Infinite Stars III',
- # 6547 : 'Ineffable Truth I',
- # 6548 : 'Ineffable Truth II',
- 6537 : 'Twilight Devastation I',
- 6538 : 'Twilight Devastation II',
- 6539 : 'Twilight Devastation III',
- # 6543 : 'Twisted Appendage I',
- # 6544 : 'Twisted Appendage II',
- # 6545 : 'Twisted Appendage III',
- # 6540 : 'Void Ritual I',
- # 6541 : 'Void Ritual II',
- # 6542 : 'Void Ritual III',
- 6573 : 'Gushing Wound',
- }
- interesting_corruptions = dict(map(reversed, corruption_table.items()))
- if __name__ == '__main__':
- access_token = get_access_token()
- print(f'access token: {access_token}')
- with multiprocessing.Pool(32) as pool:
- update_all_realms(pool, access_token)
- items = set(item_id for (item_id, item_name) in interesting_items)
- best_prices = search_all_realms_for_items(items)
- for item_id, item_name in interesting_items:
- print(f'\n========== {item_name} ==========\n')
- pprint(best_prices[item_id])
- # most of this is not my code; I have no idea who wrote it, but all credit goes to them
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement