豪翔天下

Change My World by Program

0%

作者:Jon Bentley

本书的作者通过一个一个实际生活中的例子来给引导我们对编程进行思考,虽然在实际工作中我们多半是只使用思考的结果,但本书更重要的是让我们了解到发现问题本源,并真正解决问题的一个思考过程。本书主要提出了一些抽象概念,目的不是像《算法导论》那样先提出抽象问题,然后进行实际的讲解与编码,而是一步一步带领我们如何更好地解决问题。

其实本书后半部分包括续集,其质量都不高(我是这么认为的),都是讲一些没多大用的东西。其实我从中学到最多的就是位图的使用以及实际开发过程中需要注意的一些问题。

没想到,小小的位图对于海量数据的处理还有这么大的功效。当然了,书中所说的所有问题以及思考我都没有去真正编码过,但我觉得自己能写好80%的代码(感觉和事实肯定不一样的。)

语录

1.对小问题的仔细分析有时可以得到明显的实际益处。

2.明确了问题,那这场战役就成功了90%

3.设计者确定其设计已经达到了完美的标准不是不能再增加任何东西,而是不能再减少任何东西。——Antoine de Saint-Exupery

4.程序员在节省空间方面无计可施时,将自己从代码中解脱出来,退回起点并集中心力研究数据,常常能有奇效,(数据的)表示形式是程序设计的根本。——Fred Brooks

5.计算机系统中最廉价、最快速且最可靠的元件是根本不存在的。——Gordon Bell

6.当程序性能问题无法回避时,考虑设计层面会有助于程序员集中精力解决问题。如果仅需要较小的加速,就对效果最佳的层面做改进,因为“性价比”最高的那一个投入最小的精力就可以获得最大加速系数的那个设计层面。如果需要较大的加速,就对多个层面做改进。

7.任何事都应尽量简单,但不宜过于简单。——爱因斯坦

8.代码调优的最重要的原理就是尽量少用它

9.解决现有的问题是程序员任务的一部分,另一个也许更重要的部分是做好解决未来问题的准备。本章示例了编程过程中的几个重要步骤:正确理解所遇到的问题;提炼出抽象问题;考虑尽可能多的解。

10.如果还没想清楚,就用蛮力算法吧。——Ken Thompson

11.代码写得越急,程序跑得越慢。——Roy Carlson

12.如果你发现特殊情况太多,那你肯定是用错方法了。——Craig Zerouni

13.在我所有的程序错误中,80%是语法错误。剩下的20%里,80%是简单的逻辑错误。在剩下的4%里,80%是指针错误。只有余下的0.8%才是困难的问题。——Marc Donner

14.在系统测试阶段找出并修正错误,要比开发者自己完成这一工作多付出2倍的努力。而当系统已经交付使用之后找出并修正一个错误,要比系统测试阶段多付出9倍的努力。因此,请坚持让开发者进行单元测试吧。——Larry Bernstein

15.新系统的每一个新用户都可能发现一类新的错误。——Brian Kernighhan

16.对于那些快速算法,我们总是可以拿到一些速度差不多但是更容易理解的算法来替代它们。——Dougls W. Jones

17.在一个非I/O密集型的程序中,超过一半的运行时间是花在不足4%的代码上的。——Don Knuth

18.在优化一个程序之前,请先用性能监视工具找到程序的“热点”。——Mike Moron

19.【代码规模守恒定律】当你为了加速,把一页代码变成几条简单的指令时,请不要忘了增加注释,以使源码的行数保持为一个常量。——Mike Morton

20.纸上的工作没结束,整个工作也就还没结束。

21.【90-90法则】前90%的代码占用了90%的预定开发时间,余下的10%代码又花费了90%的预定开发时间。——Tom Cargill

22.正确的判断来源于经验,然而经验来源于错误的判断。——Fred Brooks

23.如果有人基本上做出了你想要做的东西,你就没必要自己写一个新程序。就算你非写不可,也请尽可能多地利用现有的代码。——Richard Hill

24.先让程序跑起来,再考虑怎么让程序跑得快。——Bruce Whiteside

虽然用U盘装过很多次系统了,但昨天突然感觉制作完win7启动盘后,那个图标也太丑了吧。所以毅然决定改了一下,通过这种改动,无论是在什么电脑上都能显示出来的。

1.制作图标

U盘的图标其实png, jpg, ico什么类型的都支持的,但是为了美观,最好选择png或ico,我就用的ico,因为这两者会把透明部分真正透明化。至于怎么
制作ico,可以使用Photoshop修改好了过后保存为png图片,然后在线将png转换为ico格式:[图标在线转换工具](http://www.img2i
co.net/)

2.在U盘根目录新建文件autorun.inf

内容如下:

[AutoRun.Amd64]
icon=haofly.ico




[AutoRun]
icon=haofly.ico

3.将图片haofly.ico拷贝到U盘根目录

4.结果如下



在我的印象里,虚拟机在安装增强功能后是可以直接互相拖放文件的,但不知道为什么最近几个月我安装的都不行啊,所以这里记录一下通过映射来共享文件的方法。

