当Spider解析完Response之后,Item就会传递到Item Pipeline,被定义的Item Pipeline组件会顺次调用,完成一连串的处理过程。
1.核心方法
process_item(item,spider)
这个是必须要实现的方法,被定义的Item Pipeline会默认调用这个方法对Item进行处理。
open_spider(spider)
这个方法是在Spider开启的时候自动调用的。在这里我们可以做一些初始化操作,如开启数据库连接等。其中spider就是被开启的Spider对象
close_spider(spider)
是在Spider关闭的时候自动调用的。在这里我们可以做一些收尾工作,如关闭数据库连接等
from_crawler(cls,crawler)
是一个类方法,用@classmethod标识,是一种依赖注入的方式。它的参数是crawler,通过crawler对象,我们可以拿到Scrapy的所有核心组件,如全局配置的每个信息,然后创建一个Pipeline实例,参数cls就是class,最后返回一个class实例。
实战练习:抓取360摄影美图
一、构造请求
在settings.py里面定义一个变量MAX_PAGE
在Spider中定义start_request()方法
def start_requests(self):
data = {'ch': 'photography', 'listtype': 'new'}
base_url = 'https://image.so.com/zj?'
for page in range (1, self.settings.get ('MAX_PAGE') + 1):
data['sn'] = page * 30
params = urlencode (data)
url = base_url + params
yield Request (url, self.parse)
修改settings.py中的ROBOTSTXT_OBEY变量,将其设置为False
二、提取信息
在Item中定义一个ImageItem
from scrapy import Item,Field
class ImageItem(Item):
# define the fields for your item here like:
# name = scrapy.Field()
collection = table = 'images'
id = Field()
url = Field()
title = Field()
thumb = Field()
接下来提取Spider里有关信息,将Spider里的parse()方法该写
def parse(self, response):
result = json.loads(response.text)
for image in result.get('list'):
item = ImageItem()
item['id'] = image.get('imageid')
item['url'] = image.get('qhimg_url')
item['title'] = image.get('group_title')
item['thumb'] = image.get('qhimg_thumb_url')
yield item
三、存储信息到数据库
新建一个数据库——images360,新建一个数据表——images
实现一个MySQLPipeline
class MysqlPipeline():
def __init__(self,host,database,user,password,port):
self.host = host
self.database = database
self.user = user
self.password = password
self.port = port
@classmethod
def from_crawler(cls,crawler):
return cls(
host=crawler.settings.get('MYSQL_HOST'),
database=crawler.settings.get ('MYSQL_DATABASE'),
user=crawler.settings.get ('MYSQL_USER'),
password=crawler.settings.get ('MYSQL_PASSWORD'),
port=crawler.settings.get ('MYSQL_PORT'),
)
def open_spider(self,spider):
self.db = pymysql.connect(self.host,self.user,self.password,self.database,charset='utf8',port=self.port)
self.cursor = self.db.cursor()
def close_spider(self,spider):
self.db.close()
def process_item(self,item,spider):
data = dict(item)
keys = ','.join(data.keys())
values = ','.join(['%s']*len(data))
sql = 'insert into %s (%s) values (%s)' % (item.table,keys,values)
self.cursor.execute(sql,tuple(data.values()))
self.db.commit()
return item
在settings.py里添加数据库相关变量
MYSQL_HOST = 'localhost'
MYSQL_DATABASE = 'images360'
MYSQL_PORT = 3306
MYSQL_USER = 'root'
MYSQL_PASSWORD = 'root'
四、下载图片到本地
Scrapy提供了专门处理下载的Pipeline,包括文件下载和图片下载
首先定义存储文件的路径,在settings.py中添加IMAGES_STORE
IMAGES_STORE = './images' #我们将路径定义为当前路径下的images子文件夹,即下载的图片都会保存到本项目的images文件夹中。
自定义ImagePipeline,继承内置的ImagesPipeline,重写几个方法
class ImagePipeline(ImagesPipeline):
def file_path(self, request, response=None, info=None):
url = request.url
file_name = url.split('/')[-1]
return file_name
def item_completed(self, results, item, info):
image_paths = [x['path'] for ok,x in results if ok]
if not image_paths:
raise DropItem('Image Downloaded Failed')
return item
def get_media_requests(self, item, info):
yield Request(item['url'])
五、修改settings.py,设置ITEM_PIPELINES
ITEM_PIPELINES = {
'images360.pipelines.ImagePipeline': 300,
'images360.pipelines.MysqlPipeline': 301,
}