英雄联盟(北美)数据抓取

Written on October 7, 2014 View on GitHub

北美官网上线了 Match 历史,无需登录,这样就不用官方 API 即可实现很多数据的抓取。

网页上看得见的是三个入口

  • https://acs.leagueoflegends.com/v1/stats/player_history/{region}/{accountid}
  • https://acs.leagueoflegends.com/v1/stats/game/{region}/{gameid}
  • https://acs.leagueoflegends.com/v1/stats/game/{region}/{gameid}/timeline

  • {region}:如 NA1
  • {accountid}:非 summoner id,也不是 summoner name,不能搞混。
  • {gameid}:同 match id

由此可以看出,{accountid}、{gameid} 是爬取的重点。两者都可以作为遍历的入口,不过当然理论上讲,第二个 API 的数据更有参考性。 {gameid} 看上去特别像 timestamp,我猜测可能早期设计就是 timestamp,后来改掉了。

数据爬取

这里以第二个 API 为主。

二分遍历一下,{gameid} 有记录的起始点为 1364960984,创建时间为2014年5月1号(1398902401616),正是 Team Builder 也就是 Patch 4.7 上线的时间,猜测是早期数据不一致就没有导入了。

简单试了一下写出这样的代码,用 php cli 可执行,也可以稍加修改作为 web api 执行。原本使用c#写的,后来发现在自己电脑上频率大概是1秒1个,但是到亚马逊加州主机上大概每秒10个,所以就放在主机上远程执行了。

数据的检测比较严格,基本不会出现记录错误数据不被发现的情况。 性能很有可能卡在json解析和curl处理,但cpu占有率又不高,所以理论上可以使用多线程加速,我这边的方法是多个进程并行执行,根据参数决定起始id。

function leagueoflegends_fetch ($region, $gameid) {
	$ch = curl_init('https://acs.leagueoflegends.com/v1/stats/game/'.$region.'/'.$gameid);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
	$body = curl_exec($ch);
	curl_close($ch);
	return $body;
}

function leagueoflegends_store ($region, $gameid, $data) {
	$folder = substr($gameid, 0, -9).'/'.substr($gameid, -9, 3).'/'.substr($gameid, -6, 3);
	$folder = './data/game/'.$region.'/'.$folder;
	if(!is_dir($folder)) mkdir($folder, 0755, TRUE);
	$file = fopen($folder.'/'.$gameid, 'wb');
	fputs($file, $data);
	fclose($file);
}

$gameid = 1364960984;
if(isset($argv[1])) {
	$gameid_tmp = intval($argv[1]);
	if ($gameid_tmp > 1364960984 && $gameid_tmp <= 2147483647 ) {
		$gameid = $gameid_tmp;
	}
}

while (TRUE) {
	echo $gameid;

	$data = leagueoflegends_fetch ('NA1', $gameid);
	$json = json_decode($data, TRUE);
	//print_r($json);

	if (isset($json['gameId']) && $json['gameId'] === $gameid) {
		echo " OK\r\n";
		leagueoflegends_store ('NA1', $gameid, $data);
	} else if (isset($json['httpStatus']) && $json['httpStatus'] === 404) {
		echo " N/A\r\n";
	} else {
		echo " ERROR\r\n";
		exit;
	}

	$gameid++;
}

fastcgi_buffers 8 4k|8k;