虚拟Linux Server

  1. 和win一样,点击虚拟机的_设备->安装增强功能_

  2. 不同的是linux_server 上面不会自动弹出安装界面,而是需要挂载在安装,执行如下命令:

    $ sudo mount /dev/cdrom /media/cdrom
    block device /dev/sr0 is write-protected, mounting read-only
    $ cd /media/cdrom
    $ sudo ./VBoxLinuxAdditions.run

  3. 在设置里面添加共享文件夹:
    ![](http://7xnc86.com1.z0.glb.clouddn.com/virtualbox-guest-host-share-
    file_0.jpg)

  4. 记住上面的共享的名称,比如company,那么在linux_server里面就可以看到_/media/sf_company_这一个目录。

  5. 如果在linux_server往那个目录添加东西时出现_Read-only_错误,可能是VirtualBox默认禁止在共享目录里建立链接(stackoverflow解答),此时应该执行如下命令,其中,VM_NAME表示你的虚拟机的名称,SHARE_NAME表示共享的名称(不加前缀sf_) 如果是windows主机,在cmd里执行:

    VBoxManage.exe setextradata VM_NAME VBoxInternal2/SharedFoldersEnableSymlinksCreate/SHARE_NAME 1

如果是linux主机,在shell里执行:

    VBoxManage setextradata VM_NAME VBoxInternal2/SharedFoldersEnableSymlinksCreate/SHARE_NAME 1

虚拟Windows

1.还是要安装增强功能

![](http://7xnc86.com1.z0.glb.clouddn.com/virtualbox-guest-host-share-
file_1.png)

安装完成后关机,之所以不重启,是因为还有要设置的地方。

2.设置共享文件夹

![](http://7xnc86.com1.z0.glb.clouddn.com/virtualbox-guest-host-share-
file_2.png)
我一般喜欢把共享文件夹设置为固定分配、自动挂载、完全访问权限。

3.添加映射

[![](http://7xnc86.com1.z0.glb.clouddn.com/virtualbox-guest-host-share-
file_3.png)
](http://haofly.net/wp-content/uploads/2014/10/virtualbox-share-
file-4.png)![](http://7xnc86.com1.z0.glb.clouddn.com/virtualbox-guest-host-
share-file_4.png)
![](http://7xnc86.com1.z0.glb.clouddn.com/virtualbox-guest-host-share-
file_5.png)
点击浏览,找到文件夹,确定

![](http://7xnc86.com1.z0.glb.clouddn.com/virtualbox-guest-host-share-
file_6.png)
![](http://7xnc86.com1.z0.glb.clouddn.com/virtualbox-guest-host-share-
file_7.png)
成功!

最近做一个项目,需要从一个Python文件里执行其他的Python文件,因为数量可能有点大,所以考虑了一下性能的问题,就去简单地测试了一下其效率,结果如下:

首先,我的另一个Python文件test1.py里内容如下,执行一条command命令

import os
os.putenv('PATH', 'C:\\Program Files (x86)\\Git\\bin')    # 我的ls命令在git下面
os.system('ls -ls')

1.使用exec函数

