目录

  • 效果
    • 运行结果
    • 模板中免费的部分
  • 损坏的模板
    • 小彩蛋
  • 代码
  • 问题及解决方式
    • 1. 返回数据_callback({})而非json
    • 2. 获取封面图链接

注:2021/7/30做

效果运行结果

模板中免费的部分

excel已简单处理,可以根据顺序大致找到页码。
一共有43个免费模板,其中39个可用,4个损坏。

损坏的模板

▽ 我以为我捡了个漏

▽ 实际上

小彩蛋

▽ “限时免费”的林丹模板

代码

# author: shandianchengzi# description: get templates of qq diary, saving as "qq日志模板.xlsx". Result: 43 free, 4 damaged.# status: completeimport jsonimport requestsimport pandas as pdimport refrom time import sleepurl="https://h5.qzone.qq.com/proxy/domain/mall.qzone.qq.com/cgi-bin/v3/cgi_get_letter_paper"headers={    'Accept': '*/*',    'Accept-Encoding': 'gzip, deflate, br',    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',    'Content-Type': 'application/json; charset=utf-8',    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 Edg/90.0.818.56',}headers['Cookie']="" #不需要填params={    'mallIds':'',    'keyWord':'',    'vip':0,    'g_tk':'1002114705',    'pageNum':3,    'pageCount':5,}datalist = []  #用来存储爬取的网页信息byYourself={    'number':5, #一次爬取的个数,建议5个,否则得到的数据会对不上}def LoadJson(JSON):    try:        return json.load(JSON)    except:        #找到"({"作为开始标志 和"})"作为结束标志之间的所有信息[jsonp格式]        return json.loads(re.match(".*?({.*}).*",JSON,re.S).group(1))def AddData(content):    for i in content['data']['items']:        i['name']=i['mall']['name']        i['attr']=i['mall']['attr']        datalist.append(i)        #print(i)def export_excel(export):    try:        #将字典列表转换为DataFrame        pf = pd.DataFrame(list(export))        #指定生成的Excel表格名称        file_path = pd.ExcelWriter('qq日志模板.xlsx')        #替换空单元格        pf.fillna(' ', inplace=True)        #输出        pf.to_excel(file_path, encoding='utf-8', index=False)        #保存表格        file_path.save()        print('保存成功!')    except Exception as e:        print("[-] Error = "+str(e))        print('无法导出为excel,请检查是否未关闭同名excel文件。正在重试……')        sleep(2)        export_excel(export)        def getData(total):    try:        params['pageCount']=byYourself['number']        pageTotal=int(total/byYourself['number'])+2        print('一共要加载',pageTotal,'页,请耐心等待:')        for i in range(1,pageTotal):            params['pageNum']=i            print('第',i,'页,',end='')            res = requests.get(url, params=params, headers=headers)            content=LoadJson(res.text)            AddData(content)    except Exception as e:        print("[-] Error = "+str(e))        print(res.text)    print(len(datalist))    export_excel(datalist)def myFunc():    datalist.clear()    res = requests.get(url, params=params, headers=headers)    #找到"({"作为开始标志 和"})"作为结束标志之间的所有信息[jsonp格式]    content=LoadJson(res.text)    total=content['data']['total']    print(total)    getData(total)myFunc()

问题及解决方式1. 返回数据_callback({})而非json

这种数据返回格式,使我们无法直接使用json.load(res.text)解析。

问题根源在于JSONP这种数据传输格式
ajax请求受同源策略影响,不允许进行跨域请求,而script标签src属性中的链接却可以访问跨域的js脚本,利用这个特性,服务端不再返回JSON格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。
比如,可用script标签直接指向不同域下的js脚本,在js脚本中加入这个函数。
本例中的_callback({})便是JSONP的典型应用。

解决方式:正则去掉_callback({})
参考https://blog.csdn.net/weixin_38208912/article/details/104208785。

def LoadJson(JSON):    try:        return json.load(JSON)    except:        #找到"({"作为开始标志 和"})"作为结束标志之间的所有信息[jsonp格式]        return json.loads(re.match(".*?({.*}).*",JSON,re.S).group(1))

2. 获取封面图链接

封面图的链接格式:
https://qzonestyle.gtimg.cn/qzone/space_item/pre/14/108942_1.gif
找了一下规律,明显是位置+ id + _1.gif。
可惜https://qzonestyle.gtimg.cn/qzone/space_item/pre/后面的14不是固定的值,我暂时没有去管它的生成规律,免费的只有39个,全部点一遍都比找出生成规律划算。因此该问题没有解决方案。