爬虫进阶之初探scrapy

文章目录

scrapy介绍

scrapy是一个基于Twisted异步处理框架,它是纯Python实现的爬虫框架,其架构清晰, 模块之
间的耦合程度低,可扩展性极强,可以灵活完成各种需求。同时scrapy也是每位Python爬虫师的必备框架,
它可以帮助我们以少量的代码完成一个高并发,高扩展的爬虫程序。

scrapy的组成部分

组件 功能 是否需要手写实现
Engine(引擎) 总指挥(调度另外四个模块)负责数据和信号在不同模块间传递
Schedule(调度器) 它是一个队列(默认为后入先出顺序),
将Request对象入队列和出队列
Spiders(爬虫) 处理引擎发来的response
1.提取需要数据;2.提取需要的url
Downloader(下载器) 下载引擎发来的request请求
Item Pipeline (管道) 处理从引擎传来的数据:
1.查重验证 2.清洗数据3.存入数据库
Downloader Middlewares (下载中间件) 1.在request进入下载器前,对其进行处理,如添加headers、代理等
2.在response进入Spiders前,对response进行处理
Spider Middlewares (爬虫中间件) 可以自定义requests请求和进行response过滤 一般不用

scrapy流程图介绍

爬虫进阶之初探scrapy
scrapy 中的数据流由引擎控制,数据流的过程如下:
该数据流希望每位爬虫开发者牢记于心

流程顺序 详细解释
1.Spider -> Engine -> Scheduler Engine从Spider中获取到第一个要爬取的URL,
并通过Scheduler以Request 的形式调度
2.Scheduler -> Engine Engine向Scheduler 请求下一个要爬取的Request
3.Engine -> Downloader Middlewares -> Downloader Scheduler返回Request给Engine
Engine将Request通过Downloader Middlewares 转发给Downloader下载
4.Downloader -> Downloader Middlewares -> Engine Downloader 对给定的Request生成该页面的Response
并将其通过Downloader Middle wares 发送给Engine
5.Engine -> Spider Middlewares -> Spiders Engine 接收到Response后 ,将其通过Spider Middlewares发送给Spider 处理
6.Spiders -> Spider Middlewares -> Engine Spider 处理Response ,并通过Spider Middlewares
返回爬取到的Item和新的Request 给Engine
7.Engine -> Item Pipeline, Engine -> Scheduler Engine分两个方向,一是将item传向管道;二是将新的Request传给Scheduler
8.循环2-7步骤 一直到Scheduler 中没有更多的Request , Engine 关闭该网站,爬取结束。

scrapy 文件介绍

  • spider.py
    用户主要写的逻辑、代码都在该文件中
import scrapy


class HttpbinSpider(scrapy.Spider):
    name = 'httpbin'  # 该爬虫名称
    allowed_domains = ['httpbin.com']  # 爬虫允许的域名(不在此范围的链接不会被爬取)
    start_urls = ['http://httpbin.com/']  # 爬虫入口地址

    def parse(self, response):
		"""
        用于解析start_urls列表中url的响应
        :param response: 在本例中,得到是'http://httpbin.com/'的响应
        :return: 1.返回的是字典或Item对象,则会进入Item Pipeline
        		 2.返回的是Reqeust对象, 则会进入到Scheduler
        # 注: 该方法一般是一个yield迭代器,用于不断生成Item对象或是Request对象
        """
        pass
  • items.py
    该文件主要定义用户想要获取的字段,
    该文件下定义的字段名称可以与spider下的字段名称互相检查,可有效防止用户字段名称的误写
import scrapy


class TestItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    pass
  • pipelines.py
    用户可定义多个pipelines,scrapy会根据定义的优先级顺序执行每个pipeline
class TestPipeline(object):
    def open_spider(self, spider):
        """
        用于当前spider启动时做一些初始化工作, 如:数据库的连接等
        :param spider: 当前spider
        :return: None
        """
        pass
     
     @classmethod
    def from_crawler(cls, crawler):
        """
        该方法是类方法,通过crawler, 可以拿到Scrapy的所有核心组件,如全局配置的每个信息,然后创
        建一个Pipeline 实例
        :param crawler: 
        :return: cls()实例对象
        """
        pass
        
    def process_item(self, item, spider):
        """
        每个抓取到的Item对象会被该方法调用
        :param item: 待处理的Item对象
        :param spider:  该Item对应的spider
        :return Item 对象:那么此Item会被低优先级的Item Pipeline的process_item方法处理,直到所有的方法被调用完毕
         or return Drop Item 异常: 那么此Item会被丢弃,不再进行处理。
        """
        return item
  • middlewares.py
    与pipelines类似,用户可定义多个Middleware,scrapy会根据定义的优先级顺序执行每个Middleware
    由于下载中间件的使用频率远高于爬虫中间件,所以先介绍下载中间件。
from scrapy import signals


