To be honest personally do not have much interest in the game, but the only Blizzard's Diablo series is very affectionate, early last year began to play Diablo3, on and off, I feel that the most troublesome is to choose the skills, each version update may have a better build, which is not a good thing for amateur players like me, well after the grand secret of the ladder, draw on the ranking of the top of the high-level The players build is always right, so spent some time to write this script.
The script only statistics active skills, passive skills and the use of legendary gems, theoretically, statistics on other information such as equipment is just as simple and feasible, but Diablo equipment generation mechanism makes the statistics of this does not make much sense, the same equipment attributes may have their own strengths and weaknesses, it is difficult to compare, and some of the equipment of the pitfalls of the drop rate is not something you want to be able to have.
As an aside, I have to say that Python is too good for writing these kinds of scripts with relatively simple functions, in a word: fast.
# -*- coding: utf-8 -*- """ Diablo3 top of the list1000Player Heroes Using Skills Statistics python help python [barbarian|crusader|demon-hunter|monk'|witch-doctor|wizard] The default is to use the data from the Asian service,If you need American or European service,variation`_rank_page`respond in singing`_api`The address of the variable is sufficient Copyright (c) 2015 JinnLynn <eatfishlin@> Released under the terms of the MIT license. """ from __future__ import unicode_literals, print_function, absolute_import import os import sys import urllib2 import json import re __version__ = '1.0.0' __author__ = 'JinnLynn <eatfishlin@>' __license__ = 'The MIT License' __copyright__ = 'Copyright 2015 JinnLynn' # Ranking Page _rank_page = '/d3/zh/rankings/' # api _api = '/api/d3/' _api_profile = (_api, 'profile') _api_data = (_api, 'data') _hero_classes = { 'barbarian': "The Barbarians, 'crusader': "Holy Army, 'demon-hunter': "Demon Hunter., 'monk': 'Martial Monk', 'witch-doctor': 'Witch Doctor', 'wizard': "Secretaries} _retry = 5 _hero_class = '' _active_skills = {} _passive_skills = {} _unique_gems = {} def _clear_output(msg=''): ('\r{:30}'.format(' ')) ('\r{}'.format(msg)) () def _process(stated, total): msg = 'Heroic Data Analysis in Progress... {}/{}'.format(stated, total) _clear_output(msg) def _get(url, is_json=True): # print('GET: ', url) retry = 5 if _retry < 1 else _retry while retry > 0: try: req = (('utf8'), timeout=10) return (req) if is_json else () except KeyboardInterrupt, e: raise e except Exception, e: retry -= 1 # print('retry', retry, e) # raise e def _api_url(*args, **kwargs): slash = ('slash', False) args = [unicode(arg) for arg in args] url = (*args).rstrip('/') return url + '/' if slash else url def get_era(): req = (_rank_page) return ().split('/')[-2] def get_rank_page_url(era): url_part = 'rift-' if _hero_class == 'demon-hunter': url_part += 'dh' elif _hero_class == 'witch-doctor': url_part += 'wd' else: url_part += _hero_class return (_rank_page, 'era', era, url_part) def fetch_rank_list(): tags = [] try: _clear_output('Getting the current game epoch...') era = get_era() _clear_output('Get the current top 1000 players...') url = get_rank_page_url(era) html = _get(url, is_json=False) # re parse lst = ( r"a href=\"(.*)\" title=.*class=\"icon-profile link-first\">", ('utf8'), ) # BeautifulSoup parse # import bs4 # soup = (html) # lst = ('#ladders-table tbody tr .battletag a')['href'] for item in lst: try: (('/')[-2]) except: pass except Exception, e: print('fetch rank list fail. {}'.format(_rank_page)) raise e return tags def get_hero(player_tag): url = _api_url(_api_profile, player_tag, slash=True) data = _get(url) hero_selected = None for hero in ('heroes', []): if hero['class'] != _hero_class: continue last_updated = hero_selected['last-updated'] # Recently used heroes if hero_selected is None or last_updated < hero['last-updated']: hero_selected = hero if not hero_selected: raise Exception('{} hero missing.'.format(player_tag)) url = _api_url(_api_profile, player_tag, 'hero', hero_selected['id']) return _get(url) # Active skill runes def stat_active_skill_rune(skill_slug, rune): global _active_skills if not rune: return slug = ('slug') if slug in _active_skills[skill_slug]['rune']: _active_skills[skill_slug]['rune'][slug]['count'] += 1 else: _active_skills[skill_slug]['rune'][slug] = { 'count': 1, 'name': ('name') } # Active skills def stat_active_skill(active): global _active_skills slug = ('skill', {}).get('slug') # d3 API returns data that may have nulls in it if not slug: return if slug in _active_skills: _active_skills[slug]['count'] += 1 else: _active_skills[slug] = { 'count': 1, 'name': ('skill').get('name'), 'rune': {} } stat_active_skill_rune(slug, ('rune')) # Passive skills def stat_passive_skill(passive): global _passive_skills slug = ('skill', {}).get('slug') # d3 API returns data that may have nulls in it if not slug: return if slug in _passive_skills: _passive_skills[slug]['count'] += 1 else: _passive_skills[slug] = { 'count': 1, 'name': ('skill').get('name') } def stat_unique_gem(items): global _unique_gems def get_gem(tooltip): if not tooltip: return None, None url = _api_url(_api_data, tooltip) data = _get(url) gems = ('gems') if not gems: return None, None gem = gems[0].get('item', {}) return ('id'), ('name') if not items: return lst = [(s, {}) for s in ['leftFinger', 'rightFinger', 'neck']] for tooltip in [('tooltipParams', None) for d in lst]: id_, name = get_gem(tooltip) if not id_: continue if id_ in _unique_gems: _unique_gems[id_]['count'] += 1 else: _unique_gems[id_] = { 'count': 1, 'name': name } def stat(hero): global _active_skills, _passive_skills map(stat_active_skill, ('skills', {}).get('active', [])) map(stat_passive_skill, ('skills', {}).get('passive', [])) items = ('items', {}) stat_unique_gem(items) def output(hero_stated, hero_stat_failed): def sort(data, count=10): d = sorted((), key=lambda d: d[1]['count'], reverse=True) return d if count <= 0 else d[0:count] _clear_output() # print('======') # print(hero_stated, hero_stat_failed) # print('======') # pprint(_active_skills) # print('======') # pprint(_passive_skills) # print('======') # pprint(_unique_gems) # pprint(_active_skills.items()) # print('======') print('\n=== RESULT ===\n') print('Counting the number of heroes \n') print(' successes: {} fail (e.g. experiments): {}\n'.format(hero_stated, hero_stat_failed)) print('Ranking of Active Skill Usage: ') for _, d in sort(_active_skills): runes = [] for _, r in sort(('rune', {})): ('{name}[{count}]'.format(**r)) ({'rune_rank': ', '.join(runes)}) print(' {name}[{count}]: {rune_rank}'.format(**d)) print() print('Ranking of Passive Skill Usage: ') for _, d in sort(_passive_skills): print(' {name}[{count}]'.format(**d)) print() print(' Ranking of Legendary Gem Usage: ') for _, d in sort(_unique_gems): print(' {name}[{count}]'.format(**d)) print() def prepare(): global _hero_class def print_hc(): print('Only the following hero types are supported, default demon-hunter:\n') for c, n in _hero_classes.items(): print(c, ':', n) if len() == 1: _hero_class = 'demon-hunter' elif len() > 2: ('Parameter error') else: arg = [1] if arg == 'help': print_hc() print('\nTips: Ctrl+C can be terminated at any time during the run to get the results of the data that has been counted') () elif arg not in _hero_classes: print_hc() () else: _hero_class = arg def main(): prepare() print('Type of hero to be analyzed:', _hero_classes[_hero_class]) hero_stated = 0 hero_stat_failed = 0 try: tags = fetch_rank_list() if not tags: raise Exception('parse rank page fail.') except Exception, e: print('error,', e) () total = len(tags) for tag in tags: try: hero = get_hero(tag) if not hero: raise Exception('no hero data') stat(hero) hero_stated += 1 _process(hero_stated, total) except KeyboardInterrupt: break except Exception, e: # print('Fail: ', tag, e, hero) hero_stat_failed += 1 output(hero_stated, hero_stat_failed) if __name__ == '__main__': main()