爬虫框架Scrapy(三):Scrapy中的管道pipeline+下载中间件middleware

一、管道文件pipeline

1.pipeline的作用

  • 清理html数据
  • 验证爬取的数据
  • 去重并丢弃
  • 将爬取的结果保存到数据库中或文件中

2.简单使用一下管道pipeline

管道的作用是为了将spider爬虫拿到的字段数据进行一些处理

例如我们有个baidu_spider爬虫

import scrapy

class BaiduSpiderSpider(scrapy.Spider):
    name = 'baidu_spider'
    allowed_domains = []
    start_urls = ['http://www.baidu.com']

    def parse(self, response):
        item = {
    
    }
        item['url'] = response.url
        return item

然后我们在pipelines.py 文件中输出一下这个item

from itemadapter import ItemAdapter

class GubaScrapyPipeline:
    def process_item(self, item, spider):
        print(item)
        return item

想要管道文件生效,需要配置一下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DyfSxzuy-1596811101114)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596802679509.png)]

运行一下:

scrapy crawl baidu_spider --nolog

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xk51DlbP-1596811101116)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596802700961.png)]

成功输出结果,说明我们的爬虫文件的item成功传入了管道文件!

3.管道文件的多个类

问题:一个管道文件有多个管道类,如何能让item在不同类中传递呢?

扫描二维码关注公众号,回复: 13170861 查看本文章

添加一个管道类,修改管道文件。每个管道类中return item的意思是将处理过的item传给下一个管道类,如果不写return,那么下一个管道文件会处理空值。

from itemadapter import ItemAdapter


class GubaScrapyPipeline:
    def process_item(self, item, spider):
        print('我进入了管道类GubaScrapyPipeline')
        return item

class GubaScrapyPipeline11111:
    def process_item(self, item, spider):
        print('我进入了管道类GubaScrapyPipeline111')
        return item

修改配置文件,每个类后边的数字代表优先级,越小越先执行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ur63EHa3-1596811101116)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596803091650.png)]

运行一下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n3NRSUyZ-1596811101119)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596803135272.png)]

4.多个爬虫文件如何使用管道文件

问题:我们scrapy项目中一般会有多个爬虫项目,但是一般管道文件只有一个,那么当不同爬虫文件的item进入管道中,那么我们如何处理呢?

方法一:

假设我们有两个爬虫文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gmdCRSj9-1596811101120)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596803409924.png)]

为了区分管道item,我们在各自的爬虫里加入一个特殊的字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QY14yOaq-1596811101122)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596803494482.png)]

管道文件修改为

from itemadapter import ItemAdapter


class GubaScrapyPipeline:
    def process_item(self, item, spider):
        if item['from_spider']=='baidu_spider':
            print('我是处理百度爬虫的管道类')
        return item

class GubaScrapyPipeline111:
    def process_item(self, item, spider):
        if item['from_spider'] == 'tencent_spider':
            print('我是处理腾讯爬虫的管道类')
        return item

方法二:

我们管道文件也可以对每个来源的爬虫进行判断

from itemadapter import ItemAdapter


class GubaScrapyPipeline:
    def process_item(self, item, spider):
        if spider.name == 'baidu_spider':
            print('我是处理百度爬虫的管道类')
        return item


class GubaScrapyPipeline111:
    def process_item(self, item, spider):
        if spider.name == 'tencent_spider':
            print('我是处理腾讯爬虫的管道类')
        return item

5.管道中的其他方法

open_spider(self,spider)
表示当spider被开启的时候调用这个方法

close_spider(self,spider)
当spider挂去年比时候这个方法被调用

from_crawler(cls,crawler)
这个可以用于获取settings配置文件中的信息,需要注意的这个是一个类方法,用法例子如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MVCYPxUX-1596877486180)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596877225499.png)]

6.一些item pipeline的使用例子

例子1
这个例子是将item写入到json文件中

import json

class JsonWriterPipeline(object):

    def __init__(self):
        self.file = open('items.jl', 'wb')

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item</pre>

例子2
将item写入到MongoDB,同时这里演示了from_crawler的用法

import pymongo

class MongoPipeline(object):

    collection_name = 'scrapy_items'

    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
        )

    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]

    def close_spider(self, spider):
        self.client.close()

    def process_item(self, item, spider):
        self.db[self.collection_name].insert(dict(item))
        return item</pre>

