今天来总结一下Scrapy框架的用法。scrapy的架构如下:

  

scrapy写入mysql速度很慢 scrapy schedule_数据库

Engine 

Items

Scheduler 

Downloader

Spiders

ItemPipeline  :项目管道,负责处理由 Spiders 从网页中提取的项目,它的主要任务是清洗、验证和存储数据。

Downloader Middlewares

Spide Middlewares

接下来介绍 个简单的项目,完成一遍 Scrapy抓取流程

1、打开 cmd 终端窗口, 输入 scrapy startproject abcd,生成一个 abcd 的项目

2、按照提示,输入 cd abcd 进入 abcd 项目所在的文件夹, 输入 scrapy genspider quotes quotes.toscrape.com,

  quotes是 spiders 的 .py 文件,quotes.toscrape.com 是爬取的网站域名。

   

scrapy写入mysql速度很慢 scrapy schedule_ide_02

 

打开项目文件 quotes,里面包含内容如下:

scrapy写入mysql速度很慢 scrapy schedule_scrapy写入mysql速度很慢_03

allowed domains :它是允许爬取的域名,如果初始或后续的请求链接不是这个域名下的,则请求链接会被过滤掉

start_urls :它包含了 Spider 在启动时爬取的 url 列表,初始请求是由它来定义的

 

3、观察目标网站,我们可以获取到到内容有 text 、author、 tags,因此开始定义 Items.py



class AbcdItem(scrapy.Item):
    # define the fields for your item here like:
    text = scrapy.Field()
    author = scrapy.Field()
    tags = scrapy.Field()



4、进入quotes.py文件,在 parse函数下输入 print(response.text), 在终端输入 scrapy crawl quotes,看看能否正常请求到内容

结果报错:UnicodeEncodeError: 'gbk' codec can't encode character '❤' in position 11162: illegal multibyte sequence

是说编码错误,经过查资料,进行修改就改好了,



import io  
import sys 
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gbk')



说是因为编码问题,但我还不太理解原因,暂且这么用

5、接下来进行quotes.py代码编写



def parse(self, response):
        quotes = response.css('.quote')
        for quote in quotes:
            item = AbcdItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item



终端运行,得到正确的输出

6、抓取下一页的内容



def parse(self, response):
        quotes = response.css('.quote')  # response 直接就是返回的内容
        for quote in quotes:
            item = QuoteItem()
            text = quote.css('.text::text').extract_first()
            author = quote.css('.author::text').extract_first()
            tags = quote.css('.tags .tag::text').extract()
            item['text'] = text
            item['author'] = author
            item['tags'] = tags
            yield item
        next = response.css('.pager .next a::attr(href)').extract_first()
        url = response.urljoin(next)  # 获取一个绝对的URL
        yield scrapy.Request(url=url, callback=self.parse)



url = response.urljoin(next),获取一个绝对的 URL,next='page/2/',url='http://quotes.toscrape.com/page/2/yield scrapy.Request(url=url, callback=self.parse),重新调用 parse()函数,一直循环下去,运行结果正常输出所有内容。



7、将输出的内容保存下来,有一下四种方法,个人感觉保存为 json 或 jl 格式的文件看起来最清晰。
  scrapy crawl quotes -o quotes.json
  scrapy crawl quotes -o quotes.jl
  scrapy crawl quotes -o quotes.xml 
  scrapy crawl quotes -o quotes.csv



8、保存到MongoDb数据库,这个稍微复杂一点,需要用到 Pipeline.py 文件。
  先在 Pipeline.py 中写入以下代码:



import pymongo
from scrapy.exceptions import DropItem

class TextPipeline(object):
    def __init__(self):
        self.limit = 50
    def process_item(self, item, spider):
        if item['text']:
            if len(item['text']) > self.limit:    # 对长度大于50的text进行修改
                item['text'] = item['text'][0:self.limit].rstrip()+'...'
            return item
        else:
            return DropItem('Missing Text')

class MongoPipeline(object):
    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_DB')
        )

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

    def process_item(self, item, spider):
        name = item.__class__.__name__
        self.db[name].insert(dict(item))
        return item

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




定义了 TextPipeline() 和 MongoPipeline() 两个类。

TextPipeline() 和 MongoPipeline() 两个类都有 process_item 的方法,process item ()方法必须返回包含数据的字典或 Item 象,或者抛出 Dropltem 异常,

启用 Item Pipeline 后, Item Pipeline 会自动调用这个方法。

MondoPipeline() 类: from crawler(),通过 crawler 我们可以拿到全局配置的每个配置信息,这个方法的定义主要是用来获取 settings.py 中的配置

            open spider(), Spider 开启时,这个方法被调用

            close_spider(), Spider 关闭时,这个方法会调用

            process item () 方法则执行了数据插入操作

我们在 settings.py 中加入如下内容:



MONGO_URI='localhost'
MONGO_DB = 'abcd'

ITEM_PIPELINES = {
    'abcd.pipelines.TextPipeline': 300,
    'abcd.pipelines.MongoPipeline': 400
}



在终端运行 scrapy crawl quotes,数据成功在 MongoDb 中保存下来。

scrapy写入mysql速度很慢 scrapy schedule_数据库_04