Py学习  »  Python

用Python对空间进行爬取

python • 8 年前 • 665 次点击  


运行环境

版本

Python3.5

系统

Windows 10

IDE

pycharm

数据处理软件Excel

附录:带好小板凳,前排出售瓜子饮料


需要的库

需求分析及源码

分析

        QQ空间是需要登陆才能爬取的,所以说首先要做的事进行登陆,这里有两种思路进行模拟登陆:

(1)、用selenium+Chrome 进行自动化检测登陆,接着用扫码或者账号自动输入都是可以的,然后获取cookies,再传入requests.Session().get()对要爬取好友的空间进行爬取。

(2)、用opener 和 cookielib 进行对网站cookie的获取,然后再传入requests.Session().get()

我在这里使用的是第一种方法。

Cookies的使用详情在这里: cuiqingcai.com/968.html

Session的使用详情在这里:cnblogs.com/whatbeg/p/5

2、当我们登陆上的时候进行抓包(炒鸡重要),然后在开发者工具里,找到这个文件,打开之后发现这就是我们想要的数据,所以......我们想要抓取的文件是找到了,但是对应的请求头呢?

        在这里的headers,点开后发现,这里有个Request URL,这个就是我们要的URL

        再点开Query发现,URL的数据这里都有,但是仔细分析后发现。。。。这里有些东西我们不知道是怎么来的,就是这里的g_tk和qzone_token,不是那么很规则,这个时候,我们多点开几个页面试试,我们会发现,只有这两个参数是改变的,其余的参数都是不变的,所以我们只要解决这两个参数,我们就可以请求到这个json数据。好,接下来要解决的问题就是如何获得g_tk和qzonetoken这两个数据。


        这里有个找参数的方法1、可以先在网页上对源代码进行查找,有些参数是隐藏在网页的源码里的,看存不存在,如果存在,用xpath或者bs4库进行解析(我在这里用的是正则表达式来提取),如果不存在,就要用下面的方法。

查找参数

        如果网页源码里找不到,可能就是被加密了,水平实在有限,没能破解的出,所以 就百度了一下QQ空间的加密方式,在CSDN的博客上发现了这个解密的代码。

        所以在这个登陆模块,我们完成的是登陆上去,获取到相应的参数,然后返回来,以备后用。好啦,参数获取完了,要获取数据了,下面这个模块就是对数据的获取。

数据获取

        有了上面的获取的三个数据,那登陆到QQ空间就是一点问题都木有啦,然后创建一个会话(Session()),保持本地与服务器的连接。一个get,我们就把json格式的数据爬取下来了。

但是!!!不能一直爬取下去,所以要对爬取的内容进行一个判别是否爬取结束

如果爬取结束了,就break出循环了,然后再爬取下一个好友的动态。

数据的清洗

        还没有学习数据库的内容,所以就将爬取的json文件转为字典,然后对字典进行处理保存为csv文件。用了一个xlwt的库,这个库可以建立并读写数据

然后保存为文件。

注意!!!这里一定要加入异常的处理,因为有些人的QQ空间是不开放的,所以遇到不开放的空间就会出错,为了让程序能够正常的执行,所以必须要加异常处理。

点击运行按钮,一段时间后,就可以查看你爬取的成果了,爬取了6W+的数据.....

数据处理

        Python有丰富的数据处理的库,numpy pandas scipy ,由于存储为csv文件,当然电脑上也有tableau和matlab,但是对这两个软件不太熟悉,就就直接用Excel软件进行处理。

以下是我用Excel做的几张图:

源码:


