QQ空间,这个曾经陪我们从童年到少年再到成年,从2G时代再到如今的4G末,占据了我们太多的青春回忆,如今好友空间动态更新的不在像从前那样频繁。依稀记得当年的好友买卖,抢车位再或者情侣空间,现在想想那时候真的很幼稚,那就是我们傻逼的童年,什么互踩,火星文,跑堂见证了我们无忧无虑的童年。

有时候看看QQ推送的"那年今日",看到自己好几年前发的动态,说的傻话,自己都怕了自己。有时候看到好朋友几年前的动态,不由笑骂道,这孙子,怎么这么2! 即使现在不怎么用QQ了,有时候看看曾经发的说说还有空间的留言。即使让我再尴尬也不舍得删,因为那都是青春满满的回忆。

空间留言上千条,说说也比较多,一页一页的翻比较麻烦。索性就把这些数据都下载到本地。同理我们也可以导出全部联系人的说说和留言板。

Selenium

由于访问好友留言板需要登录,为了方便起见我们使用Web应用程序测试的Selenium工具。该工具可以用于单元测试,集成测试,系统测试等等。它可以像真正的用户一样去操作浏览器等,支持Mozilla Firefox、Google Chrome、Safari、Opera、IE等等浏览器。

使用这个工具之前我们需要安装selenium库和下载相应浏览器的驱动。然后通过分析QQ空间登录界面我们发现默认是扫码登录,因此需要切换成账号密码登录。

通过分析html标签属性,我们发现 id="switcher_plogin",是个切换登录的全局唯一属性。同理我们再需要找到账号、密码输入框和点击登录的元素就可以用selenium模拟登录了

登录部分代码如下:

from selenium import webdriver

driver = webdriver.Chrome()
# 获取谷歌浏览器驱动
driver = webdriver.Chrome()
# 登录网站
driver.get('https://i.qq.com')
# 选择账号密码登录
driver.switch_to_frame('login_frame')
# 点击输入框获取输入
driver.find_element_by_id('switcher_plogin').click()
# 输入账号
driver.find_element_by_id('u').send_keys('你的qq号')
# 输入密码
driver.find_element_by_id('p').send_keys('qq密码')
# 点击登录
driver.find_element_by_id('login_button').click()

  

工作前的参数准备

通过查看开发者工具中的请求我们发现,登录之后每次请求除了携带必要的参数以外,还携带了登录获取的token和g_tk。token我们可以从网页源代码中直接获取,但是g_tk在源代码中没有,根据以往经验第一步只能从js中查看,果然发现了一段加密代码,再结合上下文发现是从cookie中取出“p_skey”的值再经过一系列操作就是g_tk的值了。因为我们需要先获取cookie,然后再通过cookie获取g_tk。

部分js加密逻辑代码

if (e) {
if (e.host && e.host.indexOf("qzone.qq.com") > 0) {
try {
t = parent.QZFL.cookie.get("p_skey")
} catch(e) {
t = QZFL.cookie.get("p_skey")
}
}
............
} "g_tk=" + QZFL.pluginsDefine.getACSRFToken(t) QZFL.pluginsDefine.getACSRFToken._DJB = function(e) {
var t = 5381;
for (var n = 0,
r = e.length; n < r; ++n) {
t += (t << 5) + e.charCodeAt(n)
}
return t & 2147483647
};
 

获取token && cookie && g_tk代码

"""
获取g_tk的值
"""
def get_g_tk(cookie):
hashes = 5381
for letter in cookie['p_skey']:
hashes += (hashes << 5) + ord(letter)
return hashes & 0x7fffffff # 获取登录之后的cookie信息
cookie = {}
for elem in driver.get_cookies():
cookie[elem['name']] = elem['value']
# 获取g_tk
g_tk = get_g_tk(cookie)
# 利用xpath获取登录之后的网页源代码
html = driver.page_source
xpath = r'window\.g_qzonetoken = \(function\(\)\{ try\{return "(.*?)";}'
# 通过xpath 获得登录后的token
token = re.compile(xpath).findall(html)[0]
 

开始搞事

破解了一个简单的反爬虫,下面就可以编写正式的爬虫代码了,首先确定我们目标url、通过浏览器分析响应的json对象、编写headers

因为每次请求都需要携带登录信息,为了方便我们用到了session类,其次观察相应我们发现返回的response有无用的字符,因此需要进行截取

