我们在爬取数据的时候难免涉及到将数据保存到MySQL数据库中,一般将数据保存到MySQL中有两种方式,同步和异步。
同步模式
同步模式是采用SQL语句,将数据插入到数据库中。但是要注意的是Scrapy的解析速度要远大于MySQL的入库速度,当有大量解析的时候,MySQL的入库就可能会阻塞。
代码部分:(代码为慕课网异步爬虫实战内容)
import MySQLdb
class MysqlPipeline(object):
def __init__(self):
self.conn = MySQLdb.connect('127.0.0.1','root','root','article_spider',charset="utf8",use_unicode=True)
self.cursor = self.conn.cursor()
def process_item(self, item, spider):
insert_sql = """
insert into jobbole_article(title,create_date,url,url_object_id) VALUES (%s,%s,%s,%s)
"""
self.cursor.execute(insert_sql,(item["title"],item["create_date"],item["url"],item["url_object_id"]))
self.conn.commit()
异步模式
采用同步模式可能会产生阻塞,我们可以使用Twisted将MySQL的入库和解析变成异步操作,而不是简单的execute,commit同步操作。
关于MySQL的配置,我们可以直接在配置文件配置数据库:
MYSQL_HOST = "127.0.0.1"
MYSQL_DBNAME = "article_spider"
MYSQL_USER = "root"
MYSQL_PASSWORD = "root"
在settings中的配置,我们通过在pipeline中定义from_settings获取settings对象,可以直接获取settings配置文件中的值。
使用Twisted提供的异步容器连接MySQL:
import MySQLdb
import MySQLdb.cursors
from twisted.enterprise import adbapi
使用adbapi可以使mysqldb的一些操作变成异步化的操作
使用cursors进行sql语句的执行和提交
代码部分:
class MysqlTwistedPipline(object):
def __init__(self,dbpool):
self.dbpool = dbpool
@classmethod
def from_settings(cls,settings):
dbparms = dict(
host = settings["MYSQL_HOST"],
db = settings["MYSQL_DBNAME"],
user = settings["MYSQL_USER"],
passwd = settings["MYSQL_PASSWORD"],
charset = 'utf8',
cursorclass = MySQLdb.cursors.DictCursor,
use_unicode=True,
)
dbpool = adbapi.ConnectionPool("MySQLdb",**dbparms)
return cls(dbpool)
def process_item(self, item, spider):
#使用Twisted将mysql插入变成异步执行
#runInteraction可以将传入的函数变成异步的
query = self.dbpool.runInteraction(self.do_insert,item)
#处理异常
query.addErrback(self.handle_error,item,spider)
def handle_error(self,failure,item,spider):
#处理异步插入的异常
print(failure)
def do_insert(self,cursor,item):
#会从dbpool取出cursor
#执行具体的插入
insert_sql = """
insert into jobbole_article(title,create_date,url,url_object_id) VALUES (%s,%s,%s,%s)
"""
cursor.execute(insert_sql, (item["title"], item["create_date"], item["url"], item["url_object_id"]))
#拿传进的cursor进行执行,并且自动完成commit操作
以上代码部分,除了do_insert之外,其它均可复用。
关于将数据保存到MySQL数据库,除了使用原生SQL语句外,还可以使用django的ORM机制。关于这个,以后有时间研究研究,有兴趣的可以点击连接:https://github.com/scrapy-plugins/scrapy-djangoitem