爬虫框架Scrapy之其他通用功能
去重
通过Item Pipeline写一个去重的过滤去:
丢弃那些已经被处理过的item。假设我们的item有一个唯一的id,但是我们spider返回的多个item中包含有相同的id,我们就可以使用集合来去重,下面是一个例子:
from scrapy.exceptions import DropItem class DuplicatesPipeline(object): def __init__(self): self.ids_seen = set() def process_item(self, item, spider): if item['id'] in self.ids_seen: raise DropItem("Duplicate item found: %s" % item) else: self.ids_seen.add(item['id']) return item
文件与图片下载
通过Media Pipeline下载文件(图片)。
启用Media Pipeline
# 同时启用图片和文件管道 ITEM_PIPELINES = { 'scrapy.pipelines.images.ImagesPipeline': 1, 'scrapy.pipelines.files.FilesPipeline': 2, } FILES_STORE = 'D:' # 文件存储路径 IMAGES_STORE = 'D' # 图片存储路径 # 避免下载最近90天已经下载过的文件内容 FILES_EXPIRES = 90 # 避免下载最近90天已经下载过的图像内容 IMAGES_EXPIRES = 30 # 设置图片缩略图 IMAGES_THUMBS = { 'small': (50, 50), 'big': (250, 250), } # 图片过滤器,最小高度和宽度,低于此尺寸不下载 IMAGES_MIN_HEIGHT = 110 IMAGES_MIN_WIDTH = 110
下面我们以ImagesPipeline为例来自定义ImagesPipeline,需要重写以下两个方法:
- get_media_requests(item, info)
在工作流程中可以看到,管道会得到图片的URL并从项目中下载。为了这么做,你需要重写 get_media_requests() 方法,并对各个图片URL返回一个Request:
def get_media_requests(self, item, info): for image_url in item['image_urls']: yield scrapy.Request(image_url)
这些请求将被管道处理,当它们完成下载后,结果将以2元素的元组列表形式传送到 item_completed() 方法: 每个元组包含 (success, file_info_or_error)。
- item_completed(results, items, info)
当一个单独项目中的所有图片请求完成时,例如,item里面一共有10个URL,那么当这10个URL全部下载完成以后,ImagesPipeline.item_completed() 方法将被调用。默认情况下, item_completed() 方法返回item。
例子,使用ImagesPipeline下载图片:
下面我们用上面学习到的知识来下载一些图片。
我们以http://jandan.net/ooxx为例,把页面上的图片下载下来,并产生缩略图
我们新建一个项目,名为jiandan,各个文件内容如下。
item.py
import scrapy class JiandanItem(scrapy.Item): image_urls = scrapy.Field()#图片的链接 images = scrapy.Field()
jiandan_spider.py
import scrapy from jiandan.items import JiandanItem class jiandanSpider(scrapy.Spider): name = 'jiandan' start_urls = ["http://jandan.net/ooxx"] def parse(self, response): item = JiandanItem() item['image_urls'] = response.xpath('//img//@src').extract() #提取图片链接 yield item
settings.py
BOT_NAME = 'jiandan' SPIDER_MODULES = ['jiandan.spiders'] NEWSPIDER_MODULE = 'jiandan.spiders' DEFAULT_REQUEST_HEADERS = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en', 'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", } ITEM_PIPELINES = { 'jiandan.pipelines.JiandanPipeline':1, } IMAGES_STORE='H:\\jiandan' IMAGES_THUMBS = { 'small': (50, 50), 'big': (200, 200), }
pipelinse.py
import scrapy from scrapy.exceptions import DropItem from scrapy.pipelines.images import ImagesPipeline #内置的图片管道 class JiandanPipeline(ImagesPipeline):#继承ImagesPipeline这个类 def get_media_requests(self, item, info): for image_url in item['image_urls']: image_url = "http://" + image_url 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") return item

浙公网安备 33010602011771号