class TestDownloaderMiddleware(object):  
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the downloader middleware does not modify the
    # passed objects.
	'英文大意: 并不是所有方法都需要实现,如果方法未定义,scrapy则不会修改传递来的对象'
    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request, spider):
		"""
        每个进入downloader前的request会被该方法调用
        :param request: 需要处理的Request对象
        :param spider: 该request对应的spider
        
        # Must either:  必须返回以下其中一种
        # - return None: 仅仅处理request,如头部信息
        # - or return a Response object: 产生新的响应(低优先级的process_request停止调用)进入到process_response方法
        # - or return a Request object: 产生新的请求进入调度器(同理低优先级的process_request停止调用)
        #                              然后重新顺序执行每个DownloaderMiddleware的process_request方法
        # - or raise IgnoreRequest: 所有的 Downloader Middleware 的process_exception方法会依次执行。
        """
        return None

    def process_response(self, request, response, spider):
        # Called with the response returned from the downloader.
		"""
        从Downloader中得到的Response在进入Spider前该方法调用 
        :param request: 该response对应的Request对象
        :param response: 被处理的Response对象
        :param spider: 该response对应的spider
       
        # Must either;
        # - return a Response object: Response会顺序通过每个DownloaderMiddleware的process_response,最后进入到Spider中
        # - return a Request object: Request会重新放到调度队列里等待被调度,随后会被process_request方法依次处理。
        # - or raise IgnoreRequest:  Request的errorback方法会回调。如果该异常还没有被处理,那么它便会被忽略。
         """
        return response

    def process_exception(self, request, exception, spider):
        # Called when a download handler or a process_request()
        # (from other downloader middleware) raises an exception.
		"""
        当Downloader或process_request方法抛出异常时,例如抛出Ignore Request 异常,该方法就会被调用
        :param request: 产生异常对象的Request
        :param exception: 抛出的Exception对象
        :param spider: 产生异常的spider
        """
        # Must either:
        # - return None: continue processing this exception
        # - return a Response object: stops process_exception() chain
        # - return a Request object: stops process_exception() chain
        pass

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)

  • settings.py
    该文件存放scrapy的所有配置信息,下面我介绍一些经常用到的配置,以后待补充。
# 项目名称
BOT_NAME = 'httpbintest'

# scrapy将会在以下路径模块中寻找爬虫
SPIDER_MODULES = ['httpbintest.spiders']
# 使用genspider命令创建的爬虫模块
NEWSPIDER_MODULE = 'httpbintest.spiders'

# 设置爬虫初始化时USER_AGENT(注:如要随机更换则需要在下载中间件中设置)
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36"

# 不遵循robots.txt(默认为True,一般要置为False)
ROBOTSTXT_OBEY = False

# 设置日志输出文件路径(设置后将不再控制台输出)
# LOG_FILE = 'spider.log'
# 日志等级从低到高分为 1.DEBUG 2.INFO 3.WARNING 4.ERROR 5.CRITICAL
# 等级越高,输出的日志将越少(默认DEBUG)
# LOG_LEVEL = 'ERROR'

# 设置scrapy最大并发请求数目(默认16)
# CONCURRENT_REQUESTS = 32

# 对同一网站下的连续请求设置时间间隔(默认为0,但在大于0的情况下scrapy设置的不会是固定时间,
# 而是在0.5 * DOWNLOAD_DELAY 和 1.5 * DOWNLOAD_DELAY之间)
# DOWNLOAD_DELAY = 3
# 以下请求延迟设置只会生效其中之一:
# CONCURRENT_REQUESTS_PER_DOMAIN = 16  # 对同一域名下的请求并发数
# CONCURRENT_REQUESTS_PER_IP = 16  # 对同一ip的请求并发数

# 设置下载的页面超时时间,超出后将会抛出异常(默认180, 建议设置10秒以内)
DOWNLOAD_TIMEOUT = 8

# 设置爬取深度(默认为0,不限制深度,一般根据情况设定,可以有效防止爬虫进入死循环)
# DEPTH_LIMIT = 3
# 设置为广度优先抓取(默认为深度优先)
# DEPTH_PRIORITY = 1

# 禁用COOKIES(默认生效)
# COOKIES_ENABLED = False

# 禁用远程控制(默认生效)
# TELNETCONSOLE_ENABLED = False

# 重写默认的请求头
# DEFAULT_REQUEST_HEADERS = {
#   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
#   'Accept-Language': 'en',
# }

# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html
# 启用自定义的SpiderMiddleware,数值越小越接近Engine
SPIDER_MIDDLEWARES = {
	'httpbintest.middlewares.HttpbintestSpiderMiddleware': 543,
}

# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
# 启用自定义的DOWNLOADER_MIDDLEWARES, 数字越小越接近Engine,越大越靠近Downloader
# 根据scrapy数据流可以知道request依次经过数值从小到大的DOWNLOADER_MIDDLEWARE,
# 而response则会依次经过数值从大到小的DOWNLOADER_MIDDLEWARE
DOWNLOADER_MIDDLEWARES = {
   'httpbintest.middlewares.ProxyMiddleware': 543,
}

# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
# 启用管道(数字越小越先处理)
ITEM_PIPELINES = {
	'httpbintest.pipelines.HttpbintestPipeline': 300,
}

结语本篇是我的原创博客,其中花费了不少的心思。当然也借鉴了一些优秀书籍内容,希望能够帮助到正在学习scrapy框架的你们,其中也会有很多不足之处,欢迎指正。

上一篇:Scrapy框架


下一篇:Python爬虫工程师必学——App数据抓取实战