headers = {
'authority': 'user.qzone.qq.com',
'method': 'GET',
'scheme': 'https',
'accept-language': 'zh-CN,zh;q=0.9',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
} def get_resp(cookie, g_tk, token, page):
session = requests.session()
# 将cookie字典转换成RequestsCookieJar
c = requests.utils.cookiejar_from_dict(cookie)
# 将headers 放入session
session.headers = headers
# RequestsCookieJar复制给session
session.cookies = c
# 访问留言板的url
url = f'https://user.qzone.qq.com/proxy/domain/m.qzone.qq.com/cgi-bin/new/get_msgb?uin={登陆的qq}&hostUin={要查询留言内容的QQ号}&start={page}&num=10&g_tk={g_tk}&qzonetoken={token}'
print(url)
response = session.get(url)
# 截取无用的字符
resp_text = response.text[10: -3]
# 转为json
resp_json = json.loads(resp_text)
return resp_json

  

 

上面的方法,只是获得了某一页的接口相应,我们通过json获取留言总数,再除以每页的条数,就可以知道总页数了。然后再遍历去取每页的数据,为了方便查看将数据保存在csv文件中,另外将留言内容保存在txt文件中,生成词云。

def get_zone_xx(cookie, g_tk, token, page=0):
# 初始化请求为了取总条数
resp_json = get_resp(cookie, g_tk, token, page)
# 总条数
total = resp_json['data']['total']
print(f'共{total}条留言信息')
# 总页数
size = int(total/10 + 1)
# 已经读取的信息条数
use_page = 0
# 保存每条数据信息,生成csv文件用
content_arr = []
for i in range(0, size):
# 请求每一页的内容
resp_json = get_resp(cookie, g_tk, token, i)
# 当条数大于或等于总条数 跳出循环
if use_page >= total:
break
# 从每页数据中取出需要的字段值
for comment in resp_json['data']['commentList']:
use_page += 1
print(f'当前正在读取第{use_page}条')
page_json = []
# 留言日期
page_json.append(comment['pubtime'])
# 昵称
page_json.append(comment['nickname'])
# 内容
content = replace_html(comment['htmlContent'])
# 将内容写入文本 生成词云用
with open('zone_text111.txt', 'a') as f:
f.write(content) page_json.append(content)
content_arr.append(page_json)

  

 

生成csv文件

# 将总数据转化为data frame再输出
df = pd.DataFrame(data=content_arr,
columns=['留言日期', '昵称', '留言内容'])
df.to_csv('QQ_ZONE.csv', index=False, encoding='utf-8_sig')
print('已保存为csv文件.')

  

运行上面代码生成csv文件部分内容如下

生成词云(wordcloud)代码如下

from wordcloud import WordCloud
import matplotlib.pyplot as plt
with open('zone_text.txt','r') as f:
mytext = f.read() font = r'C:\Windows\Fonts\simfang.ttf'
wc = WordCloud(collocations=False, font_path=font, width=1400, height=1400, margin=2).generate(mytext)
plt.imshow(wc)
plt.axis("off")
plt.show() plt.show()

  

运行结果如下:

写在最后

上面的代码并没有太复杂,也许是触景生情,也许是对现在朋友圈各种乱七八糟的信息产生了抵触,所以试着去回忆青春的那些往事。
朋友圈和空间并不能去衡量一个人是是否成熟,但是对于大部分90后来说,空间真的是承载了太多纯真的回忆。不忘初心,砥砺前行!!!


公众号 程序员共成长 内回复【空间】,获取源代码

本文首发于公众号 程序员共成长 公众号内回复 [礼包] 即可领取优质资源,包括但不限于Java、Python、Linux、数据库、大数据、架构、测试、前端、ui以及各方向电子书