例子3:去重
一个用于去重的过滤器,丢弃那些已经被处理过的item,假设item有一个唯一的id,但是我们spider返回的多个item中包含了相同的id,去重方法如下:这里初始化了一个集合,每次判断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</pre>

7.注意事项

  • 使用管道,必须要在settings.py文件中进行配置
  • 配置文件中的管道配置时候的数字代表优先级,越小越先执行
  • 管道类中的item传递必须通过return
  • 管道类中的process_item(self, item, spider)才可以接收传过来的item,其他方法不可以
  • 管道的作用一般就是处理接收过来的item,或者将接收的item存入数据库
  • spider将值传入管道文件通过return,但是return的时候不可以retrun列表,一般就是字典

二、下载中间件middleware

1.常用的下载中间件方法

 class RenrenDownloaderMiddleware:
     def process_request(self, request, spider):
         # 当每个request请求通过下载中间件时候调用的,可以不返回值,比如我们就单单的使用随机useragent和proxy时候
         return None

     def process_response(self, request, response, spider):
          # 当我们下载器从网页上下载完http请求,调用的方法,必须要返回一个响应传给spider
          return response
        
     def process_exception(self, request, exception, spider):
          #处理在使用下载器中间时候遇到的异常
          pass

2.使用下载中间件写一个随机user-agent

问题:有时候我们爬取一个网站爬取太频繁,可能网站会通过判断user-agent判断是不是一个爬虫,我们因此可以通过随机user-agent来避免这种情况

1.在setting.py 加入我们的user-agent列表

USER_AGENT_LIST = [
            'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1',
            'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0',
            'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
            'Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50',
            'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)',
            'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)'
        ]

2.在下载中间件middlewares.py文件中随机选择一个user-agent

import random

class RandomUserAgentMiddleware:
	def process_request(self, request, spider):
		ua=random.choice(self.settings.USER_AGENT_LIST)
        request.headers["User-Agent"]=ua

3.在settings中启用下载中间件

DOWNLOADER_MIDDLEWARES = {
    
    
   'renren.middlewares.RandomUserAgentMiddleware': 543,
}

4.在spider.py中输出看一下
在这里插入图片描述

结果:
在这里插入图片描述

常见的user-agent

1) Chrome
Win7:
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1
 
2) Firefox
Win7:
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0
 
3) Safari
Win7:
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50
 
4) Opera
Win7:
Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50
 
5) IE
Win7+ie9:
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)
 
Win7+ie8:
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3)
 
WinXP+ie8:
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.0)
 
WinXP+ie7:
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
 
WinXP+ie6:
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
 
6) 傲游
傲游3.1.7在Win7+ie9,高速模式:
Mozilla/5.0 (Windows; U; Windows NT 6.1; ) AppleWebKit/534.12 (KHTML, like Gecko) Maxthon/3.0 Safari/534.12
 
傲游3.1.7在Win7+ie9,IE内核兼容模式:
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E)
 
7) 搜狗
搜狗3.0在Win7+ie9,IE内核兼容模式:
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)
 
搜狗3.0在Win7+ie9,高速模式:
Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.33 Safari/534.3 SE 2.X MetaSr 1.0
 
8) 360
360浏览器3.0在Win7+ie9:
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E)
 
9) QQ浏览器
QQ浏览器6.9(11079)在Win7+ie9,极速模式:
Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1 QQBrowser/6.9.11079.201
 
QQ浏览器6.9(11079)在Win7+ie9,IE内核兼容模式:
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E) QQBrowser/6.9.11079.201
 
10) 阿云浏览器
阿云浏览器1.3.0.1724 Beta(编译日期2011-12-05)在Win7+ie9:
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)

3.使用下载中间件写代理IP

步骤:

  • 首先准备一些代理IP
  • 一般我们对代理IP会有一个验证的过程,假设有一个代理IP的列表,定义一个函数,如果代理ip可以通过则没事,当代理IP不通过删除该代理IP,然后再进行正常的爬虫
  • 然后写下载中间件,此处知识假设,真实不可能只有一个代理IP,一般是从代理ip列表随机选择
  • 配置文件中激活下载中间件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OWIrfRD4-1596900041972)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596899619275.png)]

猜你喜欢

转载自blog.csdn.net/qq_40558166/article/details/107871911
今日推荐