使用NodeJs爬取英雄联盟帐号所有区的资产

使用NodeJs爬取英雄联盟帐号所有区的资产

起因

我应该也称得上是一名英雄联盟的老玩家了, S3 赛季就被同学拉入坑, 期间断断续续在多个大区创建了账号.

因为不固定玩某个大区, 所以我并没有一个大区达到了满英雄, 这使得我每次想练英雄时, 都得通过英雄联盟社区或 WeGame 去查找我已购买那个英雄的大区.

经历了多次这样的情况后, 我决定写这么一个爬虫来帮助我统计指定英雄联盟账号上所有大区的资产.

查找获取资产信息的接口

英雄联盟官网的资产数据查询页面地址是 https://lol.qq.com/space/game_info.shtml.

在这个页面可以看到指定大区的帐号昵称, 精粹, 点卷, 英雄与皮肤等资产数据.

这些数据是异步请求接口获取的, 我们需要分析是哪个接口取得的这些数据 (也可能是多个接口), 方法有很多, 笔者这里仅描述自己的分析过程.

  • 因为数据获取后的渲染肯定是有模板的, 笔者这里是直接查看页面的静态代码, 查找相关的模版代码 (可能存在于 html 中, 也可能存在于 js 中, 而这个页面的模版是在 html 中的).

    这里就是英雄与皮肤的渲染模板了, 可以看到它的 class 为hero-and-skin.

  • 尝试使用 chrome 开发者工具进行全局搜索 (因为渲染很可能会用到这个 class 选择器).

    开发者工具中的全局搜索快捷键是 ctrl+shift+f, 我们来看搜索结果.

  • 搜索结果中可以看到 3 个包含了该关键词的文件, 其中一个是 js 文件, 大概率是我们的目标.

    点击其中的 $('.hero-and-skin').append($('#skinList')) 跳转到 https://lol.qq.com/space/js/gameInfo.js 文件中查看相关代码, 可以看到这行代码位于showHeroList函数内.

  • 继续在此文件内搜索调用了showHeroList的地方, 可以快速找到几个调用点, 简单分析下就可以得知真正有效的初始化调用点 (因较简单不多赘述).

    $('.btn-hero-skin')也就是”英雄与皮肤“按钮第一次被点击时会进行初始化渲染, 代码在下方.

  • 可以看到这里的GameInfoFunc.showHeroList调用时传入了GameInfoFunc.heroAndSkinData变量, 继续查找这个变量定义的位置.

  • 发现初始化是一个空数组, 那么继续查找这个数组压入数据是在哪个位置.

    很快就可以找到, 是在函数setPlayerChampSkin中进行的 push.

  • 继续查找setPlayerChampSkin的调用点.

  • 是在requestMainGameInfo函数中调用的, 这里就已经看到 api 接口的调用了, 至此 api 地址已经明了.

    直接在 network 中使用PlayerChampSkin,PlayerHonor,PlayerBattleSummary作为关键词过滤, 即可找到这里的 api 调用.

  • 最终结果

    https://lol.ams.game.qq.com/lol/autocms/v1/transit/LOL/LOLWeb/Official/PlayerChampSkin,PlayerHonor,PlayerBattleSummary?use=acc&area=3&callback=jQuery191047596816129288566_1574136448457&_=1574136448458


分析获取资产信息的接口

分析参数

这个 API 调用的 resource 部分, 有些类似于 GraphQL 那样可以自定义要获取的数据, 可以直接在 network 中使用Official进行过滤, 找到另外的几个调用.

比如上图中的这个接口调用, 可以获得资产信息, 排位信息, 常用英雄这 3 种数据.

这样我们就可以自定义需要的 resource, 筛选了一下, 一共有 4 个需要的:

  • PlayerInfo 账号信息 昵称/等级/头像等
  • PlayerProperty 财产信息 (精粹/点卷)
  • PlayerRankInfo 排位信息
  • PlayerChampSkin 已拥有的英雄&皮肤数据

然后是后面的 querystring:

  • use=acc, 用途不明, 可能和鉴权有关
  • area=3 大区 id, 这里 3 为祖安, 对应的 map 代码在下方
  • season=s9 这个参数是给 PlayerRankInfo 使用的, 用于决定返回哪个赛季的排位数据
  • callback_就不多做解释了, 一个 jsonp 相关, 一个时间戳

分析鉴权

从 querystring 中可以看出这个接口调用参数时并没有传递帐号信息如 QQ 等, 所以这个接口明显是有着其他地方的鉴权, 通过后自动获取用户身份.

比较常见的鉴权就是CookieAuthorization头, 这里只看到了 Cookie, 所以直接对 Cookie 测试, 最终可以找出其中鉴权用的 Cookie 是uinskey, 只要带上这 2 个 Cookie 就可以调用接口了.


编写爬虫

笔者比较常用的网络请求是request-promise, request包提供了一个函数defaults, 可以封装包含了一些默认参数的requester.

  • 我们先将鉴权头封装进去, 因为 api 返回的是 json 格式, 为了方便, 我们再将 json 选项也加入.

  • 然后我们将 OfficialApi 的调用做一个封装

  • 然后根据这个封装后的 Api 函数, 封装一个可以获取单个大区资产的函数

  • 调用测试一下

    test code
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    getAssetsInfo(3).then(console.log)
    // Log:
    { name: 'Gucci狂徒',
    level: 124,
    area: '祖安',
    avatar:
    'https://game.gtimg.cn/images/lol/act/img/profileicon/4027.png',
    pointIP: '8847',
    pointRP: '300',
    ranks:
    [ { battleType: '单双排',
    win: 122,
    lost: 96,
    queue: 0,
    tier: 1,
    point: 38,
    rank: '璀璨钻石I' },
    { battleType: '灵活组排',
    win: 54,
    lost: 42,
    queue: 3,
    tier: 1,
    point: 19,
    rank: '璀璨钻石IV' } ],
    champ:
    [ { id: 'Annie',
    key: '1',
    name: '黑暗之女',
    title: '安妮',
    image:
    'https://ossweb-img.qq.com/images/lol/img/champion/Annie.png',
    skins: [ {
    id: '1012',
    name: '十周年纪念 安妮',
    image: 'https://ossweb-img.qq.com/images/lol/appskin/1012.jpg' },
    ...
    ] },
    ...
    ]
    }
  • 进一步封装为获取所有大区的

  • 至此基本完成, 接下来说一些其他的代码来源

    • ChampSkin.json

      来自英雄联盟社区页面上的window.LOLherojs对象

    • BattleTypeCN / TierCN / RomanNum

      实际上是看了几次数据规律猜出来的, 但页面上应该也存在


完整代码

Github: https://github.com/WhiteMinds/lol-assets-query


使用NodeJs爬取英雄联盟帐号所有区的资产

https://front.js.cn/2019/11/18/crawl-lol-assets/

作者

WhiteMind

发布于

2019-11-18

更新于

2021-12-13

许可协议

评论