90后的青春,定格在被淡忘的QQ空间里的更多相关文章

  1. 一位90后的自述:如何从年薪3w到30w

    作者介绍:90后生人/男/二本本科/世界500强技术主管 1.引言 上海小胖,曾就职于pwc(普华永道)担任TechLeader,带领DS(Data Scientist)团队完成全美医疗保险大数据项目 ...

  2. 一位90后程序员的自述:如何从年薪3w到30w

    ▌自我介绍 引用赵真老师的一首歌<过去不是错>中的一句话:过去不是过错,毕竟我们也开心过.过去不是过错,何必愧疚不知所措. 我们这一代人,我相信多少都会有人和我一样,坚持过一个游戏,叫 D ...

  3. 【转载】阎焱:90后创业是扯淡 大量O2O和P2P公司濒临倒闭

    真正创业成功的大部分是年龄在30岁到38岁之间,很多90后基本什么都不懂.从历史来看,在这样的人口大国,集体性行为,无论是政治的还是经济的,基本都是导致灾难性后果. 10月14日消息,赛富基金创始首席 ...

  4. 月薪25K的90后程序员,他们都经历了什么?

    如果说薪资是检验一家公司对程序员认可的标准,那么年纪轻轻就能达到月薪 25K,一定程度上说明了公司对他创造的价值的认可. 深访10+ 名月薪25K的程序员,发现他们最常见的三种成长途径是…… 在公司发 ...

  5. QQ市场总监分享:黏住90后的独门攻略

    转自:http://www.gameres.com/476003.html 90后的关键词 1. 品质生活 90后是怎么样的一群人?他们注重生活的品质. 他们比我们更爱享受,或者说他们不像我们一样认为 ...

  6. 季逸超:90后IT少年的“盖茨梦”

    2月15日,"90后"独立开发者季逸超在其微博称,个人获得徐小平和红杉资本投资,成立了Peak Labs--以贝尔和施乐为目标的实验室. 谁是季逸超?他现年20岁,曾单独一人做出猛 ...

  7. 一位90后程序员的自述:如何从年薪3w到30w!

    初入职场之时,大多数人都应该考虑过这样的一个问题,如何找到一种实用,简化web流程的方法,在工作之中能有所提升和突破. 学好哪些?基础必须精通! 九层之塔,起于垒土;千里之行,始于足下.入门之前,这些 ...

  8. 90后iOS开发者的出路,如何规划30岁前的自己(程序员必修课)

    前言: 最近发生了一些和我们没有直接关系但是有间接关系的事情.比如华为“清洗”高龄基层员工,比如游戏公司2号员工拿不到股份而离职.先不说事实到底如何,起码很多码农是心有戚戚焉. 最近一年多也发生了一些 ...

  9. 饿了么CTO张雪峰:允许90后的技术人员“浮躁“一点

    编者按:今年4月,饿了么正式加入了阿里新零售战队,进一步加速其在本地生活市场的扩张速度.在创业9年的时间中,饿了么在外卖领域经历了真正的“从0到1”,尤其是在外卖平台的技术升级方面,越过了一个又一个的 ...

随机推荐

  1. Mybatis配置详解

    一.SqlSession的使用范围说明  1.SQLSessionFactoryBuilder   通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory, ...

  2. surging 微服务引擎 1.0 正式发布

    surging 是一个分布式微服务引擎,提供高性能RPC远程服务调用,服务引擎支持http.TCP.WS.Mqtt协议,采用Zookeeper.Consul作为surging服务的注册中心,集成了哈希 ...

  3. 微软XAML Studio - WPF, Sliverlight, Xamarin, UWP等技术开发者的福音

    目录 编辑器功能 数据源功能 调试数据绑定 伟大的开始 我们来一起实践吧 最近又在继续倒腾WPF的项目,继续使用Caliburn.Micro和Xceed来堆代码.每次调试xaml上的binding,都 ...

  4. RabbitMq在CentOs7下的完整安装步骤,带你踩坑

    1.前言 因为公司项目中用的RabbitMq来做消息处理,自己以前没有接触过,所以想自学一下.然额,光安装就花了6.7个小时才搞定,中间还换过一个版本,综合国内外博客才最终将所有安装中遇到的问题解决掉 ...

  5. .NETCore 新型 ORM 功能介绍

    简介 FreeSql 是一个功能强大的 .NETStandard 库,用于对象关系映射程序(O/RM),支持 .NETCore 2.1+ 或 .NETFramework 4.6.1+. 定义 IFre ...

  6. Spring WebFlux开门迎客,却来了一位特殊客人

    话说Spring WebFlux已经出现有一段时间了,但是知道他的人并不是很多.这让他很是闷闷不乐. 还有更惨的是,那些敢于吃螃蟹的人在尝试了他之后,有的竟把代码重新改回到Spring MVC的同步模 ...

  7. 企业级Harbor介绍及安装

    企业级Harbor介绍及安装 一.Harbor介绍 VMware公司最近开源了企业级Registry项目Harbor,其的目标是帮助用户迅速搭建一个企业级的Docker registry 服务.它以D ...

  8. [PHP] debug_backtrace()可以获取到代码的调用路径追踪

    查看代码的时候,看到有使用这个函数,测试一下 1.debug_backtrace()可以获取到代码的调用追踪,以数组形式返回 2.debug_print_backtrace() — 打印一条回溯,直接 ...

  9. 【学习笔记Part 2● MySQL】

    数据库 为什么要用数据库 如何去存放数据?生活中有各种各样的数据.比如说人的姓名.年龄.成绩等.平时我们记录这些信息都是记在大脑中.人的记忆力有限,不可能什么都记住.所以后来人们把数据记录在石头上–& ...

  10. SQLServer之修改数据库架构

    修改数据库架构注意事项 用户与架构完全分离. ALTER SCHEMA 仅可用于在同一数据库中的架构之间移动安全对象. 若要更改或删除架构中的安全对象,请使用特定于该安全对象的 ALTER 或 DRO ...