1.同步爬取存储数据:
pipeline用于专门处理要抓取的域。
scrapy可以通过pipeline模块来保存数据。在pipeline.py中已经默认创建了一个pipeline类,创建一个新的pipeline类用于处理数据,并将数据保存到MySQL。
pipeline 类会在 process_item 方法中处理数据,然后在结束时调用 close_spider 方法,因此我们
需要自定义这两个方法做相应的处理。
注意:
- 在 process_item() 方法处理完成后要返回 item 供后面的 Pipeline 类继续操作
- 在__init__()方法中做一些实例化时需要的操作
- 记得在 close_spider() 中释放资源
class MysqlPipeline(object): """ 自定义将数据写入数据库 """ def __init__(self): self.conn = MySQLdb.connect(host="127.0.0.1", user="root", password="123456", db="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, url, create_date, fav_nums) values (%s, %s, %s, %s)""" # 使用`占位符 self.cursor.execute(insert_sql, (item["title"], item["url"], item["create_date"], item["fav_nums"])) # 用commit()才会提交到数据库 self.conn.commit() def close_spider(self, spider): self.cursor.close() self.conn.close()
之后需要在setting.py文件中进行配置文件
ITEM_PIPELINES = {
'ArticelSpider.pipelines.MysqlPipeline': 1,}
2.异步爬取存储数据:
上面的 Pipeline 类虽然可以将数据写在 MySQL 数据中,但是在 Scrapy 对数据的处理是同步执行的,当爬取数据量很大的时候,会出现插入数据的速度跟不上网页的爬取解析速度,造成阻塞,为了解决这个问题需要将 MySQL 的数据存储异步化。Python 中提供了 Twisted 框架来实现异步操作,该框架提供了一个连接池,通过连接池可以实现数据插入 MySQL 的异步化。
下面是集合 Twisted 框架实现的 Pipeline 类,可以完成 MySQL 的异步化操作:
这里使用的是 MySQLdb 模块,在初始化 Pipeline 的时候,通过参数创建数据库连接池 dbpool,
然后在 process_item 方法中来对连接池进行配置,执行其执行方法和数据。这里我们没有写出上面例子中出现的 SQL 语句,而是将其封装到了具体的 Item类中,这样我们的 Pipeline 类可以处理各种不同的数据。
另外在配置文件中进行了如下配置:
MYSQL_HOST = "127.0.0.1" MYSQL_DBNAME = "article_spider" # 数据库名称 非表名称 表名称会在sql语句中指明 MYSQL_USER = "root" MYSQL_PASSWORD = "123456"这样在调用时则需要
@classmethod def from_settings(cls, settings):
host = settings["MYSQL_HOST"]即可取出 上面是固定的写法。当然也可以直接进行卸载函数内部,此处不再放码 参见链接,不过以上更方便管理。
class MysqlTwistedPipeline(object): # 采用异步机制写入MySQL def __init__(self, dppool): self.dppool = dppool # 用固定方法 【写法固定】 获取配置文件内信息 @classmethod def from_settings(cls, settings): # cls实际就是本类 MysqlTwistedPipeline dpparms = dict( host = settings["MYSQL_HOST"], db = settings["MYSQL_DBNAME"], user = settings["MYSQL_USER"], passwd = settings["MYSQL_PASSWORD"], charset = "utf8", cursorclass = MySQLdb.cursors.DictCursor, # 指定 curosr 类型 需要导入MySQLdb.cursors use_unicode = True ) # 由于要传递参数 所以参数名成要与connnect保持一致 # 用的仍是MySQLdb的库 twisted并不提供 # 异步操作 # adbapi # 可以将MySQLdb的一些操作变成异步化操作 dppool = adbapi.ConnectionPool("MySQLdb", **dpparms) # 告诉它使用的是哪个数据库模块 连接参数 # 另外 以上dpparms的参数也可单独写,这样会造成参数列表过大 return cls(dppool) # 即实例化一个pipeline def process_item(self, item, spider): # 使用twisted将mysql插入编程异步操作 # 指定操作方法和操作的数据 [下面会将方法异步处理] query = self.dppool.runInteraction(self.do_insert, item) # AttributeError: 'Deferred' object has no attribute 'addErrorback' # query.addErrorback(self.handle_error) # 处理异常 query.addErrback(self.handle_error) # 处理异常 def handle_error(self, failure, item, spider): # 定义错误 处理异步插入的异常 print(failure) def do_insert(self, cursor, item): """ 此类内其他都可以看作是通用 针对不同的sql操作只需要改写这里即可了 :param cursor: :param item: :return: """ insert_sql = """insert into jobbole_article(title, url, create_date, fav_nums) values (%s, %s, %s, %s)""" # 使用`占位符 cursor.execute(insert_sql, (item["title"], item["url"], item["create_date"], item["fav_nums"]))
do_insert
do_insert方法指定要操作的数据语句,其他不用过多修改,只需在此处编写语句 就可以异步执行操作。
本文章的编写部分 参考:Scrapy 入门笔记(4) --- 使用 Pipeline 保存数据