scrapy提供了很多中间组件可以让我们自定义想要的效果,比如项目管道(itempipeline)、下载器中间件(downloadermiddleware)、蜘蛛中间件(spidermiddleware)等。我们可以通过更改或添加来实现许多功能。这种中间组件就像一个钩子。在结果完成之前,修改部分内容使结果不同,或者只记录内容。让我们先谈谈项目管道。项目流水线处理爬虫返回或迭代的item,即爬虫抓取的结果。最常用的是将结果保存在数据库中,比如保存在MySQL、MongoDB中。示例代码:importpymysqlfromtwisted.enterpriseimportadbapiclassMysqlPipeline(object):def__init__(self,adbparams,table):self.table=tableself.adbparams=adbparams@classmethoddeffrom_crawler(cls,crawler):adbparams=dict(host=crawler.settings.get('MYSQL_HOST'),port=crawler.settings.get('MSYQL_PORT'),db=crawler.settings.get('MYSQL_DBNAME'),user=crawler.settings.get('MYSQL_USER'),password=crawler.settings.get('MYSQL_PASSWORD'),chatset=crawler.settings.get('MYSQL_CHARSET'),cursorclass=pymysql.cursors.DictCursor#指定游标类型)table=crawler.settings.get('MYSQL_TABLE')returncls(adbparams,table)defopen_spider(self,spider):self.dbpool=adbapi.ConnectionPool('pymysql',**self.adbparams)defclose_spider(self,spider):self.dbpool.close()defprocess_item(自我,项目,蜘蛛):query=self.dbpool.runInteraction(self.do_insert,item)#指定操作方法和操作数据query.addCallback(self.handle_error)#处理异常返回项defdo_insert(self,cursor,item):#插入操作到数据库,不需要commit,twisted会自动commitkeys=','.join(item.keys())values=','.join(['%s']*len(item))sql='''INSERTINTO{table}({keys})VALUES({values})'''.format(table=self.table,keys=keys,values=values)try:cursor.execute(sql,tuple(item.values)()))除了异常:传递defhandle_error(self,failure):传递存储在MongoDB中的示例代码:importpymongoclassMongoPipeline(object):collection_name='scrapy_items'def__init__(self,mongo_uri,mongo_db):self.mongo_uri=mongo_uriself.mongo_db=mongo_db@classmethoddeffrom_crawler(cls,crawler):returncls(mongo_uri=crawler.settings.get('MONGO_URI'),mongo_db=crawler.settings.get('MONGO_DATABASE','items'))defopen_spider(self,spider):self.client=pymongo.MongoClient(self.mongo_uri)self.db=self.client[self.mongo_db]defclose_spider(self,蜘蛛):self.client.close()defprocess_item(self,item,spider):self.db[self.collection_name].insert_one(dict(item))returnitemitem管道有四个内置方法:open_spider:打开时spiderstarts调用,一般用于打开资源close_spider:spider关闭时调用,一般用于关闭资源process_item:spider返回item时调用,一般用于对item进行处理(保存或丢弃)from_crawler:类方法,用于获取设置。py中的配置参数与from_settings相同。上面两个例子有些不同。MySQL使用twisted实现异步存储,而MongoDB只是同步的。当然,项目流水线除了保存数据到数据库外,还有一个比较常用的功能,就是去重。虽然scrapy内置了一个请求去重的类scrapy.dupefilters.RFPDupeFilter,但是它不会对抓取的数据进行去重。相同的数据会出现在不同的请求中吗?有可能,当然要看实际情况。但是很多时候,可以直接使用数据库的去重功能,比如设置某个字段不重复。只有一些数据没有存储在数据库中,或者数据库不方便去重,包含大量重复数据,不想增加数据库服务器的负担,才会进行去重。官网去重示例代码(这里简单使用python集合,最好使用redis):fromscrapy.exceptionsimportDropItemclassDuplicatesPipeline(object):def__init__(self):self.ids_seen=set()defprocess_item(self,item,spider):ifitem['id']inself.ids_seen:raiseDropItem("Duplicateitemfound:%s"%item)else:self.ids_seen.add(item['id'])返回项目
