庸人自谈爬虫二三事——兴之所至,心之所安,尽其在我

往期文章

爬虫摸索中~~(PS:小小爬虫,何惧哉?且到明日,再看今朝。)


前言

  最近沉迷于法环世界,惊艳之余,风烛残年,些许手残!手游方面,亦有涉猎。某日,见一小程序,可进行抽卡分析。于是乎,自发其想,以此为鉴,锻吾其手,终不再残!遂有此文!(小白编个理由也不容易啊)

一、环境

  IDE: VSCode + python3
  思路:利用脚本分析网页结构,抓取所需数据,保存在CSV文件中,对采集数据进行统计,得出非欧检测定律!

二、Python库

from time import sleep
import requests
import csv
import pandas

  其中,抓虫数据保存时使用Python的CSV库,后来数据分析时使用pandas库(需要通过pip install pandas安装)。正好两种方法,大家也可以体验一下。(我不想说是我太懒,不想统一了)

三、操作步骤

1.获取目标数据

(1) 思路一:网页抓取

  这部分内容不想多说,网上有教程,我也是看到链接获得方法后,才决定尝试下这个事情的。比如,本次目标游戏的网络连接,大概信息如下:

https://***/hk4e/event/e20190909gacha/index.html?authkey_ver=1&sign_type=2&auth_appid=webview_gacha&init_type=301&gacha_id=511f33032f12c85d8f8092341cba68c312b512&timestamp=1644969002&lang=zh-cn&device_type=pc& (此处省略一万字) &game_biz=hk4e_cn#/log

  打开后,就是自己的抽卡记录,通过分析发现,页面上<div class="log-item-row">这一行就可以了,把每一行提取出来,保存呗,用正则可以。

(2) 思路二:接口调用

  本来准备这么做时,想起来,还要处理翻页的问题,但翻页后页面URL没有变化,说明使用了ajax方式更新。
  于是F12打开调试器,点击“网络”标签,点击“下一页”,发现有新的请求,如下

https://hk4e-api.mihoyo.com/event/gacha_info/api/getGachaLog?authkey_ver=1&sign_type=2&auth_appid=webview_gacha&init_type=301&(*****) &game_biz=hk4e_cn&gacha_type=301&page=2&size=6&end_id=1646197560000544578

  查看“响应”,是一个json数组。仔细分析响应数组,好家伙,所有需要的信息都在这里面,这样多好,我们就不需要去分析网页结构了,直接用API接口的响应,这多方便了。于是,自此,告别了之前的想法,直接处理JSON数组,方便快捷。除此之外,还有一点,这里,每个抽卡记录,都有个ID,可以作为标识,而网页抓取上没有,不好进行每次查询去重。(因为厂商只提供6个月内的记录)
  通过对比,我们发现,

# 第一页
getGachaLog?authkey_ver=1&sign_type=2&auth_appid=w…pe=301&page=1&size=6&end_id=0
getGachaLog?authkey_ver=1&sign_type=2&auth_appid=w…pe=301&page=3&size=6&end_id=1646197560000507878
# 后几页

  通过对比,我们发现只有每个的end_id不一样,经分析发现,end_id为当前页面最后一条记录的ID。OK,这样我们就能得到全部信息,开始写代码了。

获取接口数据代码如下:

# 获取抽卡数据,url为请求的首页地址
def get_info(url):
    res = requests.get(url)
    #直接将结果软化为JSON数组
    resArr = res.json()
    # 最后一条记录ID
    url_id = resArr['data']['list'][-1]['id']
    # info_lists为全局数组变量
    info_lists.append(resArr['data']['list'])
    # 延时1秒是为了防止请求太频繁,服务器拒绝
    sleep(1)
    for i in range(2, num): #num为预计设计的最多请求页面数,比如100等,可多设,可自动跳出循环
        # 构造下一页的请求地址
        url_tail = "&gacha_type=301&page={}&size=6&end_id={}".format(str(i), url_id)
        res = requests.get(url_head + url_tail)
        resArr = res.json()
        # 服务器拒绝或记录结束,则跳出循环;否则,请求下一页数据
        if (resArr['data'] == None) or (resArr['data']['list'] == []):
            break
        else:
            print(resArr['data']['list'])
            info_lists.append(resArr['data']['list'])
            url_id = resArr['data']['list'][-1]['id']
            sleep(1)
            
if __name__ == '__main__':
	# 在主程序中调用
	get_info(url_head + url_tail)
    f = open(qyFilePath,'a+', encoding='utf-8', newline="")
    csv_writer = csv.writer(f)
    csv_writer.writerow(["序号","星级","类型","名字","时间","记录ID"])
    j = 1
    for info_list in info_lists:
        for item in info_list:
            try:
                csv_writer.writerow([j,item["rank_type"],item["item_type"],item["name"],item["time"], str(item["id"])])
                j = j+1
            except UnicodeEncodeError:
                pass

    f.close()

2.整理保存数据

  获取数据后,需要将数据归整,与以往数据合并,因为只能查询6个月的,所以每次查询只有最新的6个月,之前的数据保存后,还需进行合并,并按照记录ID号,从大到小,也就是时间从现在到过去排列。

往期数据合并归整代码如下:

# 将抽卡数据合并归整
def dealData(path):
    # 读取往期数据
    df = pandas.read_csv(path, encoding='utf8')
    # 去掉重复行
    df2 = df.drop_duplicates(subset=None, keep='first', inplace=False)
    # 删除重复的标题行(自己的代码原因,每次都写入了标题行,大家可以自行修正)
    row_indexes = df2[df2["序号"] == "序号"].index
    # 执行删除
    df2.drop(row_indexes, inplace=True)
    #将整理后的数据更新原文档
    data = df2.sort_values(by="记录ID" , ascending = False)
    data.to_csv(path, mode='w', index=False)  

3.统计分析数据

  抽卡游戏,是欧是非,关键看脸。这样就可以统计下五星角色每次抽取所需次数,简单数个数:一、二、三……就是读取刚才生成的文件,然后记数,生成个新的统计分析文件,代码如下:

# 统计五星所需抽卡次数
def statisticData(path1, path2):
    f = pandas.read_csv(path1, encoding='utf8')
    df_in = pandas.DataFrame(f)
    # 读取数据,倒序排列
    data = df_in.sort_values(by="序号" , ascending = False)
    summary = 0
    df_out = pandas.DataFrame( columns =["序号", "五星角色", "次数"])
    lineIndex = 0
    for i,item in data.iterrows():
        summary = summary + 1
        i = i + 1
        if item['星级'] == 5: # 抽到5星,重新计数
            df_out.loc[lineIndex] = [lineIndex + 1, item['名字'], summary]
            lineIndex = lineIndex +1
            summary = 0
    if summary != 0: # 最新情况,如果未抽到五星,则显示现已抽卡数
        df_out.loc[lineIndex] = [lineIndex + 1, "", summary]
	# 按最新到以前的顺序排列抽卡统计信息
    data = df_out.sort_values(by="序号" , ascending = False)
    data.to_csv(path2, mode='w', index=False)

  至此,我们就可以鉴定自己的血统了,欧非天注定,命运靠打拼啊!

总结

  一点心得,雕虫小技,庸人自谈,欢迎交流!如有不妥,敬请指正!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值