关键词:
上节说到Pipeline会拦截item,根据设置的优先级,item会依次经过这些Pipeline,所以可以通过Pipeline来保存文件到json、数据库等等。
下面是自定义json
#存储item到json文件 class JsonWithEncodingPipeline(object): def __init__(self): #使用codecs模块来打开文件,可以帮我们解决很多编码问题,下面先初始化打开一个json文件 import codecs self.file = codecs.open('article.json','w',encoding='utf-8') #接着创建process_item方法执行item的具体的动作 def process_item(self, item, spider): import json #注意ensure_ascii入参设置成False,否则在存储非英文的字符会报错 lines = json.dumps(dict(item),ensure_ascii=False) + "\n" self.file.write(lines) #注意最后需要返回item,因为可能后面的Pipeline会调用它 return item #最后关闭文件 def spider_close(self,spider): self.file.close()
scrapy内置了json方法:
from scrapy.exporters import JsonItemExporter
除了JsonItemExporter,scrapy提供了多种类型的exporter
class JsonExporterPipeline(object): #调用scrapy提供的json export导出json文件 def __init__(self): #打开一个json文件 self.file = open('articleexport.json','wb') #创建一个exporter实例,入参分别是下面三个,类似前面的自定义导出json self.exporter = JsonItemExporter(self.file,encoding='utf-8',ensure_ascii=False) #开始导出 self.exporter.start_exporting() def close_spider(self,spider): #完成导出 self.exporter.finish_exporting() #关闭文件 self.file.close() #最后也需要调用process_item返回item def process_item(self, item, spider): self.exporter.export_item(item) return item
和自定义json相比,存的文件由【】
通过源码可以看到如下:
接着是如何把数据存储到mysql,我这开发环境是ubuntu,支持的mysql-client工具不多,免费的就用Mysql Workbench,也可以使用navicat(要收费)
spider要创建的一张表,和ArticleSpider项目里的item一一对应就行。
然后接下来是配置程序连接mysql
这里我使用第三方库pymysql来连接mysql,安装方式很简单,可以使用pycharm内置的包安装,也可以在虚拟环境用pip安装
然后直接在pipline里创建mysql的pipline
import pymysql class MysqlPipeline(object): def __init__(self): """ 初始化,建立mysql连接conn,并创建游标cursor """ self.conn = pymysql.connect( host='localhost', database='spider', user='root', passwd='123456', charset='utf8', use_unicode=True ) self.cursor = self.conn.cursor() def process_item(self,item,spider): #要执行的sql语句 insert_sql = """ insert into jobbole_article(title,create_date,url,url_object_id, front_image_url,front_image_path,praise_num,comment_num,fav_num,tags,content) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) """ #使用游标的execute方法执行sql self.cursor.execute(insert_sql,(item["title"],item['create_date'], item['url'],item['url_object_id'], item['front_image_url'],item['front_image_path'], item['praise_num'],item['comment_num'],item['fav_num'], item['tags'],item['content'])) #commit提交才能生效 self.conn.commit() return item
上面的这种mysql存储方式是同步的,也就是execute和commit不执行玩,是不能继续存储数据的,而且明显的scrapy爬取速度会比数据存储到mysql的速度快些,
所以scrapy提供了另外一种异步的数据存储方法(一种异步的容器,还是需要使用pymysql)
首先把mysql的配置连接信息写进setting配置文件,方便后期修改
MYSQL_HOST = "localhost" MYSQL_DBNAME = 'spider' MYSQL_USER = "root" MYSQL_PASSWORD = "123456"
接着在pipeline中导入scrapy提供的异步的接口:adbapi
from twisted.enterprise import adbapi
完整的pipeline如下:
class MysqlTwistedPipeline(object): #下面这两个函数完成了在启动spider的时候,就把dbpool传入进来了 def __init__(self,dbpool): self.dbpool = dbpool #通过下面这种方式,可以很方便的拿到setting配置信息 @classmethod def from_settings(cls,setting): dbparms = dict( host = setting['MYSQL_HOST'], db = setting['MYSQL_DBNAME'], user = setting['MYSQL_USER'], password = setting['MYSQL_PASSWORD'], charset = 'utf8', #cursorclass = pymysql.cursors.DictCursor, use_unicode = True, ) #创建连接池, dbpool = adbapi.ConnectionPool("pymysql",**dbparms) return cls(dbpool) # 使用twisted将mysql插入变成异步执行 def process_item(self, item, spider): # 指定操作方法和操作的数据 query = self.dbpool.runInteraction(self.do_insert,item) #处理可能存在的异常,hangdle_error是自定义的方法 query.addErrback(self.handle_error,item,spider) def handle_error(self,failure,item,spider): print(failure) def do_insert(self,cursor,item): #执行具体的插入 # 根据不同的item 构建不同的sql语句并插入到mysql中 insert_sql = """ insert into jobbole_article(title,create_date,url,url_object_id, front_image_url,front_image_path,praise_num,comment_num,fav_num,tags,content) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) """ # 使用游标的execute方法执行sql cursor.execute(insert_sql, (item["title"], item['create_date'], item['url'], item['url_object_id'], item['front_image_url'], item['front_image_path'], item['praise_num'], item['comment_num'], item['fav_num'], item['tags'], item['content']))
注意:导入pymysql需要单独导入cursors
import pymysql import pymysql.cursors
一般我们只需要修改do_insert方法内容就行
还有,传递给的item要和数据表的字段对应上,不能以为不传值就会自动默认为空(但是存储到json文件就是这样)
除了pymysql,还可以通过安装mysqlclient连接数据库,但安装前需要先安装别的包,否则会报错
ubuntu需要安装:
(one_project) laoni@ubuntu:~$ sudo apt-get install libmysqlclient-dev
centos下需要安装:
(one_project) laoni@ubuntu:~$ sudo yum install python-devel mysql-devel
第九篇vue(代码片段)
v-for我们可以使用v-for指令基于一个数组来渲染一个列表。v-for指令的值需要使用iteminitems形式的特殊语法,其中items是源数据的数组,而item是迭代项的别名data()returnitems:[message:\'Foo\',message:\'Bar\']<liv-for="iteminitems">item.message</... 查看详情
第九篇:进程与线程
一、paramiko模块二、ssh登录过程和上传下载三、进程和线程简绍四、多线程、多线程实例五、守护线程六、线程锁七、递归锁八、信号量九、线程间通信event十、queue消息队列十一、进程Queue数据传递十二、pipe管道通信十三、进程... 查看详情
(第九篇)iptables详解
常见的网络攻击形式1.拒绝服务攻击:DOS2.分布式拒绝服务攻击DDOS3.漏洞入侵4.口令猜测以上内容简单了解,具体可自行百度,此处不必知晓。Linux防火墙基础Linux防火墙体系主要工作在网络层,针对TCP/IP数据包实施过滤和限制,... 查看详情
第九篇:网络编程补充与进程
本篇内容udp协议套接字开启进程的方式多进程实现并发的套接字通信join方法守护进程同步锁进程队列生产者消费者模型进程池paramiko模块 一、 udp协议套接字1.TCP和UDP在传输层区别:UDP是无连接不可靠的数据报协议。TCP提... 查看详情
第九篇:sparksql源码分析之in-memorycolumnarstorage源码分析之cachetable
/** SparkSQL源码分析系列文章*/ SparkSQL可以将数据缓存到内存中,我们可以见到的通过调用cachetabletableName即可将一张表缓存到内存中,来极大的提高查询效率。 这就涉及到内存中的数据的存储形式,... 查看详情
实践课-------(第九篇)
通过这十天的框架搭建学习,学会了环境配置,及其测试,得出以下总结1.创建WEB工程添加struts支持2.分包3添加spring支持4.添加spring配置文件5.在web.xml文件中配置初始化读取参数(spring的配置文件)6.配置spring监听... 查看详情
用仿actionscript的语法来编写html5——第九篇,仿urlloader读取文件
第九篇,仿URLLoader读取文件先看看最后的代码functionreadFile(){urlloader=newLURLLoader();urlloader.addEventListener(LEvent.COMPLETE,readFileOk);urlloader.load("../file/test.txt","text");}functionreadFileOk(){mytxt.text 查看详情
第九篇:top命令free命令
top命令(查看进程的状态)1.cacheandbuffer2.cache:存放cpu经常调用的数据3.buffer:积攒硬盘上零散数据 free命令(使用内存的使用状态)1.free-m以M为单位 free-h以G为单位2.信息解读,如图:(1):已经分配给cache和buffer的内存=3+4+5(... 查看详情
flask第九篇flask-script组件
FlaskScript扩展提供向Flask插入外部脚本的功能,包括运行一个开发用的服务器,一个定制的Pythonshell,设置数据库的脚本,cronjobs,及其他运行在web应用之外的命令行任务;使得脚本和系统分开;FlaskScript和Flask本身的工作方式类似... 查看详情
第九篇:使用lstat函数获取文件信息
前言 在之前的文章中,描述过如何用fcntl函数改变文件的状态标记。但,文件还有很多信息,如文件类型,权限设置,设备编号,访问时间等等。如果要获取这些信息,则使用函数 lstat 可以轻松达到这... 查看详情
neo4j第九篇:查询数据(match)(代码片段)
Cypher使用match子句查询数据,是Cypher最基本的查询子句。在查询数据时,使用Match子句指定搜索的模式,这是从Neo4j数据库查询数据的最主要的方法。match子句之后通常会跟着where子句,向模式中添加过滤性的谓词,用于对数据进... 查看详情
python成长之路第九篇:网络编程(代码片段)
一、套接字1.1、套接字套接字最初是为同一主机上的应用程序所创建,使得主机上运行的一个程序(又名一个进程)与另一个运行的程序进行通信。这就是所谓的进程间通信(InterProcessCommunication,IPC)。有两种类型的套接字:... 查看详情
第九篇道
第九篇 道 “道”这个字出现在人们的视野中,已经有很悠久的历史。但是人们对于“道”这个字的理解非常模糊,都是盲目地去猜测,不知道这个字真正的意义是什么。其实,“道”就是轨道,也可以称之为“宇宙... 查看详情
混合编程jni第九篇之jni总结
系列目录:【混合编程Jni】系列目录_香菜聊游戏的博客-CSDN博客动态库的加载可以使用标准System.loadLibrary从共享库加载原生代码。关于参数传递int、char等这样的基本数据类型,在本地代码和JVM之间进行复制传递,而对象是... 查看详情
windows编程系列第九篇:剪贴板使用
??上一篇我们学习了常见的通用对话框,本篇来了解剪贴板的使用,它经常使用于复制粘贴功能。剪贴板是Windows最早就增加的功能,因为该功能很有用,我们差点儿每天都会使用到。通过剪贴板,我们就能够将数据从一个应用程... 查看详情
第九篇异常(代码片段)
12异常当Python检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的"异常"。12.1捕获异常12.1.1捕获异常try…except…看如下示例:try:print('-----test--1---')open('123.txt','... 查看详情
第九篇:map/reduce工作机制分析-数据的流向分析
前言 在MapReduce程序中,待处理的数据最开始是放在HDFS上的,这点无异议。 接下来,数据被会被送往一个个Map节点中去,这也无异议。 下面问题来了:数据在被Map节点处理完... 查看详情
directx11第九篇光照模型——高光
本系列文章主要翻译和参考自《Real-Time3DRenderingwithDirectXandHLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。 这里是书中的代码和资源。 本... 查看详情