《PYTHON3网络爬虫开发实践》——第五章 数据存储

第五章 数据存储

  • 用解析器解析出数据之后,接下来就是存储数据了。保存的形式可以多种多样,最简单的形式是直接保存为文本文件,如TXT、JSON、CSV等。另外,还可以保存到数据库中,如关系型数据库MySQL,非关系型数据库MongoDB、Redis 等。

  • 爬虫——TXT文本存储

    import requests
    from pyquery import PyQuery as pq
    
    url = 'https://www.zhihu.com/explore'
    headers = {
        'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'
    }
    html = requests.get(url, headers=headers).text
    doc = pq(html)
    items = doc('.explore-tab .feed-item').items()
    for item in items:
        question = item.find('h2').text()
        author = item.find('.author-link-line').text()
        answer = pq(item.find('.content').html()).text()
        file = open('explore.txt', 'a', encoding='utf-8')
        file.write('\n'.join([question, author, answer]))
        file.write('\n'+'=' * 50 + '\n')
        file.close()
    

    image-20190222112112803

  • 文件的打开方法

    image-20190222112159698

    image-20190222112210551

  • JSON

    JSON,全称为JavaScript Object Notation, 也就是JavaScript对象标记,它通过对象和数组的组合来表示数据,构造简洁但是结构化程度非常高,是一种轻量级的数据交换格式。

    在JavaScript语言中,一切都是对象。因此,任何支持的类型都可以通过JSON来表示,例如字符串、数字、对象、数组等。

    Python为我们提供了简单易用的JSON库来实现JSON文件的读写操作。

    JSON库的loads()方法将JSON文本字符串转为JSON对象

    dumps()方法将JSON对象转为文本字符串。
    例如,这里有一段JSON形式的字符串,它是str类型,我们用Python将其转换为可操作的数据结构,如列表或字典:

    image-20190222140400013

    image-20190222140537679

    JSON字符串的表示需要用双引号,否则loads()方法会解析失败。

  • 如果从JSON文本中读取内容,例如这里有一个data.json 文本文件,其内容是刚才定义的JSON字符串,我们可以先将文本文件内容读出,然后再利用loads()方法转化:

    image-20190222140911647

    image-20190222140921834

  • 如果想将列表重新写入文本,可以使用dump()方法,将JSON对象转为字符串。

    image-20190222141328225

    image-20190222141337277

    如果想保存JSON的格式,可以再加一个参数indent,代表缩进字符个数。

    image-20190222141423003

    为了输出中文,还需要指定参数ensure_ascii为false,还要规定文件输出的编码

    image-20190222141546975

  • CSV文件存储

    CSV,全称为Comma-Separated Values, 中文可以叫作逗号分隔值或字符分隔值,其文件以纯文本形式存储表格数据。记录间以某种换行符分隔。最常见的是逗号或制表符,CSV中不包含文本、数值、公式和格式等内容,就是特定字符分隔的纯文本,结构简单清晰。

    写入:

    image-20190222142219628

    image-20190222142234147

    image-20190222142245405

    如果想修改列与列之间的分隔符,可以传入delimiter参数。

    image-20190222142415044

    image-20190222142427457

    另外,我们也可以调用writerows()方法同时写人多行,此时参数就需要为二维列表:

    image-20190222142537716

    但是一般情况下,爬虫爬取的都是结构化数据,我们一般会用字典来表示。在csv库中字典的写入方式:

    image-20190222142741343

  • CSV的读取

    image-20190222142936406

    这里我们构造的是Reader对象,通过遍历输出了每行的内容,每一行都是一个列表形式。注意,如果CSV文件中包含中文的话,还需要指定文件编码。
    另外,如果接触过pandas的话,可以利用read_ csv()方法将数据从CSV中读取出来,例如:

    image-20190222143052172

    image-20190222143101262

    在做数据分析的时候,此种方法用得比较多,也是一种比较方便地读取CSV文件的方法。

  • 关系型数据库

    关系型数据库是基于关系模型的数据库,而关系模型是通过二维表来保存的,所以它的存储方式就是行列组成的表,每一列是一个字段,每一行是一条记录。表可以看作某个实体的集合,而实体之间存在联系,这就需要表与表之间的关联关系来体现,如主键外键的关联关系。多个表组成一个数据库,也就是关系型数据库。
    关系型数据库有多种,如SQLite、MySQL、Oracle、SQL Server、DB2 等。

  • 连接数据库

    mysql.server start
    mysql -u root -p
    

    image-20190222145138830

    这里通过PyMySQL的connect()方法声明一个 MySQL连接对象db,此时需要传人MySQL运行的host (即IP)。由于MySQL在本地运行,所以传人的是localhost。如果MySQL在远程运行,则传入其公网IP地址。后续的参数user即用户名,password 即密码,port 即端口(默认为3306 )。
    连接成功后,需要再调用cursor()方法获得MySQL的操作游标,利用游标来执行SQL语句。这里我们执行了两句SQL,直接用execute()方法执行即可。第一句SQL用于获得MySQL的当前版本,然后调用fetchone()方法获得第一条数据, 也就得到了版本号。第二句SQL执行创建数据库的操作,数据库名叫作spiders,默认编码为UTF-8。由于该语句不是查询语句,所以直接执行后就成功创建了数据库spiders。接着,再利用这个数据库进行后续的操作。

  • 创建数据库和表

    create DATABASE spiders(表名);
    

    image-20190222150948372

  • 向MySQL数据库中插入数据

    image-20190222152540738

    image-20190222152553375

    构造一个动态的SQL语句,实现传入一个字典来插入数据的方法。

    image-20190222153837540

    首先,需要构造插入的字段id、name和age。这里只需要将data的键名拿过来,然后用逗号分隔即可。所以’,’.join(data. keys())的结果就是id, name, age,然后需要构造多个%s当作占位符,有几个字段构造几个即可。比如,这里有三个字段,就需要构造%s, %s, %s。这里首先定义了长度为1的数组[ ‘%s’],然后用乘法将其扩充为[’%s’, ‘%s’, ‘%s’], 再调用join()方法,最终变成%s, %s, %s。最后,我们再利用字符串的format()方法将表名、字段名和占位符构造出来。最终的SQL语句就被
    动态构造成了:
    INSERT INTO students(id, name, age) VALUES (%s, %s, %s)
    最后,为execute()方法的第一个参数传人sql变量,第二个参数传人data的键值构造的元组,就可以成功插入数据了。

  • 事务机制

    为了保持数据的一致性,涉及到事务机制,事务含有4个属性,ACID特性。

    image-20190222153636849

    image-20190222153646878

  • 向MySQL数据库中更新数据

    image-20190222155647342

    这里构造的SQL语句其实是插入语句,但是我们在后面加了ON DUPLICATE KEY UPDATE。这行代码的意思是如果主键已经存在,就执行更新操作。比如,我们传人的数据id 仍然为20120001, 但是年龄有所变化,由20变成了21,此时这条数据不会被插人,而是直接更新id为20120001的数据。

  • 删除MySQL中的数据

    直接使用DELETE即可,只需要指定要删除的目标表名和删除条件,且仍需使用commit()方法。

    image-20190222155957368

  • 查询MySQL中的数据

    将年龄20岁及以上的学生查询出来:

    image-20190222160230229

    构造一条SQL语句,将年龄20岁及以上的学生查询出来,然后将其传给execute()
    方法。这里不再需要db的commit()方法。接着,调用cursor的rowcount属性获取查询结果的条数,然后我们调用了fetchone()方法,这个方法可以获取结果的第一条数据,返回结果是元组形式,元组的元素顺序跟字段一一对应 ,随后,我们又调用了fetchall()方法,它可以得到结果的所有数据。然后将其结果和类型打印出来,它是二重元组,每个元素都是一条记录,我们将其遍历输出出来。

