首页 > 技术文章 > Python|爬虫|爬取QQ空间电脑版日志模板

shandianchengzi 2021-07-30 16:22 原文

效果

代码以及结果均在Gitee仓库中:https://gitee.com/shandianchengzi/a-collection-of-reptiles。python-frame.py即是爬取日志模板的文件,可直接运行。

运行结果

在这里插入图片描述

模板中免费的部分

在这里插入图片描述

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

损坏的模板

▽ 我以为我捡了个漏
在这里插入图片描述
▽ 实际上
在这里插入图片描述

小彩蛋

▽ “限时免费”的林丹模板
在这里插入图片描述

代码

# author: shandianchengzi
# description: get templates of qq diary, saving as "qq日志模板.xlsx". Result: 43 free, 4 damaged.
# status: complete
import json
import requests
import pandas as pd
import re
from time import sleep
url="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个,全部点一遍都比找出生成规律划算。因此该问题没有解决方案。

推荐阅读