第十五章 Scrapy框架的使用之工作原理及简单入门

架构图

scrapy架构图

组成部分

  • ENGINE:引擎(用于处理整个系统的数据流和事件,核心),主要负责数据流转和逻辑处理
  • SPIDERS:蜘蛛(对应多个spider,每个spider定义了站点的爬取逻辑和页面解析规则),主要负责解析响应并生成Item和新的请求给引擎处理
  • Scheduler:调度器(接受引擎发过来的Request(url)并将其加入队列,或将Request发回给引擎),主要负责维护Request的调度逻辑
  • Downloader:下载器(接收引擎的请求并向服务器发送请求,拿到响应后发送给引擎)
  • ITEM PIPELINES:项目管道(处理Item,数据清洗、验证和储存等)
  • ITEM:爬取结果的数据结构
  • Downloader Middlewares:下载器中间件,位于引擎和下载器之间的Hook框架,主要负责引擎和下载器之间的请求和响应的处理过程。
  • Spider Middlewares:蜘蛛中间件(引擎和蜘蛛之间的Hook框架,负责item、请求响应的处理)

数据流
①启动爬虫时,engine根据需要爬取的站点找对对应的spider,spider会生成一个或多个需要爬取页面对应的request,然后发给engine。
②engine将对应的request交给scheduler等待调度。
③engine向scheduler索要下一个要处理的request,scheduler根据调度逻辑将合适的request交给engine。
④engine将scheduler发来的request转发给downloader进行下载执行,这个过程会由定义好的下载中间件处理。
⑤下载器将Request发送给目标服务器的到对应的response后返回给engine,这个过程也会经由定义好的下载器中间件处理。
⑥Engine将下载器返回的response交给spider处理,这个过程中会经由定义好的蜘蛛中间件处理。
⑦spider处理response并解析相应内容,产生一个或多个的爬取结果Item或后续要爬取的目标页面对应的一个或多个Request,将Item或Request发送给engine处理,这个过程中会经由定义好的蜘蛛中间件处理。
⑧engine将spider发回的一个或多个Item转发给Item pipelines进行数据处理或储存一系列的操作,将spider发回的Request转发给scheduler等待调度。


基本命令

  • 创建scrapy项目
scrapy startproject news
  • 创建spider
scrapy genspider baidu www.baidu.com
  • 使用Feed Exports抓取结果输出
# 直接运行,打印到控制台
scrapy crawl quotes
# 运行并将结果保存为json格式文件
scrapy crawl quotes -o quotes.json
# 运行并将结果保存为jsonline格式文件
scrapy crawl quotes -o quotes.j1
scrapy crawl quotes -o quotes.jsonlines
# 运行并将结果保存为csv格式文件
scrapy crawl quotes -o quotes.csv
# 运行并用ftp远程输出
scrapy crawl quotes -o ftp://user:[email protected]/path/to/quotes.csv

  • spider.py文件初始结构
import scrapy

class QuotesSpider(scrapy.Spider):
# 每个项目唯一的名字,区分不同的spider
    name = 'quotes'
# 允许爬取的域名
    allowed_domains = ['quotes.toscrape.com']
# spider在启动时爬取的URL列表
    start_urls = ['http://quotes.toscrape.com/']
# 负责处理返回的响应,提取数据或进一步生成要处理的请求
    def parse(self, response):
        pass
  • quote.py
import scrapy

from scrapy_tutorial_demo.items import ScrapyTutorialDemoItem

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response):
        # 将返回的response用css选择器解析,先拿到class为quote的数据
        quotes = response.css('.quote')
        for quote in quotes:
            item = ScrapyTutorialDemoItem()
            # class为text的文本的第一个元素
            item['text'] = quote.css('.text::text').extract_first()
            # class为author的文本的第一个元素
            item['author'] = quote.css('.author::text').extract_first()
            # class为tags下的class为tags下的文本元素列表
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item

        # 下一页的后缀:/page/2/  attr():提取节点属性,括号内填要提取的属性名
        next = response.css('.pager .next a::attr(href)').extract_first()
        # urljoin():将相对URL构造成一个绝对URL
        url = response.urljoin(next)
        # 返回一个新构造的Request请求,其中回调方法是parse
        yield scrapy.Request(url=url, callback=self.parse)
  • item.py
import scrapy

class ScrapyTutorialDemoItem(scrapy.Item):
    text = scrapy.Field()
    author = scrapy.Field()
    tags = scrapy.Field()
  • 使用pipelines
import pymongo
from scrapy.exceptions import DropItem


class TextPipeline(object):
    def __init__(self):
        self.limit = 50

    def process_item(self, item, spider):
        # 判断item的text属性是否存在,不存在则抛出DropItem异常
        if item['text']:
            # 判断长度是否大于50
            if len(item['text']) > self.limit:
                # 截取并拼接...
                item['text'] = item['text'][0:self.limit].rstrip() + '...'
            return item
        else:
            return DropItem('Missing Text')


class MongoDBPipeline(object):
    def __init__(self, connection_string, database):
        self.connection_string = connection_string
        self.database = database

    # 类方法,以依赖注入的方式实现方法通过参数crawler可以拿到全局配置settings.py的每一个配置信息
    # 主要用来获取settings.py中的配置
    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            connection_string=crawler.settings.get('MONGODB_CONNECTION_STRING'),
            database=crawler.settings.get('MONGODB_DATABASE')
        )

    # 当spider被开启时,这个方法被调用,主要进行一些初始化操作。
    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.connection_string)
        self.db = self.client[self.database]

    # 数据插入操作,调用insert()方法传入item对象即可将数据存储到MongoDB
    def process_item(self, item, spider):
        name = item.__class__.__name__
        self.db[name].insert_one(dict(item))
        return item

    # 当spider被关闭时,这个方法被调用,将数据库连接关闭
    def close_spider(self, spider):
        self.client.close()
  • settings
# 声明字典,数字越小越先被调用
ITEM_PIPELINES = {
    'scrapy_tutorial_demo.pipelines.TextPipeline': 300,
    'scrapy_tutorial_demo.pipelines.MongoDBPipeline': 400
}
# 声明MongoDB连接字符串
MONGODB_CONNECTION_STRING = 'localhost'
# 声明MongoDB存储的数据库名称
MONGODB_DATABASE = 'scrapytutorial'

你可能感兴趣的:(第十五章 Scrapy框架的使用之工作原理及简单入门)