Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Scrapy下载大文件_Python_Scrapy - Fatal编程技术网

Python Scrapy下载大文件

Python Scrapy下载大文件,python,scrapy,Python,Scrapy,我不熟悉python和scrapy。最近我尝试爬网一个视频网站,它有3000多页,每页包含20个视频。我正在使用scrapy获取URL(包括视频源和下一页),并使用请求下载视频。问题是,脚本运行时没有任何错误,但爬行速度相当慢(大约4页/分钟)。我猜这是因为scrapy在下载视频时阻止了下一个请求,或者暂停了下载过程?如果是这样的话,有没有办法提高scrapy的速度,而不是使用多线程编写另一个脚本?以下是我的脚本: setting.py: BOT_NAME = 'video' SPIDER_M

我不熟悉python和scrapy。最近我尝试爬网一个视频网站,它有3000多页,每页包含20个视频。我正在使用
scrapy
获取URL(包括视频源和下一页),并使用
请求
下载视频。问题是,脚本运行时没有任何错误,但爬行速度相当慢(大约4页/分钟)。我猜这是因为scrapy在下载视频时阻止了下一个请求,或者暂停了下载过程?如果是这样的话,有没有办法提高scrapy的速度,而不是使用
多线程编写另一个脚本?以下是我的脚本:

setting.py:

BOT_NAME = 'video'

SPIDER_MODULES = ['video.spiders']
NEWSPIDER_MODULE = 'video.spiders'

LOG_LEVEL= 'DEBUG'

DUPEFILTER_CLASS= 'video.custom_filters.ViewKeyFilter'

DOWNLOAD_DELAY= 1

ITEM_PIPELINES= {'video.pipelines.VideoPipeline': 1,
                 'video.pipelines.Duplicates_Pipeline':300}

FILES_STORE= '/root/OneDrive/HDvideo'
自定义过滤器.py

class ViewKeyFilter(RFPDupeFilter):

def __init__(self,path=None,debug=False):
    self.urls_seen = set()
    RFPDupeFilter.__init__(self,path,debug)

def request_seen(self, request):
    if 'viewkey=' in request.url:
        pattern = re.compile(r'viewkey=(\w*)')
        if pattern.search(request.url).group(1) in self.urls_seen:
            return True
        else:
            self.urls_seen.add(request.url)
spider.py

class videoSpider(scrapy.Spider):
name = 'video'

def start_requests(self):
    url = "http://video.com/v.php?next=watch&page=1"
    yield Request(url,callback=self.parse,headers=headers,dont_filter=True)


def parse(self, response):
    doc = HTML(html=response.text)
    if doc.find('a:contains(">")'):
        yield Request('http://video.com/v.php' + doc.find('a:contains(">")')[0].attrs['href'],
                      callback=self.parse, headers=headers,dont_filter=True)
    for video_box in doc.find('div.listchannel'):
        title = video_box.find('a[target="blank"]')[0].find('img')[0].attrs['title']
        if not any(keyword in title for keyword in filterTitle):
            SDURL = video_box.find('a[target="blank"]')[0].attrs['href']
            if 'viewkey=' in SDURL:
                if video_box.find('div.hd-video'):
                    vkey = pattern.search(SDURL).group(1)  # Handling HD videos
                    yield Request('http://video.com/video_hd.php?viewkey={}'.format(vkey),
                                  callback=self.parse_videoPage, headers=headers, cookies=cookies[random.randint(0,len(dummy_cookie) -1)])
                else:
                    yield Request(SDURL,callback=self.parse_videoPage,
                                  headers=headers)  

def parse_videoPage(self,response):
    if 'video_missing' not in response.url:
        doc = HTML(html=response.text)
        title = doc.find('#video-title')[0].text
        src = doc.find('source')[0].attrs['src']
        item = VideoItem()
        item['title'] = title
        item['src'] = src
        item['vkey'] = pattern.search(response.url).group(1)
        self.logger.info('Return item. Title:{} src:{}'.format(title,src))
        yield item
管道.py

 class VideoPipeline(MediaPipeline):


    def process_item(self, item,spider):
        if item['src']:
            try:
                r =requests.get(item['src'],stream=True,timeout=5,headers=headers)
                log.logger.info('Downloading video: {}'.format(item['title']))
                with open('/root/OneDrive/HDvideo/' + item['title'] + '.mp4','wb') as f:
                    for chunk in r.iter_content(chunk_size=1024):
                        if chunk:
                            f.write(chunk)
                log.logger.info('Downloaded video: {}'.format(item['title']))
            except:
                log.logger.exception('Something bad happened: ')
            finally:
                return


class Duplicates_Pipeline(object):
    def __init__(self):
        self.vkeys_seen = set()

    def process_item(self,item,spider):
        if item is not None:
            if item['vkey'] in self.vkeys_seen:
                raise DropItem('Duplicate item found: {}'.format(item))
            else:
                self.vkeys_seen.add(item['vkey'])
                return item

视频将保存到
/root/OneDrive/
,这是一个安装在我的Vultr VPS上的目录,带有
rclone
。对不起我的英语。任何帮助都将不胜感激。

如果您没有设置并发请求(我认为默认值为16),您可以尝试更改该值。有时候降低它可以提供更好的整体速度。您好,@Tony感谢您的快速回复。我之前已经完全尝试了您所说的,包括每个域的并发请求,但是日志文件显示,一旦并发值增加,scrapy将多次访问同一页面。我认为问题来自于
pipelines.py
?如果您每页有20个视频,并且有16个并发连接,那么您的页面数将很低,因为根据视频文件的大小,您需要下载20个视频,然后才能请求下一页。你说爬行速度很慢,但pages/min不是最好的衡量标准。在浏览器中下载1个视频需要多长时间?您的互联网连接速度是多少?嗨,@Tony,我刚刚在VPS上测试过。你说得对,目标网站的下载速度确实有限制,我能得到的最大下载速度约为600KB/s。但在使用
concurrent.futures.ThreadPoolExecutor
之前,我编写了一个简单的脚本,该脚本在2小时内为我提供了22GB的视频。所以我猜scrapy正在一个接一个地下载视频?我认为最好是用一个框架来抓取大型网站,因为网站会不断更新。如果该网站将你的连接识别为机器人,它也可能会限制你的下载。您的日志中有502个错误吗?