簡體   English   中英

在python中並行地從url下載文件

[英]Download files from url parallely in python

我在數據庫中有一些鏈接,我想並行下載。 我嘗試連續做,但花了太多時間。 我有大約1877個鏈接。

我嘗試使用此代碼並行運行下載,但它會引發錯誤:失敗:'tuple'對象沒有屬性'read'

#!/usr/bin/env python

import urllib
from stream import ThreadPool

URLs = [
  'http://www.cnn.com/',
  'http://www.bbc.co.uk/',
  'http://www.economist.com/',
  'http://nonexistant.website.at.baddomain/',
  'http://slashdot.org/',
  'http://reddit.com/',
  'http://news.ycombinator.com/'
 ]

def retrieve(urls):
    for url in urls:
    print url,' '
    res = urllib.urlretrieve(url).read()
    yield url, res

if __name__ == '__main__':
    retrieved = URLs >> ThreadPool(retrieve, poolsize=7)
    for url, content in retrieved:
        print '%r is %d bytes' % (url, len(content))
    for url, exception in retrieved.failure:
        print '%r failed: %s' % (url, exception)

我也嘗試過這個:

import urllib
import tldextract
from multiprocessing.pool import ThreadPool

URLs = [
  'http://www.cnn.com/',
  'http://www.bbc.co.uk/',
  'http://www.economist.com/',
  'http://nonexistant.website.at.baddomain/',
   'http://slashdot.org/',
  'http://reddit.com/',
  'http://news.ycombinator.com/'
 ]


def dwld(url):
  print url
  res = urllib.urlopen(url).read() 
  filename = tldextract.extract(url)
  with open(filename.domain, 'wb') as fh:
     fh.write(res)
  return url 

pool = ThreadPool(processes = 4)
pool.map(dwld, URLs)

給我回溯(最近一次調用最后一次):文件“dwld_thread.py”,第26行,在pool.map(dwld,URL)文件“/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2。 6 / multiprocessing / pool.py“,第148行,在map中返回self.map_async(func,iterable,chunksize).get()文件”/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2。 6 / multiprocessing / pool.py“,第422行,在get raise self._value IOError:[Errno socket error] [Errno 8]提供nodename或servname,或者不知道

我不知道那個stream.ThreadPool是你正在使用的,或者它的API是什么......但問題很明顯:

res = urllib.urlretrieve(url).read()

如果你看一下urlretrieve的文檔:

返回一個元組(文件名,標題),其中filename是可以在其下找到對象的本地文件名...

你顯然不能打電話read 如果要使用此舊版API下載到本地文件,然后讀取該文件,您可以

filename, headers = urllib.urlretrieve(url)
with open(filename) as f:
    res = f.read()

但為什么? 只需使用urllib2.urlopen ,它“返回一個類似文件的對象,有兩個額外的方法”,所以你只需要調用read就可以了,你就不會創建一個臨時文件,而你也沒有使用舊的函數設計不對,沒有人能保持多年。


但是Python在標准庫中內置了一個很好的ThreadPoolExecutor 如果你看看他們向你展示的第一個例子,那正是你想要做的。

不幸的是,你使用的是Python 2.x,它沒有concurrent.futures模塊。 幸運的是,有一個反向移植與2.5+工作PyPI上。

Python還有multiprocessing.dummy.Pool (也可以在未記錄的,但可能更具可讀性的名稱下進行multiprocessing.ThreadPool )。 但是如果你願意走出stdlib以外的某個模塊,你顯然不知道如何使用,而且我從未聽說過,我猜你使用futures不會有任何問題。 所以:

import futures
import urllib2

URLs = [
  'http://www.cnn.com/',
  'http://www.bbc.co.uk/',
  'http://www.economist.com/',
  'http://nonexistant.website.at.baddomain/',
  'http://slashdot.org/',
  'http://reddit.com/',
  'http://news.ycombinator.com/'
 ]

def load_url(url):
    return urllib2.urlopen(url).read()

if __name__ == '__main__':
    with futures.ThreadPoolExecutor(max_workers=7) as executor:
        fmap = dict((executor.submit(load_url, url), url) for url in URLs)
        for f in futures.as_completed(fmap):
            url = fmap[f]
            try:
                content = f.result()
            except Exception as exception:
                print '%r failed: %s' % (url, exception)
            else:
                print '%r is %d bytes' % (url, len(content))
from threading import *
from time import sleep
# if Python2:
import urllib
# if Python3:
# import urllib.request

URLs = [
  'http://www.cnn.com/',
  'http://www.bbc.co.uk/',
  'http://www.economist.com/',
  'http://nonexistant.website.at.baddomain/',
  'http://slashdot.org/',
  'http://reddit.com/',
  'http://news.ycombinator.com/'
 ]

class worker(Thread):
    def __init__(self, link):
        Thread.__init__(self)
        self.link = link
        self.start()
    def run(self):
        # if Python2:
        res = urllib.urlopen(url).read() # as mentioned by @DhruvPathak
        # if Python3:
        # res = urllib.request.urlopen(url).read()
        with open(url, 'rb') as fh:
            fh.write(res) # store fetched data in a file called <link>

for url in urls:
    while len(enumerate()) > 500:
        sleep(0.25)
    worker(url)

while len(enumerate()) > 1:
    sleep(0.25) # wait for all threads to finish

urllib.urlretrieve(url).read()應該是urllib.urlopen(url).read()

那么使用multiprocessing呢?

示例代碼:

#! /usr/bin/env python

# -*- coding: utf-8 -*-


import sys
import urllib
from multiprocessing import Pool

import os

POOL = 8
PDFS_DOWNLOAD_DIR = 'pdfs'
PDF_LINKS = sys.argv[1]


class DownloadFiles(object):
    def __init__(self):
        self.pdf_links = self.read_links_from_file()
        self.create_download_dir()

    def create_download_dir(self):
        try:
            if not os.path.exists(PDFS_DOWNLOAD_DIR):
                os.makedirs(PDFS_DOWNLOAD_DIR)
        except IOError as e:
            exit()

    def read_links_from_file(self):
        try:
            with open(PDF_LINKS, 'r') as f:
                return list(set([x.strip() for x in f]))
        except (IndexError, IOError) as e:
            exit()

    def get_file(self, link):

        filename = link.split('/')[-2]

        print('Downloading file --> "{filename}"'.format(
            filename=filename
        ))

        urllib.urlretrieve(link, filename='{pdfs_data}/{filename}'.format(
            pdfs_data=PDFS_DOWNLOAD_DIR,
            filename=filename
        ))

    def download(self):

        pool = Pool(POOL)
        pool.map(self.get_file, self.pdf_links)

        pool.close()
        pool.join()

        print('\nSuccessfully downloaded files from given source!\n')


d = DownloadFiles()
d.download()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM