爬虫框架Scrapy(13)保存数据到数据库

保存数据到数据库

在之前的章节中,曾讨论过将爬取到的数据导出到文件的相关话题,但在某些时候,我们希望将爬取到的数据存储到数据库中,这一章来学习使用 Item Pipeline 实现 Scrapy 爬虫和几种常用数据库的接口。

下面我们继续以爬取网站 [http://books.toscrape.com] 中的书籍信息为例,其中每一本书的信息包括:书名、价格、评价等级、产品编码、是否有货以及图片地址。

现在我们在第七节中所创建的项目基础上进一步完善,学习如何在爬取数据的过程中将书籍信息存储到各种数据库,这些数据库主要有:MySQL、MongoDB、Redis。

(一)数据保存至 MySQL 数据库

MySQL是一个应用极其广泛的关系型数据库,它是开源免费的,可以支持大型数据库,在个人用户和中小企业中成为技术首选。

1. 安装 pymysql

在 Python 中可以使用第三方库 pymysql 访问 MySQL 数据库,使用 pip 安装 pymysql:

$ sudo pip install pymysql
2. 创建数据库与表

使用客户端登录MySQL,创建一个供 Scrapy 使用的数据库,取名为 scrapy_db:

$ mysql -uroot -pqwe123
... 
mysql> CREATE DATABASE scrapy_db CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
Query OK, 1 row affected (0.00 sec)
mysql> USE scrapy_db;
Database changed

接下来,创建存储书籍数据的表:

mysql> create table books(
    -> name VARCHAR(256) NOT NULL,
    -> price VARCHAR(20) NOT NULL,
    -> rate INT,
    -> availability VARCHAR(10),
    -> img_url VARCHAR(256)
    -> );
Query OK, 0 rows affected (0.01 sec)
3. 实现 MySQLPipeline

在项目文件夹下的 pipelines.py 中实现 MySQLPipeline,代码如下:

import pymysql

class MySQLPipeline():
    def open_spider(self, spider):
        host = spider.settings.get('MYSQL_HOST')
        port = spider.settings.get('MYSQL_PORT')
        database = spider.settings.get('MYSQL_DATABASE')
        user = spider.settings.get('MYSQL_USER')
        password = spider.settings.get('MYSQL_PASSWORD')
        self.db_connect = pymysql.connect(host=host, port=port, database=database, user=user, password=password, charset='utf8')
        self.cursor = self.db_connect.cursor()

    def close_spider(self, spider):
        self.db_connect.commit()
        self.db_connect.close()

    def process_item(self, item, spider):
        self.insert_db(item)
        return item

    def insert_db(self, item):
        values = (
            # item['upc'],
            item['name'],
            item['price'],
            item['rate'],
            item['availability'],
            item['img_url'],
        )
        sql = 'INSERT INTO books VALUES (%s,%s,%s,%s,%s)'
        self.cursor.execute(sql, values)
        print("数据保存成功!")

在配置文件 settings.py 中指定我们所要使用的 MySQL 数据库,并启用 MySQLPipeline:

ITEM_PIPELINES = {
   
   ...
   'scrapy_books.pipelines.MySQLPipeline': 600,
   ...
}
...

# MySQL数据库相关配置
MYSQL_HOST = '127.0.0.1'
MYSQL_DATABASE = 'scrapy_db'
MYSQL_PORT = 3306
MYSQL_USER = 'kevin'
MYSQL_PASSWORD = '20210401'

然后执行爬虫,程序运行结束后,我们就可以在数据库中看到保存的数据:
在这里插入图片描述

结果表明,我们成功地将1000条数据存储到了 MySQL 数据库。

上述代码中,同样是先执行全部的插入语句(INSERT INTO),最后一次性调用 commit 方法提交给数据库。或许在某些情况下,我们的确需要每执行一条插入语句,就立即调用 commit 方法更新数据库,如爬取过程很长,中途可能被迫中断,这样程序就不能执行到最后的 commit 。如果在上述代码的 insert_db 方法中直接添加 self.db_conn.commit() ,又会使程序执行慢得让人无法忍受。为解决以上难题,下面讲解另一种实现方法。

Scrapy 框架自身是使用另一个 Python 框架 Twisted 编写的程序,Twisted 是一个事件驱动型的异步网络框架,鼓励用户编写异步代码,Twisted 中提供了以异步方式多线程访问数据库的模块 adbapi,使用该模块可以显著提高程序访问数据库的效率。下面我们就以这个模块改写 MySQLPipeline

class MySQLAsyncPipeline():
    def open_spider(self, spider):
        host = spider.settings.get('MYSQL_HOST')
        port = spider.settings.get('MYSQL_PORT')
        database = spider.settings.get('MYSQL_DATABASE')
        user = spider.settings.get('MYSQL_USER')
        password = spider.settings.get('MYSQL_PASSWORD')
        self.dbpool = adbapi.ConnectionPool('pymysql', host=host, port=port,db=database, user=user, password=password, charset='utf8')

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

    def process_item(self, item, spider):
        self.dbpool.runInteraction(self.insert_db, item)
        return item

    def insert_db(self, tx, item):
        values 
  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值