侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Python获取暗黑破坏神3战网前1000命位玩家的英雄技能统计

Python  /  管理员 发布于 7年前   190

说实在的个人对游戏并没有多大的兴趣,但唯独对暴雪的Diablo系列很有感情,去年年初开始玩Diablo3,断断续续,感觉最麻烦的是选择技能,每次版本更新可能都有更优的build,这对于我这样的业余玩家来说可不是件好事,好在宏伟秘境后有了天梯,借鉴排名在前的高级玩家们build总没错,于是花了点时间写了这个脚本。

脚本只是统计了主动技能、被动技能和传奇宝石的使用情况,理论上统计其它如装备等信息也是一样简单可行的,但Diablo装备的生成机制使得统计这个没有多大意义,相同的装备属性可能各有优劣,难以比较,而且某些装备坑爹的掉率也不是你想要就能有的。

题外话,不得不说Python太适合写这类功能相对简单的脚本了,一个字:快。

# -*- coding: utf-8 -*-"""Diablo3 排名前1000玩家英雄使用技能统计python diablo.py helppython diablo.py [barbarian|crusader|demon-hunter|monk'|witch-doctor|wizard]默认使用的是亚服的数据,如果需要美服或欧服,更改`_rank_page`和`_api`变量地址即可Copyright (c) 2015 JinnLynn <[email protected]>Released under the terms of the MIT license."""from __future__ import unicode_literals, print_function, absolute_importimport osimport sysimport urllib2import jsonimport re__version__ = '1.0.0'__author__ = 'JinnLynn <[email protected]>'__license__ = 'The MIT License'__copyright__ = 'Copyright 2015 JinnLynn'# 排名页面_rank_page = 'http://tw.battle.net/d3/zh/rankings/'# api_api = 'http://tw.battle.net/api/d3/'_api_profile = os.path.join(_api, 'profile')_api_data = os.path.join(_api, 'data')_hero_classes = {  'barbarian': '野U人', 'crusader': '}教', 'demon-hunter': '狩魔C人',  'monk': '武僧', 'witch-doctor': '巫t', 'wizard': '秘g'}_retry = 5_hero_class = ''_active_skills = {}_passive_skills = {}_unique_gems = {}def _clear_output(msg=''):  sys.stdout.write('\r{:30}'.format(' '))  sys.stdout.write('\r{}'.format(msg))  sys.stdout.flush()def _process(stated, total):  msg = '英雄数据分析中... {}/{}'.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 = urllib2.urlopen(url.encode('utf8'), timeout=10)      return json.load(req) if is_json else req.read()    except KeyboardInterrupt, e:      raise e    except Exception, e:      retry -= 1      # print('retry', retry, e)      # raise edef _api_url(*args, **kwargs):  slash = kwargs.get('slash', False)  args = [unicode(arg) for arg in args]  url = os.path.join(*args).rstrip('/')  return url + '/' if slash else urldef get_era():  req = urllib2.urlopen(_rank_page)  return req.geturl().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 os.path.join(_rank_page, 'era', era, url_part)def fetch_rank_list():  tags = []  try:    _clear_output('获取当前游戏纪元...')    era = get_era()    _clear_output('获取当前排名前1000的玩家...')    url = get_rank_page_url(era)    html = _get(url, is_json=False)    # re parse    lst = re.findall(      r"a href=\"(.*)\" title=.*class=\"icon-profile link-first\">",      html.decode('utf8'),      re.UNICODE)    # BeautifulSoup parse    # import bs4    # soup = bs4.BeautifulSoup(html)    # lst = soup.select('#ladders-table tbody tr .battletag a')['href']    for item in lst:      try:        tags.append(item.split('/')[-2])      except:        pass  except Exception, e:    print('fetch rank list fail. {}'.format(_rank_page))    raise e  return tagsdef get_hero(player_tag):  url = _api_url(_api_profile, player_tag, slash=True)  data = _get(url)  hero_selected = None  for hero in data.get('heroes', []):    if hero['class'] != _hero_class:      continue    last_updated = hero_selected['last-updated']    # 最近使用的英雄    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)# 主动技能符文def stat_active_skill_rune(skill_slug, rune):  global _active_skills  if not rune:    return  slug = rune.get('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': rune.get('name')    }# 主动技能def stat_active_skill(active):  global _active_skills  slug = active.get('skill', {}).get('slug')  # d3 API 返回的数据中可能存在空的数据  if not slug:    return  if slug in _active_skills:    _active_skills[slug]['count'] += 1  else:    _active_skills[slug] = {      'count': 1,      'name': active.get('skill').get('name'),      'rune': {}    }  stat_active_skill_rune(slug, active.get('rune'))# 被动技能def stat_passive_skill(passive):  global _passive_skills  slug = passive.get('skill', {}).get('slug')  # d3 API 返回的数据中可能存在空的数据  if not slug:    return  if slug in _passive_skills:    _passive_skills[slug]['count'] += 1  else:    _passive_skills[slug] = {      'count': 1,      'name': passive.get('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 = data.get('gems')    if not gems:      return None, None    gem = gems[0].get('item', {})    return gem.get('id'), gem.get('name')  if not items:    return  lst = [items.get(s, {}) for s in ['leftFinger', 'rightFinger', 'neck']]  for tooltip in [d.get('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, hero.get('skills', {}).get('active', []))  map(stat_passive_skill, hero.get('skills', {}).get('passive', []))  items = hero.get('items', {})  stat_unique_gem(items)def output(hero_stated, hero_stat_failed):  def sort(data, count=10):    d = sorted(data.items(), 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('统计英雄数\n')  print(' 成功: {} 失败: {}\n'.format(hero_stated, hero_stat_failed))  print('主动技能使用排名: ')  for _, d in sort(_active_skills):    runes = []    for _, r in sort(d.get('rune', {})):      runes.append('{name}[{count}]'.format(**r))    d.update({'rune_rank': ', '.join(runes)})    print(' {name}[{count}]: {rune_rank}'.format(**d))  print()  print('被动技能使用排名: ')  for _, d in sort(_passive_skills):    print(' {name}[{count}]'.format(**d))  print()  print('传奇宝石使用排名: ')  for _, d in sort(_unique_gems):    print(' {name}[{count}]'.format(**d))  print()def prepare():  global _hero_class  def print_hc():    print('仅支持以下英雄类型, 默认 demon-hunter:\n')    for c, n in _hero_classes.items():      print(c, ':', n)  if len(sys.argv) == 1:    _hero_class = 'demon-hunter'  elif len(sys.argv) > 2:    sys.exit('参数错误')  else:    arg = sys.argv[1]    if arg == 'help':      print_hc()      print('\nTips: 运行中可随时Ctrl+C终止以获得已统计的数据结果')      sys.exit()    elif arg not in _hero_classes:      print_hc()      sys.exit()    else:      _hero_class = argdef main():  prepare()  print('待分析的英雄类型:', _hero_classes[_hero_class])  hero_stated = 0  hero_stat_failed = 0  try:    tags = fetch_rank_list()    if not tags:      raise Exception('parse battle.net rank page fail.')  except Exception, e:    print('error,', e)    sys.exit()  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()

您可能感兴趣的文章:

  • python实现爬虫统计学校BBS男女比例(一)
  • python实现爬虫统计学校BBS男女比例之多线程爬虫(二)
  • python实现音乐下载的统计


  • 上一条:
    Python的Tornado框架的异步任务与AsyncHTTPClient
    下一条:
    Python实现代码统计工具(终极篇)
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客