5.3 非关系型数据库存储

  • NoSQL,全称Not Only SQL,意为不仅仅是SQL,泛指非关系型数据库。NoSQL是基于键值对的,而且不需要经过SQL层的解析,数据之间没有耦合性,性能非常高。
    非关系型数据库又可细分如下。
    键值存储数据库:代表有Redis、Voldemort和Oracle BDB等。
    列存储数据库:代表有Cassandra、HBase 和Riak等。
    文档型数据库:代表有CouchDB和MongoDB等。
    图形数据库:代表有Neo4J、InfoGrid 和Infinite Graph等。

  • 为什么要有非关系型数据库?/ 非关系型数据库的较比关系型数据库的优势?

    对于爬虫的数据存储来说,一条数据可能存在某些字段提取失败而缺失的情况,而且数据可能随时调整。另外,数据之间还存在嵌套关系。如果使用关系型数据库存储,一是需要提前建表,二是如果存在数据嵌套关系的话,需要进行序列化操作才可以存储,这非常不方便。如果用了非关系型数据库,就可以避免一些麻烦,更简单高效。

MongoDB

  • MongoDB是由C++语言编写的非关系型数据库,是一个基于分布式文件存储的开源数据库系统,其内容存储形式类似JSON对象,它的字段值可以包含其他文档、数组及文档数组,非常灵活。

  • 安装MongoDB

    连接MongoDB

    指定数据库

    指定集合

    插入数据(insert()方法,insert_one()和insert_many())

    查询(find_one()或find()、比较符号:大于$gt、正则匹配查询)

    计数(count())

    排序(sort())

    偏移(skip()、limit())

    更新(update())

    删除(remove()、delete_one()、delete_many())

    其他操作

Redis存储

  • Redis是-个基于内存的高效的键值型非关系型数据库,存取效率极高,而且支持多种存储数据结构,使用也非常简单。

猜你喜欢

转载自blog.csdn.net/qq_39362996/article/details/88029289
今日推荐