import requestsfrom selenium import webdriverfrom PIL import Imageimport xlwtimport timeimport reimport jsonfrom collections import Iterableimport csvn = 1header = {'Host': 'h5.qzone.qq.com',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0',
    'Accept': '*/*',
    'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
    'Accept-Encoding': 'gzip, deflate, br',
    'Referer': 'https://user.qzone.qq.com/790178228?_t_=0.22746974226377736',
    'Connection':


    
'keep-alive'}#对表格进行处理file = xlwt.Workbook()table = file.add_sheet('sheet name', cell_overwrite_ok= True)table.write(0,1,"日期")table.write(0,2,"时间")table.write(0,3,"年份")table.write(0,4,"月份")table.write(0,5,"时间点")table.write(0,6,"图片数量")table.write(0,7,"评论数量")table.write(0,8,"手机型号")table.write(0,9,"经度")table.write(0,10,"地点")table.write(0,11,"纬度")table.write(0,12,"位置")table.write(0,13,"内容")#从邮箱里到导出的联系人,然后进行读取操作def getfriends():
    


    
csv_reader = csv.reader(open('qq.csv'))
    friend = []
    for row in csv_reader:
        friend.append(row[3])
    friend.pop(0)
    friends = []
    for f in friend:
        f = f[:-7]
        friends.append(f)
    return friends# 这个函数用来解决腾讯g_tk加密算法的函数def get_g_tk(cookie):
    hashes = 5381
    for letter in cookie['p_skey']:
        hashes += (hashes << 5) + ord(letter)  # ord()是用来返回字符的ascii码
    return hashes & 0x7fffffff#这个函数是用来获取cookie,g_tk,g_qzontoken这三个数据def Login_QQ():
    driver = webdriver.Chrome()             
    start_url = "https://qzone.qq.com/"
    driver.get(start_url)
    time.sleep(10)
    cookie = {}
    for elem in driver.get_cookies():
        cookie[elem['name']] = elem['value']
    html = driver.page_source
    g_qzonetoken = re.search(r'window\.g_qzonetoken = \(function\(\)\{ try\{return (.*?);\} catch\(e\)',html)
    g_tk = get_g_tk


    
(cookie)
    driver.quit()
    print(g_qzonetoken.group(1))
    return (cookie, g_tk, g_qzonetoken.group(1))def spyder_info():
    s = requests.session()
    friends = getfriends()
    cookie, g_tk, g_qzonetoken = Login_QQ()
    for qq in friends:
        global n
        for i in range(1000):
            pos = i*20
            param = {
                'uin': qq,
                'ftype': '0',
                'sort': '0',
                'pos': pos,
                'num': '20',
                'replynum': '100',
                'g_tk': g_tk,
                'callback': '_preloadCallback',
                'code_version': '1',
                'format': 'jsonp',
                'need_private_comment': '1',
                'qzonetoken': g_qzonetoken
            }
            respond = s.get("https://h5.qzone.qq.com/proxy/domain/taotao.qq.com/cgi-bin/emotion_cgi_msglist_v6",
                                params=param, headers = header,cookies=cookie)
            r = re.sub("_preloadCallback", "", respond.


    
text)
            test = r[1:-2]
            Data = json.loads(test)
            if not re.search('lbs', test):  # 通过lbs判断此qq的说说是否爬取完毕
                print('%s说说下载完成' % qq)
                break
            try:
                for each_data in Data["msglist"]:
                    # 说说发表的日期1
                    table.write(n, 1, each_data["createTime"])
                    # 说说发表的时间2
                    table.write(n, 2, time.strftime("%H:%M:%S", time.localtime(each_data["created_time"])))
                    # 说说发表的年份3
                    table.write(n, 3, time.strftime("%Y", time.localtime(each_data["created_time"])))
                    # 说说发表的月份4
                    table.write(n, 4, time.strftime("%m", time.localtime(each_data["created_time"])))
                    # 说说发表的小时5
                    table.write(n, 5, time.strftime("%H", time.localtime(each_data[


    
"created_time"])))
                    # 统计图片的数量6,以及用的手机型号8
                    if "pic" in each_data:
                        table.write(n, 6, each_data["pictotal"])
                        table.write(n, 8, each_data["source_name"])
                    else:
                        table.write(n, 6, 0)
                        table.write(n, 8, "")

                    # 统计每个说说的评论数量7
                    if each_data["commentlist"]:
                        table.write(n, 7, each_data["commentlist"][-1]["tid"])
                    else:
                        table.write(n, 7, 0)

                    # 获取该条说说的发表位置:9,10,11,12
                    if "story_info" in each_data:
                        table.write(n, 9, each_data["story_info"]["lbs"]["pos_x"])
                        table.write(n, 11, each_data["story_info"]["lbs"]["name"])
                        table.write(n, 10, each_data["story_info"]["lbs"]["pos_y"])
                        table.write(n, 12,


    
 each_data["story_info"]["lbs"]["idname"])
                    else:
                        table.write(n, 9, "")
                        table.write(n, 11, "")
                        table.write(n, 10, "")
                        table.write(n, 12, "")

                    # 获取每一条说说的内容13
                    if each_data["content"]:
                        table.write(n, 13, each_data["conlist"][0]["con"])
                    else:
                        table.write(n, 13, "")
                    n = n + 1
            except:
                print("error")


    file.save("demo6.xls")#if '__name__' == '__main__':spyder_info()




今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/TKJzNdHGOk
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/4161