使用Scrapy时不要等待文件下载

3 投票
1 回答
2082 浏览
提问于 2025-04-18 07:20

我有一个处理流程,它会从一个项目中获取网址并下载文件。问题是,我还有另一个流程,在这个流程中,我需要手动检查这个文件并添加一些信息。而我真的需要在文件下载之前就完成这个检查。

class VideoCommentPipeline(object):

    def process_item(self, item, spider):
        os.system("vlc -vvv %s > /dev/null 2>&1 &" % item['file'])
        item['comment'] = raw_input('Your comment:')
        return item

class VideoDownloadPipeline(object):

    def process_item(self, item, spider):
        video_basename = item['file'].split('/')[-1]
        new_filename = os.path.join(VIDEOS_DIR, video_basename)
        downloaded = False
        for i in range(5):
            try:
                video = urllib2.urlopen(item['file']).read()
                downloaded = True
                break
            except:
                continue
        if not downloaded:
            raise DropItem("Couldn't download file from %s" % item)
        f = open(new_filename, 'wb')
        f.write(video)
        f.close()
        item['file'] = video_basename
        return item

但是现在我总是得等着下一个项目,因为前一个项目的文件还没下载好。我更希望能先检查所有项目,然后再一起下载文件。那我该怎么做呢?

1 个回答

3

Scrapy 提供了一个叫做 媒体管道 的功能,可以用来满足你的需求。虽然这个功能的文档写得不太好,但它确实存在,并且在最近的 Scrapy 版本中可以使用。要理解它是怎么工作的,你需要看看代码,个人觉得还是挺直观的。你可以查看 图像管道 的接口,这样能帮助你理解媒体管道是如何运作的。

如果你想在下载每个视频之前先检查一下,可以写一些类似下面的代码(你需要根据你的项目字段名称进行调整)

from scrapy.contrib.pipeline.media import MediaPipeline

class VideoPipeline(MediaPipeline):
    VIDEOS_DIR = "/stack/scrapy/video/video/store"

    def get_media_requests(self, item, info):
        """
        Evaluate file and, if you like it, download it.
        """
        os.system("vlc -vvv %s > /dev/null 2>&1 &" % item['video_url'][0])
        your_opinion = raw_input("how does it look?")
        item["comment"] = your_opinion
        if your_opinion == "hot":
            # issue request download video
            return Request(item["video_url"][0], meta={"item":item})

    def media_downloaded(self, response, request, info):
        """
        File is downloaded available as response.body save it.
        """
        item = response.meta.get("item")
        video = response.body
        video_basename = item['title'][0]
        new_filename = os.path.join(self.VIDEOS_DIR, video_basename)
        f = open(new_filename, 'wb')
        f.write(video)
        f.close()

撰写回答