使用Python2.7和火狐浏览器下载QQ空间好友相册
说明:本文代码参考:http://haofly.net/python3-get-qqalbum/
20150903更新:本文仍存在部分相册不能下载的问题,本文代码不再维护,请移步至:使用Python2.7和火狐浏览器下载QQ空间好友相册(二)
不过由于QQ空间后台更新,本文根据QQ空间最新的JSONAPI做了改进
首先需要下载windows版本的curl,具体可以参考百度经验
下载地址:http://curl.haxx.se/download/?C=M;O=D
如果你是64位系统,建议下载curl-7.33.0-win64-nossl.zip
然后解压到D盘根目录下,如图
此时,你可以将D:\curl-7.33.0-win64-nossl这个路径添加到环境变量中,也可以在python代码中添加
接下来从火狐浏览器中复制两个curl
打开火狐浏览器-->F12-->网络-->打开下面两个网页,右键复制cURL
http://user.qzone.qq.com/[QQ号码]/4,这个是相册的cRUL,注意找fcg_list_album_v3开头的地址
点击某一个相册进入相片列表,找到相片的cURL,注意找cgi_list_photo开头的地址
先去掉地址中的压缩指令 --compressed(因为windows版本的CURL不支持压缩指令)
然后把地址用单引号括起来,然后复制到对应的代码中,如图
另外,还需要添加一个创建一个文本文件qqlist.txt添加QQ号码,该文本文件位于python脚本的同一目录下,每个号码一行,也可以用软件抓
python2.7代码如下:(运行之前请务必安装好windows版本的cURL)
# -*- coding: UTF-8 -*-
import os
import re
import subprocess
import shlex
import urllib2
import json
import datetime
import shutil
import cookielib
import Cookie# 添加curl的环境变量
os.putenv('PATH', 'D:\\curl-7.33.0-win64-nossl\\;' + os.getenv('PATH'))# 获取原始curl请求,相册fcg_list_album_v3相片cgi_list_photo
origin_album = 'fcg_list_album_v3'
origin_photo = 'cgi_list_photo'
origin_album = origin_album.replace('--compressed ', '')
origin_photo = origin_photo.replace('--compressed ', '')
# ------------------------------构造cookies开始-----------------------------------------------cookiestr = origin_photo[origin_photo.find('"Cookie:'): origin_photo.find('"', -1)]
cookie_str = cookiestr[cookiestr.find(':') + 2: cookiestr.find('"', 2)]
print cookie_str
cookie_domain = '.photo.store.qq.com'
cookie_path = '/'simple_cookie = Cookie.SimpleCookie(cookie_str) # Parse Cookie from str
cookiejar = cookielib.CookieJar() # No cookies stored yet
for c in simple_cookie:cookie_item = cookielib.Cookie(version=0, name=c, value=str(simple_cookie[c].value),port=None, port_specified=None,domain=cookie_domain, domain_specified=None, domain_initial_dot=None,path=cookie_path, path_specified=None,secure=None,expires=None,discard=None,comment=None,comment_url=None,rest=None,rfc2109=False,)cookiejar.set_cookie(cookie_item) # Apply each cookie_item to cookiejar
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar)) # Return opener# ------------------------------构造cookies结束-----------------------------------------------
# 获取目标QQ
fp = open('qqlist.txt', 'r')
qqlist = fp.readlines()
for i in range(len(qqlist)):qqlist[i] = qqlist[i][:-1]
fp.close()for target in qqlist:if len(target) == 0 : # 防止因为出现空行删除所有照片continuelog = { }log['qq'] = targetlog['access'] = 1 # 是否允许访问log['time'] = datetime.datetime.now() # 下载完成后记录花费的时间log['album_count'] = 0 # 相册总数log['photo_count'] = 0 # 照片总数print('当前QQ:' + target)try:os.makedirs('photos/' + target) # 建立相应的文件夹except:shutil.rmtree('photos/' + target) # 无论文件夹是否为空都移除该文件夹os.makedirs('photos/' + target)# 先得到正确的curl,然后执行获取json数据hostUin = origin_album.split('&hostUin=')[1].split('&')[0]curl = origin_album.replace(hostUin, target) # 替换被访问者curl = curl.replace('&pageNumModeSort=40', '&pageNumModeSort=100') # 显示相册数量args = shlex.split(curl)result = subprocess.check_output(args).decode('utf-8')jsonstr = result[result.find('(') + 1: result.find(')', -1) - 1] # json字符串,去除不标准的json数据output = json.loads(jsonstr) # 最终json数据if output['code'] == -3000: # 对不起,您尚未登录或者登录超时。print output['message']breakif output['code'] == -4009:log['access'] = 0 # 是否允许访问fp = open('photos/' + target + '/log.txt', 'w') # 日志文件,记录时间与数量fp.writelines(str(log))fp.close()continue# 相册没有分类时print jsonstralbumList = []if 'albumListModeSort' in output['data']: # 相册没有分类,目前这一类占大多数print 'type1'if output['data']['albumListModeSort'] == 'null':print 'noalbum'breakprint u'第一个相册名称:' + output['data']['albumListModeSort'][0]['name'] # 输出第一个相册名称albumList = output['data']['albumListModeSort']else: # 相册有分类print 'type2'print u'第一个相册名称:' + output['data']['albumListModeClass'][0]['albumList'][0]['name'] # 输出第一个相册名称albumList = [dict() for i in range(0, output['data']['albumsInUser'])]count = 0# 重新构造albumListfor i in range(0, len(output['data']['albumListModeClass'])):for j in range(0, output['data']['albumListModeClass'][i]['totalInClass']):albumList[count] = output['data']['albumListModeClass'][i]['albumList'][j]count = count + 1if count > output['data']['albumsInUser']: # 对跳出条件加强控制breaktheSameAlbumName = 0 # 防止相册同名for album in albumList:if not album: # 字典为空跳出,上面的output['data']['albumsInUser']是可访问相册数。continuelog['album_count'] += 1print u'当前相册:' + str(album['classid']) + album['name']if album['allowAccess'] == 0: # 相册无法直接访问(需要密码或者禁止访问)continue# album['id']就是照片列表的ID# 获取照片列表数据hostUin = origin_photo.split('&hostUin=')[1].split('&')[0]topicId = origin_photo.split('&topicId=')[1].split('&')[0]curl = origin_photo.replace(hostUin, target)curl = curl.replace(topicId, album['id'])curl = curl.replace('&pageNum=30', '&pageNum=600') # QQ空间每个相册最大貌似不会超过512args = shlex.split(curl)result = subprocess.check_output(args).decode('utf-8')jsonstr = result[result.find('(') + 1: result.find(')', -1) - 1] #json字符串output = json.loads(jsonstr) #json字符串转字典if (output['code'] == -4404):continue# 相册名里面会不会也有奇葩名字呢filt = re.compile(r'\\|/|:|\*|\?|<|>|\||\.')album['name'] = re.sub(filt, '', album['name'])# 我服都服了,QQ空间居然还允许同名的相册。。。albumname = str(album['classid']) + album['name'].replace(' ', '')filelist = os.listdir('photos/' + target + '/')temp = albumname.encode('gbk') # encode的作用是将unicode编码转换成其他编码的字符串,由于文件列表filelist里是gbk编码,保存一致才能比较if (temp in filelist) or (len(albumname) == 0): # 编号,防止同名albumname = albumname + '_' + str(theSameAlbumName)theSameAlbumName += 1os.makedirs('photos/' + target + '/' + albumname)# 防止相片同名same = 0# 获取该相册下的每一张照片,如果相册为空,那么output['data']['photoList'] = None,output['data']['totalInAlbum']=0photoList = output['data']['photoList']if output['data']['totalInAlbum'] == 0:continuefor photo in photoList:log['photo_count'] += 1print(u'当前图片:' + photo['name'])# 图片格式由photo['phototype']字段(整型)控制# 1:jpg# 3:pngphototype = {'1': '.jpg', '2': '.gif', '3': '.png', '5': '.jpg', '10': '.jpg'}try:format = phototype[str(photo['phototype'])]except:format = '.jpg'# 建立文件夹并下载图片# QQ图片里面有太多的特殊字符了photoname = photo['name']filelist = os.listdir('photos/' + target + '/' + albumname)for i in range(len(filelist)):filelist[i] = filelist[i][:-4]photoname = photoname.replace(' ', '')# 文件名中不能有特殊字符filt = re.compile(r'\\|/|:|\*|\?|<|>|\||\.|\n|\t|\"')photoname = re.sub(filt, '', photoname)if (photoname in filelist) or (len(photoname) == 0):photoname = photoname + '_' + str(same)same += 1path = 'photos\\' + target + '\\' + albumname + '\\' + photoname + formattry:f = opener.open(photo['url'])with open(path, "wb") as code:code.write(f.read())except urllib2.HTTPError as e:print('保存图片出错')fp = open('photos/' + target + '/log.txt', 'w')# 日志文件,记录时间与数量log['time'] = (datetime.datetime.now() - log['time']).secondslog['time'] = str(log['time']) + 's'fp.writelines(str(log))fp.close()print('当前QQ:' + target + '下载完毕')
开始用urllib.urlretrieve()下载的时候速度极慢,经过验证之后证实是HTTP协议版本的问题urllib使用0.9和1.0版本,换urllib2之后果然快多了
下面是改进过程中用到的测试代码,有兴趣的可以看下
#-*- coding: UTF-8 -*-import os
import shlex
import subprocess
import json# 添加curl的环境变量
os.putenv('PATH', 'D:\\curl-7.33.0-win64-nossl\\;'+os.getenv('PATH'))
# 获取原始curl请求
origin_album = fcg_list_album_v3
origin_photo = cgi_list_photo#相册中的ID对应链接中的topicId;
target=QQ号码print target
print origin_albumhostUin=origin_album.split('&hostUin=')[1].split('&')[0]
print hostUin
# 先得到正确的curl,然后执行获取json数据
curl = origin_album.replace(hostUin, target) # 替换被访问者
curl = curl.replace('&pageNumModeSort=40', '&pageNumModeSort=100') # 显示相册数量
args = shlex.split(curl)
result = subprocess.check_output(args).decode('utf-8')
jsonstr=result[result.find('(') + 1 : result.find(')', -1) -1] #json字符串print jsonstr
output = json.loads(jsonstr) #json字符串转字典
print output['data']['albumListModeClass'][0]['albumList'][0]['name']
print output['data']['albumListModeClass'][0]['albumList'][1]['name']
print output['data']['albumListModeClass'][0]['albumList'][2]['name']
print output['data']['albumListModeClass'][0]['albumList'][3]['name']
print output['data']['albumListModeClass'][0]['totalInClass']
print output['data']['albumListModeClass'][1]['albumList'][0]['name']
print output['data']['albumListModeClass'][1]['albumList'][1]['name']
print output['data']['albumListModeClass'][1]['albumList'][2]['name']
print output['data']['albumListModeClass'][1]['albumList'][3]['name']
print output['data']['albumListModeClass'][1]['totalInClass']
print output['data']['albumListModeClass'][2]['albumList'][0]['name']
print output['data']['albumListModeClass'][2]['totalInClass']
print output['data']['albumsInUser']
print 'type'
print output['data']['mode']albumListModeClass = output['data']['albumListModeClass']
print '------------'
for albumClass in albumListModeClass: albumList=albumClass['albumList']for album in albumList:print u'当前相册:' + str(album['classid']) + album['name']print '------------'#下面是photo#判断是否允许访问1为允许0为不允许album = output['data']['albumListModeClass'][1]['albumList'][1]
#
print album['allowAccess']
#id与topicId对应
#
print album['id']
#相册名
#
print album['name']
hostUin=origin_photo.split('&hostUin=')[1].split('&')[0]
topicId=origin_photo.split('&topicId=')[1].split('&')[0]curl = origin_photo.replace(hostUin, target) #替换链接里的被访问者账号curl = curl.replace(topicId, album['id']) #替换链接里的相册IDcurl = curl.replace('&pageNum=30', '&pageNum=600') # QQ空间每个相册最大貌似不会超过512args = shlex.split(curl)result = subprocess.check_output(args).decode('utf-8')
print result
jsonstr=result[result.find('(') + 1 : result.find(')', -1) -1] #json字符串
print jsonstroutput = json.loads(jsonstr) #json字符串转字典
photo = output['data']['photoList'][4]
#print photo
#print output['data']['totalInAlbum'] #相册里相片总张数print output['data']['photoList'][4]['url']
解决了部分相册需要cookies的问题,json里面也没找到对应字段,所以把cookies全加上了,
cookies测试代码
#-*- coding: UTF-8 -*-
import Cookie
import urllib2
import os
import shlex
import cookielib
import json
# 添加curl的环境变量
os.putenv('PATH', 'D:\\curl-7.33.0-win64-nossl\\;'+os.getenv('PATH'))
# 获取原始curl请求
origin_album = fcg_list_album_v3
origin_photo = cgi_list_photocookiestr=origin_photo[origin_photo.find('"Cookie:') : origin_photo.find('"', -1) ]
cookie_str = cookiestr[cookiestr.find(':') + 2 : cookiestr.find('"', 2) ]
print cookie_str
cookie_domain='.photo.store.qq.com'
cookie_path='/'simple_cookie = Cookie.SimpleCookie(cookie_str) # Parse Cookie from str
cookiejar = cookielib.CookieJar() # No cookies stored yet
for c in simple_cookie:cookie_item = cookielib.Cookie(version=0, name=c, value=str(simple_cookie[c].value),port=None, port_specified=None,domain=cookie_domain, domain_specified=None, domain_initial_dot=None,path=cookie_path, path_specified=None,secure=None,expires=None,discard=None,comment=None,comment_url=None,rest=None,rfc2109=False,)cookiejar.set_cookie(cookie_item) # Apply each cookie_item to cookiejar
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar)) # Return openerurl=realurl #图片实际地址savepath='D:\\test.jpg'
f = opener.open(url)
with open(savepath, "wb") as code: code.write(f.read())
后记:
20150718:修正第二类型相册分类数始终为3的错误
20150829:不用再手工删除 --compressed指令
使用Python2.7和火狐浏览器下载QQ空间好友相册相关推荐
- 使用Python2.7和火狐浏览器下载QQ空间好友相册(二)
原来的文章由于用到了curl的命令,比较麻烦,而且带上cookie之后还是有一部分无法下载,所以用httplib2代替了curl.urllib.urllib2的一些功能.重新写了一个代码 前面文章的代 ...
- 火狐浏览器 模拟人工重复操作_火狐浏览器下载手机版-火狐浏览器下载安装到手机v68.6.0...
[火狐浏览器下载手机版]是一款非常热门的手机浏览器,西门手游网为用户提供火狐浏览器下载安装到手机,火狐浏览器下载手机版中有非常丰富的浏览器功能,让用户可以在浏览器中体验到多种多样的服务,带给用户可以轻 ...
- 火狐linux 32位,火狐浏览器下载电脑版32位
火狐浏览器下载电脑版32位有着所有用户们对于浏览器的需求功能.海量丰富的功能拓展可以让用户们自由使用,喜欢网络冲浪的你还不快来打造你的专属浏览器. 火狐浏览器下载电脑版32位介绍: 1.节省时间,所有 ...
- 火狐浏览器下载最后一秒卡住怎么办?
在火狐浏览器中大家在使用他浏览器自带的下载器下载文件的话可能会遇到在最后一秒卡住不动的情况,这是因为我们没有对其中的一些选项进行设置导致的,只要去设置一下就可解决这个问题. 火狐浏览器下载卡住解决方法 ...
- 火狐浏览器下载文件名乱码
##火狐浏览器下载文件名乱码 response.setHeader("Content-Disposition","attachment;filename*=utf-8'z ...
- selenium,设置火狐浏览器下载文件时不要弹出弹框问题、以标签页打开新的页面及设置失效问题
使用火狐浏览器做自动化时, 1.火狐浏览器下载文件会弹出弹框,可以通过设置火狐浏览器不要弹出弹框的方式,来完成自动化测试 def setup_method(self):# 创建一个存放自定义浏览器配置 ...
- [问题小计]火狐浏览器下载任何东西都是提示失败
这两天用火狐浏览器下载任何东西都失败,如下: 网上找了一圈,才发现原来是下载路径设置有误,原本的路径下应该是没有保存文件的权限. 重新修改后,恢复正常,实操过程记录如下. 浏览器打开后右上角点击, ...
- 关闭firefox火狐浏览器下载完成时自动扫描(49.0.2以后版本)
用firefox火狐浏览器下载文件到最后时,会显示"剩余时间未知",将持续10秒钟左右,即使几KB 的文件,也要持续这么长时间,问度娘才知道是自动扫描,检查是否有毒,用的却是Goo ...
- python自动下载qq文件夹_GitHub - 1061700625/QQZone_AutoDownload_Album: Python+selenium 自动下载QQ空间相册...
QQZone_AutoDownload_Album Python+selenium 自动下载QQ空间相册 . selenium_firefox.zip 需要解压后放在同路径下 . 貌似腾讯的登陆加密做 ...
- Python自动下载QQ空间相册
github:https://github.com/1061700625/QQZone_AutoDownload_Album 貌似腾讯的登陆加密做的很复杂.所以用selenium模拟登陆的,这样就可以 ...
最新文章
- 如何将C#对象转换为.NET中的JSON字符串?
- android 带清除功能的输入框控件
- PHP 实现快速排序
- glass fish_Glass Fish 4.0.1中的Jersey SSE功能
- 程序员分析报告(2018)-总结篇
- 微信开发(4) -- 推送微信模板信息到服务号
- 煤岩分析仪测定煤的镜质体反射率和煤显微组分
- 不知道这些,你的世界杯就白看了!
- html 显示编辑xml文件,如何将 XML 文件显示为 HTML 表格展示
- USBCNC输出板与VFD和主轴的使用
- 离线地图下载及地图瓦片制作
- Python复习笔记———超详细
- RK987蓝牙键盘使用说明书分享
- 太湖之光超级计算机应用最高奖,世界最快超级计算机“神威·太湖之光”获得100多项应用成果...
- 【SNA】社会网络分析二 Gephi 功能详解
- 千梦网创108计第三十六计:当地人才招聘网,一个年入50W的战友实操案例
- hackinglab.cn 注入关之一
- Java面向对象-01-类和对象
- Visual Studio运行C语言程序(第一个程序)
- EF Core 5.0原生sql语句执行
热门文章
- 数学建模-灰色系统理论与灰色关联分析
- c语言 双重取反的高级用途(提升代码效率)
- 基于ansys命令流的水池静力学分析
- 迭代重心法 matlab,重心法
- 软件安全测试培训大纲
- Mac上qmc0文件转码为mp3
- java并行计算π_3月14日圆周率日—使用并行计算求圆周率π
- delphi连接mysql不用添加dsn_Delphi]delphi中动态创建MySQL的ODBC连接 .
- android 7修改机型,Android 7.0支持机型大全
- opencv cv::Mat::convertTo()函数