加快网络文件下载的处理速度

时间:2016-12-07 02:25:01

标签: python performance python-2.7 urllib2 gist

我编写的程序必须先从网上下载一堆文件才能运行,所以我创建了一个可以下载所有文件的函数,并且"初始化&#34 ; 名为init_program的程序,它的工作原理是它通过一对dicts运行,它们在github上有一个gistfiles的URL。它会提取网址并使用urllib2下载它们。我无法添加所有文件,但您可以通过克隆回购here来尝试。以下是将从要点创建文件的功能:

def init_program():
    """ Initialize the program and allow all the files to be downloaded
        This will take awhile to process, but I'm working on the processing
        speed """

    downloaded_wordlists = []  # Used to count the amount of items downloaded
    downloaded_rainbow_tables = []

    print("\n")
    banner("Initializing program and downloading files, this may take awhile..")
    print("\n")

    # INIT_FILE is a file that will contain "false" if the program is not initialized
    # And "true" if the program is initialized
    with open(INIT_FILE) as data: 
        if data.read() == "false": 
            for item in GIST_DICT_LINKS.keys():
                sys.stdout.write("\rDownloading {} out of {} wordlists.. ".format(len(downloaded_wordlists) + 1, 
                                                                                  len(GIST_DICT_LINKS.keys())))
                sys.stdout.flush()
                new_wordlist = open("dicts/included_dicts/wordlists/{}.txt".format(item), "a+") 
                # Download the wordlists and save them into a file
                wordlist_data = urllib2.urlopen(GIST_DICT_LINKS[item])
                new_wordlist.write(wordlist_data.read())
                downloaded_wordlists.append(item + ".txt")
                new_wordlist.close()

            print("\n")
            banner("Done with wordlists, moving to rainbow tables..")
            print("\n")

            for table in GIST_RAINBOW_LINKS.keys():
                sys.stdout.write("\rDownloading {} out of {} rainbow tables".format(len(downloaded_rainbow_tables) + 1, 
                                                                                    len(GIST_RAINBOW_LINKS.keys())))
                new_rainbowtable = open("dicts/included_dicts/rainbow_tables/{}.rtc".format(table))
                # Download the rainbow tables and save them into a file
                rainbow_data = urllib2.urlopen(GIST_RAINBOW_LINKS[table])
                new_rainbowtable.write(rainbow_data.read())
                downloaded_rainbow_tables.append(table + ".rtc")
                new_rainbowtable.close()

            open(data, "w").write("true").close()  # Will never be initialized again
        else:
            pass

    return downloaded_wordlists, downloaded_rainbow_tables

这是可行的,但是它非常慢,由于文件的大小,每个文件至少有100,000行。如何加快此功能,使其更快,更友好?

2 个答案:

答案 0 :(得分:1)

几周前,我遇到了类似的情况,需要下载许多大文件,但我发现所有简单的纯Python解决方案在下载优化方面都不够好。所以我找到了 Axel - 适用于Linux和Unix的Light命令行下载加速器

  

什么是Axel?

     

Axel尝试使用多个加速下载过程   连接一个文件,类似于DownThemAll和其他着名的   程式。它也可以使用多个镜像进行一次下载。

     

使用Axel,您可以更快地从Internet获取文件。所以,阿克塞尔可以   加速下载高达60%(大约,根据一些人说   测试)。

Usage: axel [options] url1 [url2] [url...]

--max-speed=x       -s x    Specify maximum speed (bytes per second)
--num-connections=x -n x    Specify maximum number of connections
--output=f      -o f    Specify local output file
--search[=x]        -S [x]  Search for mirrors and download from x servers
--header=x      -H x    Add header string
--user-agent=x      -U x    Set user agent
--no-proxy      -N  Just don't use any proxy server
--quiet         -q  Leave stdout alone
--verbose       -v  More status information
--alternate     -a  Alternate progress indicator
--help          -h  This information
--version       -V  Version information

由于axel是用C语言编写的,并且没有Python的C扩展,所以我使用subprocess模块在​​外部执行它,并且对我来说非常适合。

您可以这样做:

cmd = ['/usr/local/bin/axel', '-n', str(n_connections), '-o',
               "{0}".format(filename), url]
process = subprocess.Popen(cmd,stdin=subprocess.PIPE, stdout=subprocess.PIPE)

您还可以解析每次下载解析stdout输出的进度。

    while True:
        line = process.stdout.readline()
        progress = YOUR_GREAT_REGEX.match(line).groups()
        ...

答案 1 :(得分:0)

在等待每次下载时,您正在阻止。因此,总时间是每次下载的往返时间的总和。您的代码可能会花费大量时间等待网络流量。改善这种情况的一种方法是在等待每个响应时阻止。您可以通过多种方式完成此操作。例如,通过将每个请求移交给单独的线程(或进程),或者使用事件循环和协同程序。阅读线程和asyncio模块。