在Python3中无法直接使用execfile()函数,execfile被分解为了open()和exec(),[详见文档](https://docs.pyt
hon.org/3/library/functions.html#exec),必须先将文件打开,再把文件浏览当作参数传入exec函数中去。代码如下:

import os




for time in range(0, 1000):
        fp = open('test1.py')
        exec(fp.read(), None, None)
        #os.popen('ls -l')

执行一千次该文件,结果如下:内存几乎无变化,CPU使用率62%左右,耗时86.3s
![](http://7xnc86.com1.z0.glb.clouddn.com/python-execute-pythonfile-
effiency.png)

2.使用os.popen()函数

os模块的popen()函数是相当于执行的是一条command命令,并可以通过read()方法获取命令的输出,代码如下:

import os




for time in range(0, 1000):
        fp = open('test1.py')
        #exec(fp.read(), None, None)
        os.popen('ls -l')

执行一千次该循环,结果如下:内存几乎无变化,CPU使用率90%左右,耗时118.1s

![](http://7xnc86.com1.z0.glb.clouddn.com/python-execute-pythonfile-

effiency_1.png)

3.结果

从上面很明显的就能发现,使用Python3里面的exec不仅占用CPU率较低,并且执行时间也较快,而在占用内存方面两者几乎都一样。所以,还是使用exec吧。

4.扩展

顺便测试了一下使用os.system()函数和os.popen()函数的区别,当然这里的测试是在单个文件里执行一千次该命令,如下:

import os




os.putenv('PATH', 'C:\\Program Files (x86)\\Git\\bin')    # 我的ls命令在git下面




for time in range(0, 1000):
        os.system('ls -l')
    # os.popen('ls -l')

os.system()的结果:CPU占用65%左右,内存几乎不变,耗时83.5s
![](http://7xnc86.com1.z0.glb.clouddn.com/python-execute-pythonfile-
effiency_2.png)
os.popen()的结果:CPU占用90%左右,内存几乎不变,耗时38.4s

![](http://7xnc86.com1.z0.glb.clouddn.com/python-execute-pythonfile-
effiency_3.png)

在网上找了几天时间,发现网上的方法都有一定的局限性,因为我想要的是在同一台服务器上实现一个nginx做反向代理到多个apache(再一次感叹网上好多教程的落后和千篇一律)。这里再次记录本次的配置过程。

环境:Ubuntu14.04 server + nginx(1.4.6) + apache2(2.4.7)

目的:使用nginx做代理,分别代理到apache的四个监听端口8080/8081/8082/8083 优点:Nginx可应付高并发,使用Proxy做代理效率也较高,占用资源少,再使用apache处理后端,也更稳定,现在一般的做法是是用nginx处理前端,apache处理后端,我这里暂时全部交由apache处理。当然,我这里都是在同一台服务器上做的,除了减少单个apache的并发处理数量,对性能来说并没有显著的提升。

1.安装nginx和apache2

安装到没什么好说的,直接apt-get安装即可。

2.修改nginx的配置文件/etc/nginx/nginx.etc

在http字段(就是那个大括号里面)添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
upstream balance{
server localhost:8080;
server localhost:8081;
server localhost:8082;
server localhost:8083;
}

server{
listen 80;
server_name haofly.net;
localhost /{
proxy_pass http://balance;
}
}

其中nginx是让upstream里面的各个IP/端口实现轮询访问,研究一下nginx的配置文件,还可以对轮询访问加上一些限制条件,比如轮训机制、权值分配等,这里不做详述。

需要注意的是如果是二级域名,那么upstream里面的server依然写成localhost:port的形式,而不用去写什么二级域名,二级域名在apache的配置文件里面定义,nginx会直接将那些都传给它的。

3.修改apache的配置文件

主配置文件/etc/apache2/apache2.conf,在#ServerRoot "/etc/apache"下添加一行指明ServerName,例如:

#ServerRoot "/etc/apache2"
ServerName haofly.net

虚拟目录配置文件(这就相当于为apache多开了几个线程,就好像是有多个apache在同时工作一样) vim /etc/apache2/sites-available/000-default.conf(这是默认的那个80端口的配置文件),只需要把里面的80端口改为8080即可。然后再新建几个配置文件vim /etc/apache2/sites-available/proxy01.conf内容如下:

1
2
3
4
5
6
<VirtualHost *:8081>
ServerAdmin localhost:8081
DocumentRoot /var/www/html
ErrorLog $\{APACHE_LOG_DIR\}/error.log
CustomLog $\{APACHE_LOG_DIR\}/access.log combined
</VIrtualHost

8082端口的配置文件proxy02.conf只需要把端口改为8082即可,另外为方便测试,我们需要把8083端口的配置文件特殊化一下,vim /etc/apache2/sites-available/proxy03.conf,内容如下:

1
2
3
4
5
6
<VirtualHost *:8083>
ServerAdmin localhost:8083
DocumentRoot /var/www/test
ErrorLog $\{APACHE_LOG_DIR\}/error.log
CustomLog $\{APACHE_LOG_DIR\}/access.log combined
</VirtualHost>

其实只是修改了DocumentRoot,使它指向/var/www/test,这样就方便测试了,/var/www/test下新建一个文件vim/var/www/test/index.html,内容如下

<html>
 hehe
</html>

在把配置文件链接到/etc/apache2/sites-available文件夹:

cd ../sites-enabled
sudo ln -s ../sites-available/proxy01.conf
sudo ln -s ../sites-available/proxy02.conf
sudo ln -s ../sites-available/proxy03.conf

最后再修改apache的端口文件vim /etc/apache2/ports.conf,把Listen *80修改为:

Listen 8080
Listen 8081
Listen 8082
Listen 8083

4.测试

首先检查配置文件是否有语法错误

nginx -t
apachectl -t

如果都OK,就可以重启了:

service apache2 restart
service nginx stop
service nginx start

然后在浏览器输入上面的Servername,即http://haofly.net,多刷新几次,就会发现,有时候出现的是apache的界面,有时候出现的是test下那个hehe界面。

5.nginx添加二级域名

比apache简单多了,我这里不仅添加了二级域名,并且也实现了一个反向代理,/etc/nginx/nginx.conf里面的http里面添加一个upstream和一个server即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
upstream {
server localhost:8084;
}
server {
server_name aa.hostname.com;
listen 80;
location / {
proxy_pass http://er;
proxy_redirect default;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
}
}

然后就像Apache简单配置以及设置二级域名 那样设置apache即可。

参考文章:

http://blog.csdn.net/yanggd1987/article/details/31375573
http://www.oschina.net/question/56436_109188

参考文档:https://docs.python.org/3/library/configparser.html#module-configparser

今天在研究MySQL Connector for Python的时候无意间发现原来Python自带了设置与读取配置信息的模块的,有了这么一个功能就能够在一个单独的文件里面写上一些敏感信息,比如你的数据库的用户名密码等,以后要使用的时候直接读取该文件即可。这里简要描述一下其使用方法。

首先,得要有一个文件用来保存配置信息,格式如下setting.conf:

[DATABASE]
Port = 21
Username = haofly
Password = 123456
Database = test

[DEFAULT]
User = hg

需要注意的是,在配置文件里字符串是不加引号的,因为无论是字符串还是数字,读取出来都是字符串的形式。

在另一个文件中使用方法如下:

1
2
3
4
5
6
import configparser

config = configparser.ConfigParser()
config.sections()
config.read('co.config')
print(config['DATABASE']['Username'])

打印出来haofly

上一次用cURL获取了QQ的好友列表,跳过了验证过程,感觉特别爽,所以趁热打铁,直接又写了个获取所有QQ好友相册的代码。

环境:Python3 + Chrome + Windows7

首先得要获取到所有QQ好友的QQ号码,直接参考《使用Python3和Chrome获取QQ好友列表》,当然,如果你想要指定的号码,那么直接在**qqlist.txt**里写上其QQ号
码即可(不过获取之后是不用处理末尾的’\n’的,因为我当时写入的时候加入了)。

然后,和那篇文章一样,获取cURL。

首先在任意一个_user.qzone.qq.com/QQ号码/4_页面刷新,在审查里面的Network获取_fcg_list_album_的cURL
,然后,再随便点进一个相册获取_cgi_list_photo_的cURL,其中一个是获取相册列表的,一个是获取某相册下照片列表的。

然后将两个字符串分别替换代码16/17行的get_album和get_photo

#-_- coding: UTF-8 -_-
import os, sys
import re
import subprocess
import shlex
import urllib.request
import json
import codecs
import datetime




# 我最先是把get_album和get_photo的值存储在request_curl.py文件里面的




# from request_curl import *




# 添加curl的环境变量




os.putenv('PATH', 'C:\\Program Files (x86)\\Git\\bin')




# 获取原始curl请求




origin_album = get_album
origin_photo = get_photo




# 获取目标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:
        log = \{\}                    # 下载日志
        log['qq'] = target          # QQ号
        log['access'] = 1           # 是否允许访问
        log['time'] = datetime.datetime.now()   # 下载完成后记录花费的时间
        log['album_count'] = 0      # 相册总数
        log['photo_count'] = 0      # 照片总数





    print('当前QQ:' + target)
    try:
        os.makedirs('photos/' + target)                                             # 建立相应的文件夹
    except:
        os.removedirs('photos/' + target)
        os.makedirs('photos/' + target)
    # 先得到正确的curl,然后执行获取json数据
    curl = origin_album.replace('&amp;hostUin=1129029735', '&amp;hostUin=' + target)    # 被访问者
    curl = curl.replace('&amp;pageNumModeSort=40', '&amp;pageNumModeSort=100')          # 显示相册数量
    args = shlex.split(curl)
    result = subprocess.check_output(args).decode('utf-8')
    convert = result[result.find('(') + 1 : result.find(')', -1) -1]            # 去除不标准的json数据
    output = json.loads(convert)                                                # 最终json数据
    if(output['code'] == -4009):
        log['access'] = 0           # 是否允许访问
        fp = open('photos/' + target + '/log.txt', 'w', encoding='utf-8')       # 日志文件,记录时间与数量
        fp.writelines(str(log))
        fp.close()
        continue

    # output['data']['albumListModeSort']就是相册列表
    # 艹,也有可能output['data']['albumListModeClass'][0]['albumList']是相册列表
    # 最后才发现,output['data']['albumListModeClass']也有可能是相册列表
    try:
        if(output['data']['albumListModeSort'] == None):
            albumList = None
        else:
            albumList = output['data']['albumListModeSort']
    except:
        if(output['data']['albumListModeClass'] == None):
            albumList = None
        else:
            albumList = output['data']['albumListModeClass'][0]['albumList']

    # 我服都服了,这么大个人了,居然还有没有相册的
    if(albumList == None):
        continue

    theSameAlbumName = 0    # 防止同名相册的出现
    print(albumList)
    for album in albumList:
        log['album_count'] += 1
        print('当前相册:' + album['name'])
        if(album['allowAccess'] == 0):                  # 相册无法直接访问(需要密码或者禁止访问)
            continue

        # album['id']就是照片列表的ID
        # 获取照片列表数据
        curl = origin_photo.replace('&amp;hostUin=1129029735', '&amp;hostUin=' + target)
        curl = curl.replace('&amp;topicId=V10HYl1S33NLS5', '&amp;topicId=' + album['id'])
        curl = curl.replace('&amp;pageNum=30', '&amp;pageNum=600')  # QQ空间每个相册最大貌似不会超过512
        args = shlex.split(curl)
        result = subprocess.check_output(args).decode('utf-8')
        convert = result[result.find('(') + 1 : result.find(')', -1) -1]
        output = json.loads(convert)

        if(output['code'] == -4404):
            continue

        # 相册名里面会不会也有奇葩名字呢
        filt = re.compile(r'\\\\|/|:|\\*|\\?|&lt;|&gt;|\\||\\.')
        album['name'] = re.sub(filt, '', album['name'])
        # 我服都服了,QQ空间居然还允许同名的相册。。。
        albumname = album['name'].replace(' ', '')
        filelist = os.listdir('photos/' + target + '/')
        if (albumname in filelist) or (len(albumname) == 0):
            albumname = albumname + '_' + str(theSameAlbumName)
            theSameAlbumName += 1

        os.makedirs('photos/' + target + '/' + albumname)
        same = 0    # 防止同名

        # 获取该相册下的每一张照片,如果相册为空,那么output['data']['photoList'] = None,艹
        photoList = output['data']['photoList']
        if(photoList == None):
            continue

        for photo in photoList:
            log['photo_count'] += 1
            print('当前照片' + photo['name'])

            # 图片格式由photo['phototype']字段(整型)控制
            # 1:jpg
            # 3:png
            phototype = \{'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(' ','')

            if (photoname in filelist) or (len(photoname) == 0):
                photoname = photoname + '_' + str(same)
                same += 1
            # 文件名中不能有特殊字符
            filt = re.compile(r'\\\\|/|:|\\*|\\?|&lt;|&gt;|\\||\\.|\\n|\\t|\\"')
            photoname = re.sub(filt, '', photoname)

            path = 'photos\\\\' + target + '\\\\' + albumname + '\\\\' + photoname + format
            try:
                urllib.request.urlretrieve(photo['url'], path)
            except urllib.error.ContentTooShortError as e:
                print('啥子错误哟')

    fp = open('photos/' + target + '/log.txt', 'w', encoding='utf-8')       # 日志文件,记录时间与数量
    log['time'] = (datetime.datetime.now() - log['time']).seconds
    log['time'] = str(log['time']) + 's'
    fp.writelines(str(log))
    fp.close()
    print('当前QQ:' + target + '下载完毕')</pre>

以下是我获取到的结果,可以说,百分之九十九都成功获取到了,但是有几个好友反映貌似他们的没有获取完,我去看了下,又是获取的json数据结构的问题,我真的服了,
腾讯同一个功能搞那么多数据结构来干嘛,操蛋。

另外写了一个统计耗时的脚本,因为我在每个相册的日志里都记录了下载时间的,所以直接就统计了

# 统计log.txt里面所有的数据




# 根目录是photos




import os
import json
alltime = 0
for i in os.walk('photos'):
    if(len(i[2]) == 1 and i[2][0] == 'log.txt'):
        fp = open(i[0] + '/' + 'log.txt', 'r')
        data = fp.read()
        data = data.replace('\\'', '"')
        if(data.find('datetime') < 0):
            #print(data)
            output = json.loads(data)
            time = output['time'][:-1]
            alltime += int(time)
            fp.close()
print(str(alltime/60/60) + 'h')

结果是13.797500000000001h,和我预计的差不多,虽然是4M的网速,但是建立连接建立过多,而且没有用到多线程,这个时间还是合情合理的。

PS:正在把这些照片上传到云盘,哈哈,要是泄漏了可不要说我是故意的 还有就是请勿模仿,我虽然总共下载了400个好友,但是停下来了十多次,都是数据结构出现问题
,请千万不要为此折腾,我纯属是为了完成自己以前的愿望罢了,下载下来也没用。

上一次用cURL获取了QQ的好友列表,跳过了验证过程,感觉特别爽,所以趁热打铁,直接又写了个获取所有QQ好友相册的代码。

环境:Python3 + Chrome + Windows7

首先得要获取到所有QQ好友的QQ号码,直接参考《使用Python3和Chrome获取QQ好友列表》,当然,如果你想要指定的号码,那么直接在**qqlist.txt**里写上其QQ号
码即可(不过获取之后是不用处理末尾的’\n’的,因为我当时写入的时候加入了)。

然后,和那篇文章一样,获取cURL。

首先在任意一个_user.qzone.qq.com/QQ号码/4_页面刷新,在审查里面的Network获取_fcg_list_album_的cURL
,然后,再随便点进一个相册获取_cgi_list_photo_的cURL,其中一个是获取相册列表的,一个是获取某相册下照片列表的。

然后将两个字符串分别替换代码16/17行的get_album和get_photo

#-_- coding: UTF-8 -_-
import os, sys
import re
import subprocess
import shlex
import urllib.request
import json
import codecs
import datetime




# 我最先是把get_album和get_photo的值存储在request_curl.py文件里面的




# from request_curl import *




# 添加curl的环境变量




os.putenv('PATH', 'C:\\Program Files (x86)\\Git\\bin')




# 获取原始curl请求




origin_album = get_album
origin_photo = get_photo




# 获取目标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:
        log = \{\}                    # 下载日志
        log['qq'] = target          # QQ号
        log['access'] = 1           # 是否允许访问
        log['time'] = datetime.datetime.now()   # 下载完成后记录花费的时间
        log['album_count'] = 0      # 相册总数
        log['photo_count'] = 0      # 照片总数





    print('当前QQ:' + target)
    try:
        os.makedirs('photos/' + target)                                             # 建立相应的文件夹
    except:
        os.removedirs('photos/' + target)
        os.makedirs('photos/' + target)
    # 先得到正确的curl,然后执行获取json数据
    curl = origin_album.replace('&amp;hostUin=1129029735', '&amp;hostUin=' + target)    # 被访问者
    curl = curl.replace('&amp;pageNumModeSort=40', '&amp;pageNumModeSort=100')          # 显示相册数量
    args = shlex.split(curl)
    result = subprocess.check_output(args).decode('utf-8')
    convert = result[result.find('(') + 1 : result.find(')', -1) -1]            # 去除不标准的json数据
    output = json.loads(convert)                                                # 最终json数据
    if(output['code'] == -4009):
        log['access'] = 0           # 是否允许访问
        fp = open('photos/' + target + '/log.txt', 'w', encoding='utf-8')       # 日志文件,记录时间与数量
        fp.writelines(str(log))
        fp.close()
        continue

    # output['data']['albumListModeSort']就是相册列表
    # 艹,也有可能output['data']['albumListModeClass'][0]['albumList']是相册列表
    # 最后才发现,output['data']['albumListModeClass']也有可能是相册列表
    try:
        if(output['data']['albumListModeSort'] == None):
            albumList = None
        else:
            albumList = output['data']['albumListModeSort']
    except:
        if(output['data']['albumListModeClass'] == None):
            albumList = None
        else:
            albumList = output['data']['albumListModeClass'][0]['albumList']

    # 我服都服了,这么大个人了,居然还有没有相册的
    if(albumList == None):
        continue

    theSameAlbumName = 0    # 防止同名相册的出现
    print(albumList)
    for album in albumList:
        log['album_count'] += 1
        print('当前相册:' + album['name'])
        if(album['allowAccess'] == 0):                  # 相册无法直接访问(需要密码或者禁止访问)
            continue

        # album['id']就是照片列表的ID
        # 获取照片列表数据
        curl = origin_photo.replace('&amp;hostUin=1129029735', '&amp;hostUin=' + target)
        curl = curl.replace('&amp;topicId=V10HYl1S33NLS5', '&amp;topicId=' + album['id'])
        curl = curl.replace('&amp;pageNum=30', '&amp;pageNum=600')  # QQ空间每个相册最大貌似不会超过512
        args = shlex.split(curl)
        result = subprocess.check_output(args).decode('utf-8')
        convert = result[result.find('(') + 1 : result.find(')', -1) -1]
        output = json.loads(convert)

        if(output['code'] == -4404):
            continue

        # 相册名里面会不会也有奇葩名字呢
        filt = re.compile(r'\\\\|/|:|\\*|\\?|&lt;|&gt;|\\||\\.')
        album['name'] = re.sub(filt, '', album['name'])
        # 我服都服了,QQ空间居然还允许同名的相册。。。
        albumname = album['name'].replace(' ', '')
        filelist = os.listdir('photos/' + target + '/')
        if (albumname in filelist) or (len(albumname) == 0):
            albumname = albumname + '_' + str(theSameAlbumName)
            theSameAlbumName += 1

        os.makedirs('photos/' + target + '/' + albumname)
        same = 0    # 防止同名

        # 获取该相册下的每一张照片,如果相册为空,那么output['data']['photoList'] = None,艹
        photoList = output['data']['photoList']
        if(photoList == None):
            continue

        for photo in photoList:
            log['photo_count'] += 1
            print('当前照片' + photo['name'])

            # 图片格式由photo['phototype']字段(整型)控制
            # 1:jpg
            # 3:png
            phototype = \{'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(' ','')

            if (photoname in filelist) or (len(photoname) == 0):
                photoname = photoname + '_' + str(same)
                same += 1
            # 文件名中不能有特殊字符
            filt = re.compile(r'\\\\|/|:|\\*|\\?|&lt;|&gt;|\\||\\.|\\n|\\t|\\"')
            photoname = re.sub(filt, '', photoname)

            path = 'photos\\\\' + target + '\\\\' + albumname + '\\\\' + photoname + format
            try:
                urllib.request.urlretrieve(photo['url'], path)
            except urllib.error.ContentTooShortError as e:
                print('啥子错误哟')

    fp = open('photos/' + target + '/log.txt', 'w', encoding='utf-8')       # 日志文件,记录时间与数量
    log['time'] = (datetime.datetime.now() - log['time']).seconds
    log['time'] = str(log['time']) + 's'
    fp.writelines(str(log))
    fp.close()
    print('当前QQ:' + target + '下载完毕')</pre>

以下是我获取到的结果,可以说,百分之九十九都成功获取到了,但是有几个好友反映貌似他们的没有获取完,我去看了下,又是获取的json数据结构的问题,我真的服了,
腾讯同一个功能搞那么多数据结构来干嘛,操蛋。

另外写了一个统计耗时的脚本,因为我在每个相册的日志里都记录了下载时间的,所以直接就统计了

# 统计log.txt里面所有的数据




# 根目录是photos




import os
import json
alltime = 0
for i in os.walk('photos'):
    if(len(i[2]) == 1 and i[2][0] == 'log.txt'):
        fp = open(i[0] + '/' + 'log.txt', 'r')
        data = fp.read()
        data = data.replace('\\'', '"')
        if(data.find('datetime') < 0):
            #print(data)
            output = json.loads(data)
            time = output['time'][:-1]
            alltime += int(time)
            fp.close()
print(str(alltime/60/60) + 'h')

结果是13.797500000000001h,和我预计的差不多,虽然是4M的网速,但是建立连接建立过多,而且没有用到多线程,这个时间还是合情合理的。

PS:正在把这些照片上传到云盘,哈哈,要是泄漏了可不要说我是故意的 还有就是请勿模仿,我虽然总共下载了400个好友,但是停下来了十多次,都是数据结构出现问题
,请千万不要为此折腾,我纯属是为了完成自己以前的愿望罢了,下载下来也没用。

不知道是因为以前看过太多成功学书籍还是译者没有翻译好,还是我买的版本不对,反正我总感觉这本书,不大好。文笔有点枯燥,和很多成功学书籍差不多。当时买这本书的时候还是京东上打折,谁知道买来纸质非常差,而且比32开还小,每本也只有300页左右,一股盗版的感觉,我一直以为京东上是不会买到盗版书的哟。

《人性的弱点》《人性的优点》《语言的突破》,分别出版于1937年、1948年、1926年,我相信,在上个世纪,这本书肯定是给很多人带来了很多的启发,无论是为人处事还是商业活动都对一个人有很大的影响,但是现在已经21世纪,书中的观点和很多方法都没有过时,只是这样的书在现在已经泛滥成灾了。任何一个书店的“成功学”分类中都能一抓一大把,或许其始祖就是卡耐基的三部曲。

唉,比较失望,也没大从中学到什么。

语录

什么是进取精神呢?我可以告诉各位:那就是在没有人告诉你应该怎样行事的情况下,就能做出最正确的行动。

让自己不停地忙着。忧虑的人一定要让自己沉浸在工作里,否则只有在绝望中挣扎。

每个人都会死,但并非每个人都真正地活着。

如果你想成为有勇气的人,那么你就去尝试一些至今从没有做过,但却令你胆怯的事情,而且一直做到有相当的成绩为止。

一个人的成功,只有15%归结于他的专业也只是,还有85%归于他表达思想、领导他人及唤起他人热情的能力。

人类天性中最深切的冲动,那是“成为重要人物的欲望”。

批评是没有用的,因它使人增加一层防御,而且竭力地替自己辩护。批评也是危险的,它会伤害了一个人的自尊和自重的感觉,并激起他的反抗。

你所认识的人,你愿意他改变、调整,或是进步吗?是的,那是最好不过的。可是为什么不从你自己先开始呢?

要显示一个伟大人物的伟大之处,那就要看他如何对待一个卑微的人。——卡莱尔

如果我们是那样的卑贱自私,不从别人身上得到什么,就不愿意分给别人一点快乐,假如我们的气量比一个酸苹果还小,那我们所要遇到的,也绝对是失败。

永远使别人感觉重要。

在辩论中,获得最大利益的唯一方法,就是避免讨论。

称赞最细微的进步,而且称赞每一个进步。

婚姻的成功,那不只是寻找一个适当的人,而是自己该如何做一个适当的人。

这条路,我只能经过一次,所以,凡我所能为人做的任何好事,任何一点仁慈,让我现在就做吧!不要延迟,不要忽略,因为我将不会再从这里经过了。

光阴似箭,日月如梭。日子看起来很慢很慢,但每次回首往事的时候我们又突然发觉时间原来早已在不经意间悄悄溜走了。我想,人在每个时期都有特定的价值观,人总是会改变
,但是改变这种东西却是可以参考的,只要你还知道曾经的自己到底是什么样的。很多人都会成长为自己曾经讨厌的样子,我还未长大,我不知道这句话是真是假,只知道无数的
“大人”都对这句话深信不疑,但,至少现在,我还坚持着。

对于这种“致未来”的主题,有时候我想写五年,有时候想写十年,但是我自己也不知道到底什么时候会改变,所以干脆写一篇文章,以后经常提醒自己看看。

注:下面列出的所有点,今后都不准删除

1.多年以后,你还有梦想吗?

今天的我21岁,如果按照新历来算,今天正好是我21岁的生日。人生大概已经过了四分之一,我,还有梦想。不过,我现在对梦想有点模糊,我知道自己有梦想,但说不出具
体是什么,只知道心中有一把火,有一个小宇宙。我想要创业,就在重庆创业,到时候能够养活自己、家人以及公司的员工们。我还想要祖国能够实现真正的民主自由,这么大了
,我也想要行使一下自己的选举权和被选举权,我也想让家人看看twitter和facebook,google是什么样子的。我还想以后能不能通过自己的经济实力来限
制到政府的某些腐败问题。

2.多年以后,你还像当初那样对金钱不敏感吗?

这里之所以说“敏感”,是因为我早已经过了视金钱如粪土的年纪了。现在的我,知道了金钱的作用,钱不是万能的,但没有钱是万万不能的。人是社会动物,不可能离开钱的。
但是我是绝对不会有拜金主义的,我相信自己永远不会因为钱的问题闹起家庭矛盾,不会因为钱的问题而做伤天害理的事情,不会因为钱的问题而去街头乞讨。哪怕再穷再苦,也
要通过自己的双手来挣钱。千万别做什么事情都为了钱,钱,够用就行。

3.多年以后,你会像现在所想的一样不收礼金吗?

这是一直以来我自认为的一个非常“崇高”的想法。以后自己办生日酒席或者其他人来访的时候,我绝不会理把钱当作礼物的人(当然,仅限于同龄人,上一辈肯定无法理解的,
没准还怪我不给他们面子)。大家可以送一下礼物,我想,朋友精挑细选的几块钱的礼物绝对比得上两三百一个的红包!

4.多年以后,你还会坚持自己的教育方法吗?

没错,一直都觉得自己肯定会是个好爸爸。幼稚的男人绝对会是一个好爸爸的,我会陪孩子一起玩耍,陪他一起疯,而不是让他一个人在旁边受冷落。我会回答孩子一切的问题,
哪怕我不知道,也不会说“别问这么天真的问题”,而是“来,爸爸教你用谷歌”。每次我说以后自己的孩子如果不想认真读书那不读也行的时候,大人们都说笑我说以后我就不
这样想了。我想,我会从小教孩子寻找自己的兴趣所在,如果真对读书不感兴趣并且认为读书真的不能给自己的兴趣带来什么,那么,不读吧,去追逐自己想要的东西。无论男女
,一定要在十八岁前谈一场恋爱,因为多年后他们回忆的时候肯定会怀念那段十分青涩的年华,要知道,你们的爸爸我当年和初恋谈了两年就只牵过一次手哇。但你们要记住,性
虽然是爱的升华,但在你们身体还未成熟之前,严禁性生活。不要像。。。额。。。 反正争取在他大学阶段就能完全撒手,我和老伴去过二人世界去了。

5.多年以后,你还会那么爱学习吗?

其实我一直庆幸自己能踏上计算机这条路,因为计算机行业的人员必须不停地学习。我从小就喜欢看书,无论什么书都看,希望自己这个爱好能一直发扬下去,到时候自己家的书
房就已经能成为一个小型的图书馆了,那该多好。

6.多年以后,你还会爱自己的家庭、爱自己的朋友吗?

现在我的家庭,虽然偶有一些小争执,但是我知道全家六口人都爱着这个家(过年,应该就会有七口人啦)。我和我哥绝不会像其他兄弟一样争过来争过去的。我会一直孝顺爸妈
,等到我自己有经济能力的时候,我会每年都带他们去进行一次全身体检,我要让他们活得更久,过得更快乐。另外,如果以后有了自己的家庭,我绝对不能成为一个工作狂(目
前看来,我很有可能成为一个工作狂),答应老婆的事情一定要实现。我绝对不会让老婆住租来的房子,我绝对不会让怀孕的老婆挤公交车。

现在的我,有一些朋友。希望以后的我不要滥交朋友,朋友绝对不是越多越好,我也希望以后的朋友能体谅我,因为虽然是我朋友,我也不大喜欢和朋友聊心里事的。但我绝对是
会把你们当作朋友的,要看我有没有把你当作朋友,找我借钱吧,哈哈!

7.多年以后,你真的会经常去旅游吗?

今天正是国庆节,我又没出去玩,感觉大学时期出去旅游的基本上都是女生,男生要么宅在寝室要么宅在家里,反正几乎不会出去的。其实我也很想玩,但是找不到同伴(好吧,
我承认,我不大喜欢和男生一起出去玩),不过以后有的是时间。很多人说,以后有时间才怪,以后上班什么的绝对没时间。我想,上班有没有时间不是老板能决定的,而是自己
。时间就像乳沟,挤一挤总会有的。当然,尽量别挑节假日,挑个小小的周末,来一个小小的自驾游,这才是生活啊!

8.多年以后,你真的会那么关注健康吗?

现在的我不运动,是因为场地受限,以后自己上下班应该尽量走路或者跑步,身体好的时候,每天来个四五公里。每周给老婆做一个养生的菜,平时嘛做一些家常菜就够了。然后
,每年来一个全身体检。以前的我说不喝酒,现在已经破戒了。但现在的我依然坚持着不抽烟,以后也会吗?

9.多年以后,你会麻木吗?

我想,任何一个接受过教育的人都不应该像鲁迅《藤野先生》里面所写的那样麻木。但现实确实,很多人不敢做自己应该做的事情或者本身就认为那不是自己应该做的事情。多年
以后,面对香港、台湾问题,我还会这么认真地去分析吗,至少现在的我能够理性地认为,谁都有对有错,但某些人却从来不改变一下自己,反而变本加厉,我草。我爱国,但我
不爱党。多年以后,面对摔倒的老人,我会不会不计后果地去扶起来呢?现在的我面对这样的情况我都不知道,只能按照本能去做了,本能,好吧,我肯定会去扶的。

10.多年以后,你还能回答下面这些问题吗?

你爸爸的生日、妈妈的生日、老婆的生日、朋友的生日、自己的生日是什么时候? 你的初恋是谁? 你家乡在哪儿? 你还记得当年的朋友都有哪些?你现在的朋友又有哪些?

最后,老的时候,告诉自己,答应自己的,全部做到了。如果没有,那么请尽量别讨厌现在的自己。希望多年以后当有人问“你为什么和别人不一样”的时候,我依然能反问

到:“我为什么要和别人一样?”