用 Python 爬取 QQ 空间说说和相册

文 | 某某白米饭

来源:Python 技术「ID: pythonall」

QQ 空间在 2005 年被腾讯开发,已经经历了 15 个年头,在还没有微信的年代,看网友发表的心情、心事、照片大多都在 QQ 空间的里。它承载了80、90 后的大量青春,下面我们一起用 selenium 模块导出说说和相册回忆青春吧

安装 selenium

selenium 是一个在浏览器中运行,以模拟用户操作浏览器的方式获取网页源码,使用 pip 安装 selenium 模块

1pip install selenium 2

查看 chrome 浏览器版本并下载 对应的 chrome 浏览器驱动

http://npm.taobao.org/mirrors/chromedriver 网址中找到相同版本的 chrome 驱动,并放在 python 程序运行的同一个文件夹中

登陆

按 F12 检擦网页源代码,找到登录和密码的文本框,如下图所示

1def login(login_qq,password, business_qq): 2    ''' 3    登陆 4    :param login_qq: 登陆用的QQ 5    :param password: 登陆的QQ密码 6    :param business_qq: 业务QQ 7    :return: driver 8    ''' 9    driver = webdriver.Chrome() 10 11    driver.get('https://user.qzone.qq.com/{}/311'.format(business_qq))  # URL 12    driver.implicitly_wait(10)  # 隐示等待,为了等待充分加载好网址 13    driver.find_element_by_id('login_div') 14    driver.switch_to.frame('login_frame')  # 切到输入账号密码的frame 15    driver.find_element_by_id('switcher_plogin').click()  ##点击‘账号密码登录’ 16    driver.find_element_by_id('u').clear()  ##清空账号栏 17    driver.find_element_by_id('u').send_keys(login_qq)  # 输入账号 18    driver.find_element_by_id('p').clear()  # 清空密码栏 19    driver.find_element_by_id('p').send_keys(password)  # 输入密码 20    driver.find_element_by_id('login_button').click()  # 点击‘登录’ 21    driver.switch_to.default_content() 22 23    driver.implicitly_wait(10) 24    time.sleep(5) 25 26    try: 27        driver.find_element_by_id('QM_OwnerInfo_Icon') 28        return driver 29    except: 30        print('不能访问' + business_qq) 31        return None 32

说说

登录 QQ 后默认的页面就在说说的界面,显示一页的说说是滚动加载的,必须要多次下拉滚动条后才能获取到该页所有的说说,然后用 BeautifulSoup 模块构建对象解析页面,下图是放说说的 iframe

1def get_shuoshuo(driver): 2     3    page = 1 4    while True: 5        # 下拉滚动条 6        for j in range(1, 5): 7            driver.execute_script("window.scrollBy(0,5000)") 8            time.sleep(2) 9 10        # 切换 frame 11        driver.switch_to.frame('app_canvas_frame') 12        # 构建 BeautifulSoup 对象 13        bs = BeautifulSoup(driver.page_source.encode('GBK', 'ignore').decode('gbk')) 14        # 找到页面上的所有说说 15        pres = bs.find_all('pre', class_='content') 16 17        for pre in pres: 18            shuoshuo = pre.text 19            tx = pre.parent.parent.find('a', class_="c_tx c_tx3 goDetail")['title'] 20            print(tx + ":" + shuoshuo) 21 22        # 页数判断 23        page = page + 1 24        maxPage = bs.find('a', title='末页').text 25 26        if int(maxPage) < page: 27            break 28 29        driver.find_element_by_link_text(u'下一页').click() 30        # 回到主文档 31        driver.switch_to.default_content() 32        # 等待页面加载 33        time.sleep(3) 34

相册

下载相册里面的照片需要 selenium 模块模拟鼠标一步步点击页面,先点击上方的相册按钮,进去就是多个相册的列表,下图是单个相册的超链接

在单个相册中点击照片,界面如下图

1def get_photo(driver): 2     3    # 照片下载路径 4    photo_path = "C:/Users/xxx/Desktop/photo/{}/{}.jpg" 5     6    # 相册索引 7    photoIndex = 1 8 9    while True: 10        # 回到主文档 11        driver.switch_to.default_content() 12        # driver.switch_to.parent_frame() 13        # 点击头部的相册按钮 14        driver.find_element_by_xpath('//*[@id="menuContainer"]/div/ul/li[3]/a').click() 15        #等待加载 16        driver.implicitly_wait(10) 17        time.sleep(3) 18        # 切换 frame 19        driver.switch_to.frame('app_canvas_frame') 20        # 各个相册的超链接 21        a = driver.find_elements_by_class_name('album-cover') 22        # 单个相册 23        a[photoIndex].click() 24 25        driver.implicitly_wait(10) 26        time.sleep(3) 27        # 相册的第一张图 28        p = driver.find_elements_by_class_name('item-cover')[0] 29        p.click() 30        time.sleep(3) 31 32        # 相册大图在父frame,切换到父frame 33        driver.switch_to.parent_frame() 34        # 循环相册中的照片 35        while True: 36            # 照片url地址和名称 37            img = driver.find_element_by_id('js-img-disp') 38            src = img.get_attribute('src').replace('&t=5', '') 39            name = driver.find_element_by_id("js-photo-name").text 40 41            # 下载 42            urlretrieve(src, photo_path.format(qq, name)) 43 44            # 取下面的 当前照片张数/总照片数量 45            counts = driver.find_element_by_xpath('//*[@id="js-ctn-infoBar"]/div/div[1]/span').text 46 47            counts = counts.split('/') 48            # 最后一张的时候退出照片浏览 49            if int(counts[0]) == int(counts[1]): 50                # 右上角的 X 按钮 51                driver.find_element_by_xpath('//*[@id="js-viewer-main"]/div[1]/a').click() 52                break 53            # 点击 下一张,网页加载慢,所以10次加载 54            for i in (1, 10): 55                if driver.find_element_by_id('js-btn-nextPhoto'): 56                    n = driver.find_element_by_id('js-btn-nextPhoto') 57                    ActionChains(driver).click(n).perform() 58                    break 59                else: 60                    time.sleep(5) 61 62        # 相册数量比较,是否下载了全部的相册 63        photoIndex = photoIndex + 1 64        if len(a) <= photoIndex: 65            break 66 67

示例结果

总结

大家在看十几年前的说说和照片是不是感觉满满的黑历史快要溢出屏幕了。时光荏苒、岁月如梭,愿一切安好。

-------------------********************************** End **********-------------**-----********-**********************************

往期精彩文章推荐:

欢迎各位大佬点击链接加入群聊【helloworld开发者社区】:https://jq.qq.com/?_wv=1027&k=mBlk6nzX进群交流IT技术热点。

本文转自 https://mp.weixin.qq.com/s/05YvMwzVy8n84fKXWo4y9w,如有侵权,请联系删除。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )