python数据存储和查询代码_【Python分享】如何便捷地存储、查询数据

前言在之前的文章(如下)中,分享了爬取天天基金、中债指数的代码。爬取的数据很多,如何方便地存储、查询,也是一个麻烦的问题。本文分享一下我实现的基于 lsm-db 的本地文件数据存储、查询模块。

分享天天基金数据爬取的Python脚本

【Python分享】爬取中债指数的信息和历史行情

基础使用文件存储数据

以下面的数据为例,要把 index 存储下来,一个非常简单的方法,就是用 JSON 序列化,存储到文件里

index = {

'source': 'chinabond',

'code': '中债-1-30年利率债指数-总值-财富',

'indexid': '8a8b2ca0561f2580015620aed8481153',

'name': '中债-1-30年利率债指数-总值-财富',

'history': [

['2007-01-04', 100.0308],

['2007-01-05', 100.1178],

...

],

}

代码如下:

import json

s = json.dumps(index)

open('index.json', 'w').write(s)

s = open('index.json').read()

index = json.loads(s)

对于单条数据的读写来说,这样确实简单方便。但是如果是很多条数据,就不那么方便了。如果把所有数据存储到一个 JSON 文件里,那么即使只想读取单条数据,也必须读取全部内容,更新数据的时候也是如此,在数据量较大时就极为低效了。如果把每个数据存储到单独的 JSON 文件里,那么当数据的数量很多时,就会产生大量小文件,读写效率也会下降。

使用数据库存储数据

数据库是计算机领域对于数据存储的通用解决方案。常见的,如关系型数据库 MySQL、SQLite,文档型数据库 MongoDB。

对于轻量数据存取需求,KV数据库 lsm-db 是一个比较好的选择。lsm-db 是一个内嵌的 KV 数据库,数据存储在单个文件中,支持高效地读写、扫描操作。还以上面的 index 数据为例,用 index 的 code 作为 key,JSON 序列化的字符串作为 value,就实现了将数据的存储在KV数据库中,避免了上面原始的文件存储数据的弊端。

更复杂一点,可以把数据的一部分字段,单独存储到特殊的key里,作为索引,用于加速查询。这里就不展开说明了。

存储查询模块使用下面开始正式介绍模块的使用

概述

lib_dbs.py

这个文件实现了一个基于 KV 数据库的数据存储类 Table,类似 MySQL 里的表。

lib_filter.py

这个文件实现了一个查询类,可以支持一些匹配条件,比如等于、不等于、大于、小于、存在、不存在等,也支持多个条件的组合。

基本用法

from lib_dbs import Table

索引字段INDEXES = [

'code',

'name',

'update_time',

'ror',

]

Index = Table(

'data/index.ldb',

'Index',

'code',

INDEXES,

['history'],

)

上面的代码里,Index 就是具体的数据模型对象了,它的初始化参数是

db_uri 数据库文件路径,每个数据模型对象都要有单独的数据库

name 数据模型对象的名称

pk 数据模型对象的主键,用于唯一标识一条数据,数据的这个字段的值必须是字符串,且不能为空

indexes 需要索引的字段,list类型,针对这些字段的匹配会比较快

heavy_keys list类型,这些字段会单独存储,可以把历史行情数据等很大的字段放里面

Table 实例的基本用法如下:

Table.ensure_index()

刷新索引数据,新增的数据表、修改了索引字段后,必须执行这个函数

Table.save(item)

存储一条数据,item 应是 dict 类型,主键必须存在且不为空值

Table.bulk_save(items)

存储多条数据

Table.delete(pk)

根据主键的值 pk 删除一条数据。对应数据不存在时也不会报错

Table.get_by_pk(pk, shallow=False)

根据主键的值 pk 查询一条数据。对应数据不存在时,返回None。shallow参数为True时,代表浅查询,表定义里 heavy_keys 里的字段将不会读取,速度会更快。

Table.list(shallow=False)

读取所有数据。shallow参数同上。

示例:

from lib_index_db import Index

Index.ensure_index()

indexids = [i['id'] for i in get_chinabond_index_list()]

names = set()

for indexid in indexids:

_indexes = get_chinabond_index(indexid)

for index in _indexes:

names.add(index['name'])

print(index['name'])

Index.save(index)

indexes = Index.list(shallow=True)

index = Index.get(name='中债-信用债总指数-总值-财富')

from lib_fund_db import Fund

from lib_fund import fund_detail

Fund.ensure_index()

codes = ['510050', '510310', '510500']

for code in codes:

fund = fund_detail(code)

if fund:

Fund.save(fund)

funds = Fund.list(shallow=True)

fund = Fund.get(code='510310')

数据模型对象的高级用法

Table.filter(q=None, shallow=False, **kwargs)

返回查询对象QuerySet,查询结果对象QuerySet的详细用法见下文。shallow参数为True时,代表浅查询,表定义里 heavy_keys 里的字段将不会读取,速度会更快。q 是查询对象Q,查询对象Q的详细用法见下文。当 q 为 None 时,kwargs 如果非空,将会用于快捷构造查询对象。

Table.get(q=None, shallow=False, **kwargs)

参数与 .filter() 函数相同,但是返回的是查询对象的第一条数据,如果不存在匹配的数据,返回 None

查询结果集对象QuerySet

迭代

QuerySet 对象可以作为迭代器使用

QuerySet.filter(q=None, **kwargs)

查询结果集对象可以再应用另一个查询,以便级联查询

QuerySet.list()

返回 list 格式的查询结果

QuerySet.list_field(field)

返回 list 格式的查询结果,但是只查询 field 字段

QuerySet.list_fields(*fields)

返回 list 格式的查询结果,但是只查询fields指定的多个字段

QuerySet.count()

返回查询结果集对象的数据个数

查询对象 Q

Q(expr)

从字符串 expr 初始化,expr 是表达式形式,例如 "ror.2020 > 10",左边是字段名,中间是运算符,右边是比较值。"ror.2020 > 10"的意思就是 item['ror']['2020'] 大于 10。注意:除非特别说明,否则字段不存在时,仍然认为是满足匹配条件的。

运算符列表

=== 相等,如果对应字段不存在,视为不匹配。

== 相等

!= 不相等

<=, =, > 字面意思

~ 字段是字符串类型,表示包含字串。例如 "name ~ '债券' 的意思是 name 字段包含 '债券'

!~ 不包含

$e 字段存在

$ne 字段不存在

Q.from_kwargs(kwargs)

kwargs 是 dict 格式,等价于 key==value 的查询条件

示例

Table.filter(code='510310) 等价于

Table.filter(Q.from_kwargs({'code': '510310'})) 等价于

Table.filter(Q('code == "510310"'))

组合 Q 对象

多个 Q 对象可以组合成复杂查询

~ q 不满足q条件,逻辑非

q1 & q2 同时满足 q1、q2,逻辑与

q1 | q2 满足 q1 或者 q2,逻辑或

示例

Q('ror.2020 > 10') | Q('mdd.2020 < 2')

模块下载与配置代码在 https://github.com/puxxustc/invlib 这里。如果不能访问,也可以从附件下载。附件 invlib.pdf 是个 zip 压缩包,因为论坛无法上传 zip 格式,所以改名成 pdf,下载后再自己改成 zip 后缀,就可以解压了。

环境依赖

Python 3.8

需要安装这些 pip 包 beautifulsoup4, lxml, matplotlib, numpy, pandas, requests, wcwidth, ujson, lsm-db, msgpack, more-itertools

1金币8金币18金币58金币88金币188金币其它金额

余额不足,立即充值

我的金币余额:个

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值