第九篇数据表设计和保存item到json文件

爬行的龟      2022-02-13     477

关键词:

上节说到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》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。      这里是书中的代码和资源。      本... 查看详情