Python 3 인터넷 파충류:Scrapy 입문 사용 Images Pipline 사진 다운로드

26989 단어 python파충류python3
Python 버 전:python 3.+실행 환경:Mac OS IDE:pycharm
  • 머리말
  • 2 초 식 Images Pipline
  • Images Pipline 의 특성
  • Images Pipline 의 워 크 플 로
  • Images Pipline 사용 사례
  • 3 ImagePipline 그림 기본 다운로드 이름 수정
  • 문서 해석
  • 코드 실전
  • ImagePipline 소스 코드 에 대한 분석
  • 사소 결
  • 머리말
      지난 블 로 그 는 간단 한 실전 으로 scrapy 프레임 워 크 의 사용 을 익 혔 다.그러나 사진 을 다운로드 하 는 방법 은 requests 라 이브 러 리 를 사용 하고 scrapy 자체 가 사진 을 가지 고 다운로드 하 는 방법ImagesPipline을 사용한다.
    둘째,이미지 Pipline 를 처음 알 게 되 었 습 니 다.
    1.Images Pipline 의 특성:
  • 최근 에 다운로드 한 데 이 터 를 다시 다운로드 하지 않 기
  • 저장 경 로 를 지정 합 니 다
  • 다운로드 한 모든 그림 을 일반적인 형식(JPG)과 모드(RGB)
  • 로 변환
  • 미리 보기 그림 생 성
  • 이미지 의 너비/높이 를 측정 하여 최소 제한 을 만족 시 킬 수 있 도록 합 니 다
  • 2.ImagesPipline 의 작업 흐름
  • 한 파충류 에서 항목 하 나 를 잡 아 그림 의 URL 을image_urls(type=list)그룹 에 넣 으 세 요.
  • item파충류 에서 돌아 와 진입Item Piplines.
  • 이미지 스 Pipeline 에 들 어가 면item그룹 내image_urls는 Scrapy 의 스케줄 러 와 다운로드 기(스케줄 러 와 다운로드 기의 미들웨어 를 재 활용 할 수 있다 는 뜻)에 의 해 다운로드 되 며,우선 순위 가 높 으 면 다른 페이지 에서 캡 처 되 기 전에 처리 된다.프로젝트 는 파일 의 다운로드 가 완료 되 거나 어떤 이유 로 다운로드 가 완료 되 지 않 을 때 까지 이 특정한 파이프 단계 에서'locker'상 태 를 유지 합 니 다.
  • 파일 을 다운로드 하면 다른 필드(files)가 구조 로 업 데 이 트 됩 니 다.이 그룹 은 다운로드 경로,원본 캡 처 주소URLs그룹 에서 얻 은)와 그림 의 검사 코드(checksum)등 사전 목록 을 포함 합 니 다.images 목록 의 파일 순 서 는 원본image_urls그룹 과 일치 합 니 다.어떤 그림 을 다운로드 하 는 데 실패 하면 잘못된 정 보 를 기록 하고 그림 도 files 그룹 에 나타 나 지 않 습 니 다.

  • 3.ImagesPipline 사용 사례
    정의 item
    media pipeline 을 사용 하기 위해 서 는 사용 하기 만 하면 됩 니 다.이 어 spider 가'file'이 있 는 것 을 되 돌려 줍 니 다.urls'나'image 'urls'(Files 나 Images Pipeline 을 사용 하 는 것 에 달 려 있 음)키 의 dict 는 pipeline 에서 해당 하 는 결 과 를 추출 합 니 다.
    Item 을 정의 하 는 item 에서 사용 하 는 것 을 더 좋아한다 면 필요 한 필드 를 설정 해 야 합 니 다.예 를 들 어 Image Pipeline 의 예 를 들 어:
    
    import scrapy
    
    class MyItem(scrapy.Item):
    
        # ... other item fields ...
        image_urls = scrapy.Field()
        images = scrapy.Field()

      여기 서 제 가 아 이 템 을 정 의 했 어 요.
    import scrapy
    
    class MscrapyItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        image_urls = scrapy.Field()
        image_ids = scrapy.Field()
        image_paths = scrapy.Field()
        pass

    설정 설정
    우선 항목 에 추가 해 야 합 니 다image_urls
    ITEM_PIPELINES = {'scrapy.pipeline.images.ImagesPipeline': 1}

    이 어ITEM_PIPELINES다운로드 한 그림 을 저장 하기 위해 유효한 폴 더 로 설정 했다.그렇지 않 으 면 파 이 프 는 ITEM 에 있어 도 사용 하지 않 습 니 다.PIPELINES 설정 에 추가 되 었 습 니 다.
    이미지 파이프라인 에 대한 설정IMAGES_STORE
    IMAGES_STORE = '/path/to/valid/dir'

    미리 보기 그림 등 다른 속성 에 대해 서 는 공식 문 서 를 참조 할 수 있 습 니 다.
    3.ImagePipline 그림 기본 다운로드 이름 수정
    1.문서 판독IMAGES_STORE의 여러 속성 에서 특히 주의해 야 할 것 은 파일 시스템 저장 입 니 다.파일 저장 시의 기본 이름 을 정의 하기 때문에 그림 의 기본 이름 을 수정 하려 면 여기 서부 터 시작 해 야 합 니 다.
    파일 시스템 저장 소
    파일 은 URL 의 SHA 1 hash 를 파일 이름 으로 합 니 다.
    예 를 들 어 아래 그림 URL 에 대해 서 는...
    http://www.example.com/image.jpg 그것 의 SHA 1 hash 값 은:ImagePipline
    다음 파일 로 다운 로드 됩 니 다:3afec3b4765f8f0a07b78f98c07b83f013567a0a
    그 중:< IMAGES_STORE>/full/3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg설정 에 정 의 된 폴 더>IMAGES_STORE그림 과 미리 보기 그림 을 구분 하 는 키 폴 더 입 니 다.
    우 리 는 당연히 자신 이 다운로드 한 그림 의 이름 이 이해 할 수 없 는 숫자 라 는 것 을 원 하지 않 는 다.그래서 파일 이름 을 수정 해 야 합 니 다.
    공식 문서 에서 다시 쓸 수 있 는 두 가지 방법 을 제공 합 니 다.
  • full
  • get_media_requests(item, info)

  • get_media_requests(item, info)
    작업 프로 세 스에 서 볼 수 있 듯 이 파 이 프 는 파일 의 URL 을 얻 고 프로젝트 에서 다운로드 합 니 다.이렇게 하기 위해 서 는 재 작성item_completed(results, items, info)방법 이 필요 하 며,각 그림 URL 에 대해 서 는 Request 를 되 돌려 주어 야 합 니 다.
    def get_media_requests(self, item, info):
        for file_url in item['file_urls']:
            yield scrapy.Request(file_url) 
                ,        ,    2-             `item_completed()`  :       
    
    get_media_requests() : (success, file_info_or_error)는 불 값 입 니 다.그림 이 성공 적 으로 다운로드 되 었 을 때success입 니 다.어떤 이유 로 다운로드 에 실 패 했 습 니 다Truefileinfo_or_error 는 다음 키 워드 를 포함 하 는 사전(성공 하면False또는 문제 가 발생 하면True입 니 다.Twisted Failure-파일 다운로드 url.요청 한 url 을url방법 으로 되 돌려 줍 니 다.get_media_requests()-이미지 저장 경로(FILES 와 유사)STORE)path-그림 내용 MD5 hash itemcompleted()가 받 은 원 그룹 목록 은checksum방법 으로 요청 한 순서 와 일치 하도록 보증 해 야 합 니 다.다음은 results 매개 변수의 전형 적 인 값 입 니 다.
    [(True,   {'checksum': '2b00042f7481c7b056c4b410d28f33cf',    'path':
    'full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg',    'url':
    'http://www.example.com/files/product1.pdf'}),  (False,  
    Failure(...))] 

    기본get_media_requests()방법 으로 되 돌아 갑 니 다get_media_requests().이 는 프로젝트 에 다운로드 할 파일 이 없다 는 것 을 의미 합 니 다.
    item_completed(results, items, info)
    하나의 단독 항목 의 모든 그림 이 완료 되 었 을 때(다운 로드 를 완료 하거나 어떤 이유 로 다운로드 에 실 패 했 을 때)None방법 이 호출 됩 니 다.FilesPipeline.item_completed()방법 은 출력 을 되 돌려 야 합 니 다.다음 프로젝트 파이프 단계 로 보 내 질 것 입 니 다.따라서 임의의 파이프 에서 한 것 처럼 항목 을 되 돌려 야 합 니 다.이것 은item_completed()방법의 예 입 니 다.그 중에서 우리 가 다운로드 한 그림 경로(results 에 전송)를item_completed()프로젝트 그룹 에 저장 합 니 다.만약 에 그림 이 없 으 면 우 리 는 항목 을 버 릴 것 입 니 다.
    from scrapy.exceptions import DropItem
    def item_completed(self, results, item, info):
        image_paths = [x['path'] for ok, x in results if ok]
        if not file_paths:
            raise DropItem("Item contains no files")
        item['image_paths'] = image_paths
        return item 

    기본 적 인 상황 에서image_paths방법 으로 되 돌아 갑 니 다item_completed().
    다음은 그림 파이프 의 완전한 예 입 니 다.그 방법 은 위 와 같 습 니 다.
    import scrapy
    from scrapy.pipeline.images import ImagesPipeline
    from scrapy.exceptions import DropItem
    
    class MyImagesPipeline(ImagesPipeline):
    
        def get_media_requests(self, item, info):
            for image_url in item['image_urls']:
                yield scrapy.Request(image_url)
    
        def item_completed(self, results, item, info):
            image_paths = [x['path'] for ok, x in results if ok]
            if not image_paths:
                raise DropItem("Item contains no images")
            item['image_paths'] = image_paths
            return item

    2.코드 실전
    이전 블 로그 의 실전 데모 를 계속 하 겠 습 니 다.여기 서 piplines 의 코드 를 수정 하 였 습 니 다.
    class UnsplashPipeline(ImagesPipeline):
        def get_media_requests(self, item, info):
            for image_url in item['image_urls']:
                yield scrapy.Request(image_url)
    
        def item_completed(self, results, item, info):
            image_paths = [x['path'] for ok, x in results if ok]
            if not image_paths:
                raise DropItem("Item contains no images")
            if item['image_ids']:
                new_path = "full/"+item['image_ids'][0]+".jpg"
            os.rename(settings.IMAGES_STORE+"/"+image_paths[0],settings.IMAGES_STORE+"/"+new_path)
            item['image_paths'] = new_path
            return item

    이 방법 은 실질 적 으로item기본 파일 이름 을 저장 한 후 파일 이름 을 바 꾸 는 것 이다.
    3.ImagePipline 소스 코드 에 대한 분석
    원본 코드 를 읽 으 면ImagesPipline방법 이 바로 그림 에 파일 이름 을 부여 하 는 방법 임 을 알 수 있다.그 러 니까 이 방법 을 직접 다시 쓰 는 게 좋 지 않 겠 습 니까?여기 서 우 리 는 먼저file_path()방법의 소스 코드 를 살 펴 보 자.
    def file_path(self, request, response=None, info=None):
            ## start of deprecation warning block (can be removed in the future)
            def _warn():
                from scrapy.exceptions import ScrapyDeprecationWarning
                import warnings
                warnings.warn('ImagesPipeline.image_key(url) and file_key(url) methods are deprecated, '
                              'please use file_path(request, response=None, info=None) instead',
                              category=ScrapyDeprecationWarning, stacklevel=1)
    
            # check if called from image_key or file_key with url as first argument
            if not isinstance(request, Request):
                _warn()
                url = request
            else:
                url = request.url
    
            # detect if file_key() or image_key() methods have been overridden
            if not hasattr(self.file_key, '_base'):
                _warn()
                return self.file_key(url)
            elif not hasattr(self.image_key, '_base'):
                _warn()
                return self.image_key(url)
            ## end of deprecation warning block
    
            image_guid = hashlib.sha1(url).hexdigest()  # change to request.url after deprecation
            return 'full/%s.jpg' % (image_guid)
    

    파일 경 로 를 수정 하기 위해 수정file_path()한 것 이 라면 원본 코드 에 대한 침입 이 너무 크다.그래서 공식 문서 에 도 재 작성 을 건의 하지 않 았 다file_path.
    다음은 Images Pinpline 의 소스 코드 입 니 다.참고 하 시기 바 랍 니 다.
    class ImagesPipeline(FilesPipeline):
        """Abstract pipeline that implement the image thumbnail generation logic
    
        """
    
        MEDIA_NAME = 'image'
        MIN_WIDTH = 0
        MIN_HEIGHT = 0
        THUMBS = {}
        DEFAULT_IMAGES_URLS_FIELD = 'image_urls'
        DEFAULT_IMAGES_RESULT_FIELD = 'images'
    
        @classmethod
        def from_settings(cls, settings):
            cls.MIN_WIDTH = settings.getint('IMAGES_MIN_WIDTH', 0)
            cls.MIN_HEIGHT = settings.getint('IMAGES_MIN_HEIGHT', 0)
            cls.EXPIRES = settings.getint('IMAGES_EXPIRES', 90)
            cls.THUMBS = settings.get('IMAGES_THUMBS', {})
            s3store = cls.STORE_SCHEMES['s3']
            s3store.AWS_ACCESS_KEY_ID = settings['AWS_ACCESS_KEY_ID']
            s3store.AWS_SECRET_ACCESS_KEY = settings['AWS_SECRET_ACCESS_KEY']
    
            cls.IMAGES_URLS_FIELD = settings.get('IMAGES_URLS_FIELD', cls.DEFAULT_IMAGES_URLS_FIELD)
            cls.IMAGES_RESULT_FIELD = settings.get('IMAGES_RESULT_FIELD', cls.DEFAULT_IMAGES_RESULT_FIELD)
            store_uri = settings['IMAGES_STORE']
            return cls(store_uri)
    
        def file_downloaded(self, response, request, info):
            return self.image_downloaded(response, request, info)
    
        def image_downloaded(self, response, request, info):
            checksum = None
            for path, image, buf in self.get_images(response, request, info):
                if checksum is None:
                    buf.seek(0)
                    checksum = md5sum(buf)
                width, height = image.size
                self.store.persist_file(
                    path, buf, info,
                    meta={'width': width, 'height': height},
                    headers={'Content-Type': 'image/jpeg'})
            return checksum
    
        def get_images(self, response, request, info):
            path = self.file_path(request, response=response, info=info)
            orig_image = Image.open(StringIO(response.body))
    
            width, height = orig_image.size
            if width < self.MIN_WIDTH or height < self.MIN_HEIGHT:
                raise ImageException("Image too small (%dx%d < %dx%d)" %
                                     (width, height, self.MIN_WIDTH, self.MIN_HEIGHT))
    
            image, buf = self.convert_image(orig_image)
            yield path, image, buf
    
            for thumb_id, size in self.THUMBS.iteritems():
                thumb_path = self.thumb_path(request, thumb_id, response=response, info=info)
                thumb_image, thumb_buf = self.convert_image(image, size)
                yield thumb_path, thumb_image, thumb_buf
    
        def convert_image(self, image, size=None):
            if image.format == 'PNG' and image.mode == 'RGBA':
                background = Image.new('RGBA', image.size, (255, 255, 255))
                background.paste(image, image)
                image = background.convert('RGB')
            elif image.mode != 'RGB':
                image = image.convert('RGB')
    
            if size:
                image = image.copy()
                image.thumbnail(size, Image.ANTIALIAS)
    
            buf = StringIO()
            image.save(buf, 'JPEG')
            return image, buf
    
        def get_media_requests(self, item, info):
            return [Request(x) for x in item.get(self.IMAGES_URLS_FIELD, [])]
    
        def item_completed(self, results, item, info):
            if self.IMAGES_RESULT_FIELD in item.fields:
                item[self.IMAGES_RESULT_FIELD] = [x for ok, x in results if ok]
            return item
    
        def file_path(self, request, response=None, info=None):
            ## start of deprecation warning block (can be removed in the future)
            def _warn():
                from scrapy.exceptions import ScrapyDeprecationWarning
                import warnings
                warnings.warn('ImagesPipeline.image_key(url) and file_key(url) methods are deprecated, '
                              'please use file_path(request, response=None, info=None) instead',
                              category=ScrapyDeprecationWarning, stacklevel=1)
    
            # check if called from image_key or file_key with url as first argument
            if not isinstance(request, Request):
                _warn()
                url = request
            else:
                url = request.url
    
            # detect if file_key() or image_key() methods have been overridden
            if not hasattr(self.file_key, '_base'):
                _warn()
                return self.file_key(url)
            elif not hasattr(self.image_key, '_base'):
                _warn()
                return self.image_key(url)
            ## end of deprecation warning block
    
            image_guid = hashlib.sha1(url).hexdigest()  # change to request.url after deprecation
            return 'full/%s.jpg' % (image_guid)
    
        def thumb_path(self, request, thumb_id, response=None, info=None):
            ## start of deprecation warning block (can be removed in the future)
            def _warn():
                from scrapy.exceptions import ScrapyDeprecationWarning
                import warnings
                warnings.warn('ImagesPipeline.thumb_key(url) method is deprecated, please use '
                              'thumb_path(request, thumb_id, response=None, info=None) instead',
                              category=ScrapyDeprecationWarning, stacklevel=1)
    
            # check if called from thumb_key with url as first argument
            if not isinstance(request, Request):
                _warn()
                url = request
            else:
                url = request.url
    
            # detect if thumb_key() method has been overridden
            if not hasattr(self.thumb_key, '_base'):
                _warn()
                return self.thumb_key(url, thumb_id)
            ## end of deprecation warning block
    
            thumb_guid = hashlib.sha1(url).hexdigest()  # change to request.url after deprecation
            return 'thumbs/%s/%s.jpg' % (thumb_id, thumb_guid)
    
        # deprecated
        def file_key(self, url):
            return self.image_key(url)
        file_key._base = True
    
        # deprecated
        def image_key(self, url):
            return self.file_path(url)
        image_key._base = True
    
        # deprecated
        def thumb_key(self, url, thumb_id):
            return self.thumb_path(url, thumb_id)
        thumb_key._base = True
    
    

    소결
    『8195』scrapy 자체 가 제공 하 는 도 구 는 이미 풍부 하고 실 용적 입 니 다.저 는 scrapy 에 대한 이해 에 한계 가 있 습 니 다.입문 일 뿐 입 니 다.본 블 로그 도 제 가file_path독학 후의 총 결 일 뿐 입 니 다.잘못 이 있 으 면 지적 해 주 십시오.

    좋은 웹페이지 즐겨찾기