分析任务的流程
我们想爬去一个网站的内容,首先肯定需要登陆一个网址,这样才可以找到这个网站的内容,但我们不可能每次请求一个新的页面都需要重新登陆,这样太麻烦了,因而我们需要记录Http协议中的Session_id,只要记住了这个id,并添加到Headers 头,就可以不需要重复登陆了。
所以,做的第一件事就是如何找到这个session_id.
首先我们先查看登陆的过程,按下F12,查看network, 可以看到我们所需要的信息在 https://go.gameanalytics.com/api/v1/public/login/basic 中,如下图所示:
查看Response, 我们可以看到如下信息:
{"errors": [], "results": [{"linked": null, "token": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJsaW5rZWQiOiBudWxsLCAiaWQiOiA0NTUyNiwgImV4cCI6IDE1NzE4OTk3MjcsICJyZW1lbWJlciI6IGZhbHNlfQ.HYfc6N03FrE_J1FX0YyemuxpMK4QPG1hAlBJBYQbwwM", "id": 45526, "exp": 1571899727, "remember": false}]}
其中的token 就是我们需要的, 可以进行验证,在网址中选择JoyPac的信息,再次查看可以看到如下信息:
可以看到X-Authorization 正好等于之前的token,所以这个值显得十分重要。
接下来我们看看此次的Response,由于这个网站的设计问题,我们可以看到所有公司的游戏,因此如果我们需要自己的游戏,就需要查看他的json格式,从中找到我所需要的信息,通过json解析网址可以比较清楚的看到其结构化,截取其中一部分我所需要注意到信息如下:
"studiosGames":[
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...},
{
"createdTimestamp":1530773715,
"access":{
"role":"owner",
"level":99
},
"archived":false,
"imageFile":"1c277d29aa2718472b7bb07412c1725d.png",
"name":"JoyPac",
"disabled":false,
"games":[
{
"googleplay_key":null,
"access":{
"role":"owner",
"level":99
},
"game_key":"b260f4cea81a3abb956d397e78a5f49c",
"imageFile":"beff455e4ea3c72dd221758f6c8077cc.png",
"title":"Super Evasion 1",
"store_app":null,
"newEventStructureStatus":0,
"archived":false,
"is_beta_game":false,
"createdTimestamp":1530782719,
"onboarding":{
"update_game_1":true
},
"link_game_notification":false,
"dataApiToken":{
"token":"priv-eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJ0b2tlbiI6ICJleUpoYkdjaU9pQWlTRk15TlRZaUxDQWlkSGx3SWpvZ0lrcFhWQ0o5LmV5SmxlSEFpT2lBeE5UY3hPRGt5TkRBeGZRLjItUlp3eVI3SDVEVzMtaTlWUjVWNHRMQVBBb1U0ZElNaTRtQ0RkTGlRc28ifQ.LMciTHD3pBsOA4msC2rit5r0RYfM7qwBR79Ko_GaAeU",
"exp":1571892401
},
"store_platform":"apple_ios",
"disabled":false,
"bundle_id":"com.joypac.kaihi",
"amazon_key":null,
"featureFlags":null,
"id":54559,
"genres":[
70
]
},
可以看到在studiosGames结构下找到了JoyPac,进一步结构下可以看到我们的所有游戏id,以及token,因此我们需要生成一个字典来记录对应的关系,方便后面的下载。
得到了所有游戏id以及对应的token后,我们就可以下载了,相同的操作可以看到下载的链接地址格式为:
https://query-0.gameanalytics.com/v1/games/id/export?start=1571616000&end=1571616000
其中id 为游戏的id start,end 为开始和截至的时间戳,要注意时区的问题。
好的,这样我们就得到了下载的链接,只需要下载解压即可。
整体流程就是这样,还是很清晰的。
获取token
由于是第一次做相关的任务,绕了不上弯子。
要访问网页,肯定需要用到post或者get ,先看下二者的区别:
(1) 在客户端,Get方式在通过URL提交数据,数据在URL中可以看到;POST方式,数据放置在HTML HEADER内提交。
(2) GET方式提交的数据最多只能有1024 Byte,而POST则没有此限制。
(3) 安全性问题。正如在(1)中提到,使用 Get 的时候,参数会显示在地址栏上,而 Post 不会。所以,如果这些数据是中文数据而且是非敏感数据,那么使用get;如果用户输入的数据不是中文字符而且包含敏感数据,那么还是使用 post为好。
表单提交中get和post方式的区别归纳如下几点:
(1)get是从服务器上获取数据,post是向服务器传送数据。
(2)对于表单的提交方式,在服务器端只能用Request.QueryString来获取Get方式提交来的数据,用Post方式提交的数据只能用Request.Form来获取。
(3)一般来说,尽量避免使用Get方式提交表单,因为有可能会导致安全问题。比如说在登陆表单中用Get方式,用户输入的用户名和密码将在地址栏中暴露无遗。但是在分页程序中,用Get方式就比用Post好。
HTTP POST和GET的区别
1、HTTP 只有POST和GET 两种命令模式;
2、 POST 是被设计用来向上放东西的,而GET是被设计用来从服务器取东西的,GET也能够向服务器传送较少的数据,而Get之所以也能传送数据,只是用来设计告诉 服务器,你到底需要什么样的数据.POST的信息作为HTTP 请求的内容,而GET是在HTTP 头部传输的;
3、POST与GET在HTTP 中传送的方式不同,GET的参数是在HTTP 的头部传送的,而Post的数据则是在HTTP 请求的内容里传送;
4、POST传输数据时,不需要在URL中显示出来,而GET方法要在URL中显示;
5、 GET方法由于受到URL长度的限制,只能传递大约1024字节;POST传输的数据量大,可以达到2M,而根据微软方面的说法,微软对用 Request.Form() 可接收的最大数据有限制,IIS 4 中为 80 KB 字节,IIS 5 中为 100 KB 字节;
6、SOAP是依赖于HTTP POST模式实现的;
原文链接
其次,我看到了一个写的不错的request.get,post 的使用,先mark 一波
request.post 和 request.get使用
接下来是实际的操作了,弄懂了上面的东西,其实就很简单了,我们只需要向url post 一个请求,带上账户信息,结果看到我们所需要的response了。
具体代码如下:
def gettoken(url,headers):
request_param={
"email": '******',
"password": '******',
"remember": False
}
response=requests.post(url,data=json.dumps(request_param), headers=headers)
get = response.json()["results"][0]
print(get["token"])
print(type(get["token"]))
return get["token"]
在request_param 中带上所需要的信息就可以,这里我的url 是:
“https://go.gameanalytics.com/api/v1/public/login/basic”
具体依据情况改变就可 。
这样我们就获得了所需要的token,感觉也很简单哈哈哈。
在代码中 .json()函数可以将json 格式转换为字典格式,方便我们进行操作,向get[“token”] 就可以直接获得其中的token 值,字典有点类似与java的哈希表? 但是感觉用起来更方便。
获取游戏id
获取游戏id 感觉和token是一模一样的,因为我们已经获取token 了,所以只需要在headers中加入这个值就可以了,主要操作就是将json 转换为字典格式后,获取我们所需要的值,直接贴代码吧!
def getmygame(token):
headers = {
"X-Authorization": token
}
res_game = requests.get('https://go.gameanalytics.com/api/v1/user/data', headers=headers)
# 调用get方法,下载这个字典
json_game = res_game.json()
# 使用json()方法,将response对象,转为列表/字典
print(type(json_game))
print(json_game)
return json_game
def get_mygame_id(StudioGame_list):
game_id_dict = {}
for i in range(len(StudioGame_list)):
dict_game = StudioGame_list[i]
if dict_game["name"] == "JoyPac":
print(StudioGame_list[i]["name"])
print("games 类型")
print(type(dict_game["games"]))
for j in range(len(dict_game["games"])):
game_id_dict[dict_game["games"][j]["id"]] = dict_game["games"][j]["dataApiToken"]["token"]
print(game_id_dict)
return game_id_dict
这里涉及到了字典和List 的遍历,由于是第一次使用,也做一个记录吧!
List 遍历
# 方法1
print '遍历列表方法1:'
for i in list:
print("序号:%s 值:%s" % (list.index(i) + 1, i))
# 方法2
print '\n遍历列表方法2:'
for i in range(len(list)):
print("序号:%s 值:%s" % (i + 1, list[i]))
# 方法3
print '\n遍历列表方法3:'
for i, val in enumerate(list):
print("序号:%s 值:%s" % (i + 1, val))
字典遍历
(1) 遍历Key值
>>> a
{'a': '1', 'b': '2', 'c': '3'}
>>> for key in a:
print(key+':'+a[key])
a:1
b:2
c:3
>>> for key in a.keys():
print(key+':'+a[key])
a:1
b:2
c:3
(2)遍历value值
>>> for value in a.values():
print(value)
1
2
3
(3)遍历字典项
>>> for kv in a.items():
print(kv)
('a', '1')
('b', '2')
('c', '3')
(4)遍历字典键值
for key,value in a.items():
print(key+’:’+value)
a:1
b:2
c:3
for (key,value) in a.items():
print(key+’:’+value)
a:1
b:2
c:3
获取数据下载链接
创建一个字典进行存储,每个Id 对应自己的链接,每个链接有List存储,整体操作类似,代码如下:
def get_download_linkdict(game_id_dict,timestamp,token):
yesterday_timestamp = timestamp
link_dict = {}
for key in game_id_dict:
headers = {
"Authorization": game_id_dict[key]
}
# 拼接url 获取每个游戏的下载链接
url = "https://query-0.gameanalytics.com/v1/games/"+str(key)+"/export?start="+str(yesterday_timestamp)+"&end=" + str(yesterday_timestamp)
link_game = requests.get(url, headers=headers)
download_link = link_game.json()
print(download_link)
demo = []
#每个游戏的链接由一个list 存储 再有一个dict 存储每个游戏的list
for i in range(len(download_link)):
demo.append(download_link[i]["url"])
#print(demo)
link_dict[key] = demo
print(link_dict)
return link_dict
下载
下载的时候先利用 os.path.join()生成一个目录,并别需要判断目录是否存在,否则可能会报错。遍历字典,获取每个Id的链接进行下载。
下载主要用到的函数为:
urllib.request.urlretrieve(link_dir[key][i], downpath)
这个函数功能为:
urlretrieve(url, filename=None, reporthook=None, data=None)
参数 finename 指定了保存本地路径(如果参数未指定,urllib会生成一个临时文件保存数据。)
参数 reporthook 是一个回调函数,当连接上服务器、以及相应的数据块传输完毕时会触发该回调,我们可以利用这个回调函数来显示当前的下载进度。
参数 data 指 post 到服务器的数据,该方法返回一个包含两个元素的(filename, headers)元组,filename 表示保存到本地的路径,header 表示服务器的响应头。
def download_data_gz(link_dir, timestamp):
dir = os.path.join('C:\data', str(timestamp))
isExists = os.path.exists(dir)
if not isExists:
# 如果不存在则创建目录
# 创建目录操作函数
os.makedirs(dir)
else:
# 如果目录存在则不创建,并提示目录已存在
print(' 目录已存在')
for key in link_dir:
data_dir = os.path.join(dir, str(key))
isExists = os.path.exists(data_dir)
if not isExists:
# 如果不存在则创建目录
# 创建目录操作函数
os.makedirs(data_dir)
else:
# 如果目录存在则不创建,并提示目录已存在
print(' 目录已存在')
for i in range(len(link_dir[key])):
name = link_dir[key][i].split('?')[-2].split('/')[-1]
downpath = os.path.join(data_dir, name)
urllib.request.urlretrieve(link_dir[key][i], downpath)
print(data_dir)
un_gz_Tree(data_dir)
delete_gz_tree(data_dir)
解压缩,删除文件
def un_gz(file_name):
"""解压单个文件"""
f_name = file_name.replace(".gz", "")
# 获取文件的名称,去掉
g_file = gzip.GzipFile(file_name)
# 创建gzip对象
open(f_name, "wb+").write(g_file.read())
# gzip对象用read()打开后,写入open()建立的文件里。
g_file.close()
print("解压完毕",end=' ')
print(file_name)
def un_gz_Tree(path):
# 解压文件夹中的zip文件
print(path)
if not os.path.exists(path): # 如果本地文件夹不存在,则创建它
print("不存在文件夹")
os.makedirs(path)
for file in os.listdir(path): #listdir()返回当前目录下清单列表
Local = os.path.join(path, file) #os.path.join()用于拼接文件路径
print("开始解压")
print(Local)
if os.path.splitext(Local)[1] == '.gz': #os.path.splitext(Remote)[1]获取文件扩展名,判断是否为.zip文件
un_gz(Local) #解压文件
def delete_gz_tree(path):
print("开始删除")
print(path)
if not os.path.exists(path): # 如果本地文件夹不存在,则创建它
print("不存在文件夹")
for file in os.listdir(path): # listdir()返回当前目录下清单列表
Local = os.path.join(path, file) # os.path.join()用于拼接文件路径
print("删除压缩包",end=' ')
print(Local)
if os.path.splitext(Local)[1] == '.gz': # os.path.splitext(Remote)[1]获取文件扩展名,判断是否为.gz文件
delete_gz(Local) # 解压文件
def delete_gz(file_name):
if (os.path.exists(file_name)):
os.remove(file_name)
else:
print("要删除的文件不存在!")