Python3 web crawler combat -34, Data storage: non-relational database storage: Redis

Redis is a memory-based key-value type of efficient non-relational databases, high access efficiency, but also supports a variety of data structures, using very simple, in this section we introduce Python's Redis operation, this introduces RedisPy usage library.

1. Preparations

Before beginning this section, make sure you have installed the Redis and RedisPy library, data import and export operation if do, then also need to install RedisDump, if not refer to the installation instructions to install the first chapter.

2. Redis, StrictRedis

RedisPy library provides for two classes StrictRedis and Redis Redis operation command implementation.

StrictRedis achieve most of the official commands, parameters also correspond, for example, set () method on the corresponding set method Redis commands. The Redis is StrictRedis subclass, its main function is for backward compatibility with older versions of several methods Curry, in order to make compatible, the way to do a rewrite, such as location lrem () method will value and num parameter command swaps, and Redis command-line parameters are inconsistent.

The official recommended StrictRedis, so this section we also use relevant methods StrictRedis class for demonstration.

3. Connect Redis

Current local Redis I have installed and running on port 6379, password is set to foobared.

Then you can use the following example and test connector Redis:

from redis import StrictRedis

redis = StrictRedis(host='localhost', port=6379, db=0, password='foobared')
redis.set('name', 'Bob')
print(redis.get('name'))
Python资源分享qun 784758214 ,内有安装包,PDF,学习视频,这里是Python学习者的聚集地,零基础,进阶,都欢迎

Here we are introduced to address Redis, operating ports, use of the database, password information. In the case of default does not pass, the four parameters are localhost, 6379,0, None. Now we declare a StrictRedis object, and then the next call to the set () method, set up a key-value pair, then get it printed.

operation result:

b'Bob'

This shows that our connection is successful, and can perform set (), get () to operate.

Of course, we can also use ConnectionPool to connect, for example:

from redis import StrictRedis, ConnectionPool

pool = ConnectionPool(host='localhost', port=6379, db=0, password='foobared')
redis = StrictRedis(connection_pool=pool)

Such a connection effect is the same, the source code can be found within StrictRedis observation is actually a host, port and other parameters and construct a ConnectionPool, so when we directly ConnectionPool argument to StrictRedis is the same.

In addition ConnectionPool also supports constructed by URL, the URL format supports the following three ways:

redis://[:password]@host:port/db
rediss://[:password]@host:port/db
unix://[:password]@/path/to/socket.sock?db=db

These three represent the URL to create Redis TCP connection, Redis TCP + SSL connection, Redis Unix Socket connection, we only need to construct any of the above URL can be connected, where password section if you can write, can not be omitted, here we and then show you the connection URL:

url = 'redis://:foobared@localhost:6379/0'
pool = ConnectionPool.from_url(url)
redis = StrictRedis(connection_pool=pool)
Python资源分享qun 784758214 ,内有安装包,PDF,学习视频,这里是Python学习者的聚集地,零基础,进阶,都欢迎

Here we use the first connection string to connect, we first declare a Redis connection string, and then call from_url () method creates a ConnectionPool, then passed StrictRedis to complete the connection, so the connection using a URL way is quite easy.

4. Key Operation

Here are some judgments mainly Key and methods of operation to do the next summary:

method effect Parameter Description Examples Example shows Sample results
exists(name) Determining whether there is a key name: key名 redis.exists('name') The existence of this key name True
delete(name) To delete a key name: key名 redis.delete('name') Delete this key name 1
type(name) Key type determination name: key名 redis.type('name') Analyzing this name key Type b'string'
keys(pattern) Get all conform to the rules of the key pattern: matching rules redis.keys('n*') Get all key to the beginning of the n [b'name']
randomkey() Gets a random key randomkey() Gets a random key b'name'
rename(src, dst) The key to rename src: original key name dst: new key name redis.rename('name', 'nickname') The name Rename nickname True
dbsize() Gets the number of key current database dbsize() Gets the number of key current database 100
expire(name, time) Set key expiration time, in seconds name: key name time: Number of seconds redis.expire('name', 2) The name of this key expiration time set two seconds True
ttl(name) Get key expiration time, in seconds, -1 permanent expiring name: key名 redis.ttl('name') Gets the expiration time name of this key -1
move(name, db) The key to a different database name: key name db: Database Code move('name', 2) No. 2 is moved to the database name True
flushdb() Delete the current selection of all key database flushdb() Delete the current selection of all key database True
flushall() Delete all all key database flushall() Delete all all key database True

5. String operations

There is the most basic Redis key-value pairs in the form of storage, usage summarized as follows:

method effect Parameter Description Examples Example shows Sample results
set(name, value) To the database key value is assigned the value of the string name name: key name value: value redis.set('name', 'Bob') The value assigned to the key name is Bob True
get(name) Returns the database key for the name of the string value name: key名 redis.get('name') Returns the name of this key value b'Bob'
getset(name, value) Giving value to the database key value for the string name and return to the previous value name: key name value: the new value redis.getset('name', 'Mike') Assignment name is Mike and get the last value b'Bob'
mget(keys, *args) 返回多个key对应的value keys: key的列表 redis.mget(['name', 'nickname']) 返回name和nickname的value [b'Mike', b'Miker']
setnx(name, value) 如果key不存在才设置value name: key名 redis.setnx('newname', 'James') 如果newname这key不存在则设置值为James 第一次运行True,第二次False
setex(name, time, value) 设置可以对应的值为string类型的value,并指定此键值对应的有效期 name: key名 time: 有效期 value: 值 redis.setex('name', 1, 'James') 将name这key的值设为James,有效期1秒 True
setrange(name, offset, value) 设置指定key的value值的子字符串 name: key名 offset: 偏移量 value: 值 redis.set('name', 'Hello') redis.setrange('name', 6, 'World') 设置name为Hello字符串,并在index为6的位置补World 11,修改后的字符串长度
mset(mapping) 批量赋值 mapping: 字典 redis.mset({'name1': 'Durant', 'name2': 'James'}) 将name1设为Durant,name2设为James True
msetnx(mapping) key均不存在时才批量赋值 mapping: 字典 redis.msetnx({'name3': 'Smith', 'name4': 'Curry'}) 在name3和name4均不存在的情况下才设置二者值 True
incr(name, amount=1) key为name的value增值操作,默认1,key不存在则被创建并设为amount name: key名 amount:增长的值 redis.incr('age', 1) age对应的值增1,若不存在则会创建并设置为1 1,即修改后的值
decr(name, amount=1) key为name的value减值操作,默认1,key不存在则被创建并设置为-amount name: key名 amount:减少的值 redis.decr('age', 1) age对应的值减1,若不存在则会创建并设置为-1 -1,即修改后的值
append(key, value) key为name的string的值附加value key: key名 redis.append('nickname', 'OK') 向key为nickname的值后追加OK 13,即修改后的字符串长度
substr(name, start, end=-1) 返回key为name的string的value的子串 name: key名 start: 起始索引 end: 终止索引,默认-1截取到末尾 redis.substr('name', 1, 4) 返回key为name的值的字符串,截取索引为1-4的字符 b'ello'
getrange(key, start, end) 获取key的value值从start到end的子字符串 key: key名 start: 起始索引 end: 终止索引 redis.getrange('name', 1, 4) 返回key为name的值的字符串,截取索引为1-4的字符 b'ello'

6. List操作

List,即列表。Redis 还提供了列表存储,列表内的元素可以重复,而且可以从两端存储,用法总结如下:

方法 作用 参数说明 示例 示例说明 示例结果
rpush(name, *values) 在key为name的list尾添加值为value的元素,可以传多个 name: key名 values: 值 redis.rpush('list', 1, 2, 3) 给list这个key的list尾添加1、2、3 3,list大小
lpush(name, *values) 在key为name的list头添加值为value的元素,可以传多个 name: key名 values: 值 redis.lpush('list', 0) 给list这个key的list头添加0 4,list大小
llen(name) 返回key为name的list的长度 name: key名 redis.llen('list') 返回key为list的列表的长度 4
lrange(name, start, end) 返回key为name的list中start至end之间的元素 name: key名 start: 起始索引 end: 终止索引 redis.lrange('list', 1, 3) 返回起始为1终止为3的索引范围对应的list [b'3', b'2', b'1']
ltrim(name, start, end) 截取key为name的list,保留索引为start到end的内容 name:key名 start: 起始索引 end: 终止索引 ltrim('list', 1, 3) 保留key为list的索引为1到3的元素 True
lindex(name, index) 返回key为name的list中index位置的元素 name: key名 index: 索引 redis.lindex('list', 1) 返回key为list的列表index为1的元素 b'2'
lset(name, index, value) 给key为name的list中index位置的元素赋值,越界则报错 name: key名 index: 索引位置 value: 值 redis.lset('list', 1, 5) 将key为list的list索引1位置赋值为5 True
lrem(name, count, value) 删除count个key的list中值为value的元素 name: key名 count: 删除个数 value: 值 redis.lrem('list', 2, 3) 将key为list的列表删除2个3 1,即删除的个数
lpop(name) 返回并删除key为name的list中的首元素 name: key名 redis.lpop('list') 返回并删除名为list的list第一个元素 b'5'
rpop(name) 返回并删除key为name的list中的尾元素 name: key名 redis.rpop('list') 返回并删除名为list的list最后一个元素 b'2'
blpop(keys, timeout=0) 返回并删除名称为在keys中的list中的首元素,如果list为空,则会一直阻塞等待 keys: key列表 timeout: 超时等待时间,0为一直等待 redis.blpop('list') 返回并删除名为list的list的第一个元素 [b'5']
brpop(keys, timeout=0) 返回并删除key为name的list中的尾元素,如果list为空,则会一直阻塞等待 keys: key列表 timeout: 超时等待时间,0为一直等待 redis.brpop('list') 返回并删除名为list的list的最后一个元素 [b'2']
rpoplpush(src, dst) 返回并删除名称为src的list的尾元素,并将该元素添加到名称为dst的list的头部 src: 源list的key dst: 目标list的key redis.rpoplpush('list', 'list2') 将key为list的list尾元素删除并返回并将其添加到key为list2的list头部 b'2'

7. Set操作

Set,即集合。Redis 还提供了集合存储,集合中的元素都是不重复的,用法总结如下:

方法 作用 参数说明 示例 示例说明 示例结果
sadd(name, *values) 向key为name的set中添加元素 name: key名 values: 值,可为多个 redis.sadd('tags', 'Book', 'Tea', 'Coffee') 向key为tags的set中添加Book、Tea、Coffee三个内容 3,即插入的数据个数
srem(name, *values) 从key为name的set中删除元素 name: key名 values: 值,可为多个 redis.srem('tags', 'Book') 从key为tags的set中删除Book 1,即删除的数据个数
spop(name) 随机返回并删除key为name的set中一个元素 name: key名 redis.spop('tags') 从key为tags的set中随机删除并返回该元素 b'Tea'
smove(src, dst, value) 从src对应的set中移除元素并添加到dst对应的set中 src: 源set dst: 目标set value: 元素值 redis.smove('tags', 'tags2', 'Coffee') 从key为tags的set中删除元素Coffee并添加到key为tags2的set True
scard(name) 返回key为name的set的元素个数 name: key名 redis.scard('tags') 获取key为tags的set中元素个数 3
sismember(name, value) 测试member是否是key为name的set的元素 name:key值 redis.sismember('tags', 'Book') 判断Book是否为key为tags的set元素 True
sinter(keys, *args) 返回所有给定key的set的交集 keys: key列表 redis.sinter(['tags', 'tags2']) 返回key为tags的set和key为tags2的set的交集 {b'Coffee'}
sinterstore(dest, keys, *args) 求交集并将交集保存到dest的集合 dest:结果集合 keys:key列表 redis.sinterstore('inttag', ['tags', 'tags2']) 求key为tags的set和key为tags2的set的交集并保存为inttag 1
sunion(keys, *args) 返回所有给定key的set的并集 keys: key列表 redis.sunion(['tags', 'tags2']) 返回key为tags的set和key为tags2的set的并集 {b'Coffee', b'Book', b'Pen'}
sunionstore(dest, keys, *args) 求并集并将并集保存到dest的集合 dest:结果集合 keys:key列表 redis.sunionstore('inttag', ['tags', 'tags2']) 求key为tags的set和key为tags2的set的并集并保存为inttag 3
sdiff(keys, *args) 返回所有给定key的set的差集 keys: key列表 redis.sdiff(['tags', 'tags2']) 返回key为tags的set和key为tags2的set的差集 {b'Book', b'Pen'}
sdiffstore(dest, keys, *args) 求差集并将差集保存到dest的集合 dest:结果集合 keys:key列表 redis.sdiffstore('inttag', ['tags', 'tags2']) 求key为tags的set和key为tags2的set的差集并保存为inttag 3
smembers(name) 返回key为name的set的所有元素 name: key名 redis.smembers('tags') 返回key为tags的set的所有元素 {b'Pen', b'Book', b'Coffee'}
srandmember(name) 随机返回key为name的set的一个元素,但不删除元素 name: key值 redis.srandmember('tags') 随机返回key为tags的set的一个元素

8. Sorted Set操作

Sorted Set,即有序集合,它相比集合多了一个分数字段,利用它我们可以对集合中的数据进行排序,其用法总结如下:

方法 作用 参数说明 示例 示例说明 示例结果
zadd(name, args, *kwargs) 向key为name的zset中添加元素member,score用于排序。如果该元素存在,则更新其顺序 name: key名 args: 可变参数 redis.zadd('grade', 100, 'Bob', 98, 'Mike') 向key为grade的zset中添加Bob,score为100,添加Mike,score为98 2,即添加的元素个数
zrem(name, *values) 删除key为name的zset中的元素 name: key名 values: 元素 redis.zrem('grade', 'Mike') 从key为grade的zset中删除Mike 1,即删除的元素个数
zincrby(name, value, amount=1) 如果在key为name的zset中已经存在元素value,则该元素的score增加amount,否则向该集合中添加该元素,其score的值为amount name: key名 value: 元素 amount: 增长的score值 redis.zincrby('grade', 'Bob', -2) key为grade的zset中Bob的score减2 98.0,即修改后的值
zrank(name, value) 返回key为name的zset中元素的排名(按score从小到大排序)即下标 name: key名 value: 元素值 redis.zrank('grade', 'Amy') 得到key为grade的zset中Amy的排名 1
zrevrank(name, value) 返回key为name的zset中元素的倒数排名(按score从大到小排序)即下标 name: key名 value: 元素值 redis.zrevrank('grade', 'Amy') 得到key为grade的zset中Amy的倒数排名 2
zrevrange(name, start, end, withscores=False) 返回key为name的zset(按score从大到小排序)中的index从start到end的所有元素 name: key值 start: 开始索引 end: 结束索引 withscores: 是否带score redis.zrevrange('grade', 0, 3) 返回key为grade的zset前四名元素 [b'Bob', b'Mike', b'Amy', b'James']
zrangebyscore(name, min, max, start=None, num=None, withscores=False) 返回key为name的zset中score在给定区间的元素 name:key名 min: 最低score max:最高score start: 起始索引 num: 个数 withscores: 是否带score redis.zrangebyscore('grade', 80, 95) 返回key为grade的zset中score在80和95之间的元素 [b'Amy', b'James']
zcount(name, min, max) 返回key为name的zset中score在给定区间的数量 name:key名 min: 最低score max: 最高score redis.zcount('grade', 80, 95) 返回key为grade的zset中score在80到95的元素个数 2
zcard(name) 返回key为name的zset的元素个数 name: key名 redis.zcard('grade') 获取key为grade的zset中元素个数 3
zremrangebyrank(name, min, max) 删除key为name的zset中排名在给定区间的元素 name:key名 min: 最低位次 max: 最高位次 redis.zremrangebyrank('grade', 0, 0) 删除key为grade的zset中排名第一的元素 1,即删除的元素个数
zremrangebyscore(name, min, max) 删除key为name的zset中score在给定区间的元素 name:key名 min: 最低score max:最高score redis.zremrangebyscore('grade', 80, 90) 删除score在80到90之间的元素 1,即删除的元素个数

9. Hash操作

Hash,即哈希。Redis 还提供了哈希表的数据结构,我们可以用name指定一个哈希表的名称,然后表内存储了各个键值对,用法总结如下:

方法 作用 参数说明 示例 示例说明 示例结果
hset(name, key, value) 向key为name的hash中添加映射 name: key名 key: 映射键名 value: 映射键值 hset('price', 'cake', 5) 向key为price的hash中添加映射关系,cake的值为5 1,即添加的映射个数
hsetnx(name, key, value) 向key为name的hash中添加映射,如果映射键名不存在 name: key名 key: 映射键名 value: 映射键值 hsetnx('price', 'book', 6) 向key为price的hash中添加映射关系,book的值为6 1,即添加的映射个数
hget(name, key) 返回key为name的hash中field对应的value name: key名 key: 映射键名 redis.hget('price', 'cake') 获取key为price的hash中键名为cake的value 5
hmget(name, keys, *args) 返回key为name的hash中各个键对应的value name: key名 keys: 映射键名列表 redis.hmget('price', ['apple', 'orange']) 获取key为price的hash中apple和orange的值 [b'3', b'7']
hmset(name, mapping) 向key为name的hash中批量添加映射 name: key名 mapping: 映射字典 redis.hmset('price', {'banana': 2, 'pear': 6}) 向key为price的hash中批量添加映射 True
hincrby(name, key, amount=1) 将key为name的hash中映射的value增加amount name: key名 key: 映射键名 amount: 增长量 redis.hincrby('price', 'apple', 3) key为price的hash中apple的值增加3 6,修改后的值
hexists(name, key) key为namehash中是否存在键名为key的映射 name: key名 key: 映射键名 redis.hexists('price', 'banana') key为price的hash中banana的值是否存在 True
hdel(name, *keys) key为namehash中删除键名为key的映射 name: key名 key: 映射键名 redis.hdel('price', 'banana') 从key为price的hash中删除键名为banana的映射 True
hlen(name) 从key为name的hash中获取映射个数 name: key名 redis.hlen('price') 从key为price的hash中获取映射个数 6
hkeys(name) 从key为name的hash中获取所有映射键名 name: key名 redis.hkeys('price') 从key为price的hash中获取所有映射键名 [b'cake', b'book', b'banana', b'pear']
hvals(name) 从key为name的hash中获取所有映射键值 name: key名 redis.hvals('price') 从key为price的hash中获取所有映射键值 [b'5', b'6', b'2', b'6']
hgetall(name) 从key为name的hash中获取所有映射键值对 name: key名 redis.hgetall('price') 从key为price的hash中获取所有映射键值对 {b'cake': b'5', b'book': b'6', b'orange': b'7', b'pear': b'6'}

10. RedisDump

RedisDump 提供了强大的 Redis 数据的导入和导出功能,本节我们来看下它的具体用法。

首先确保已经安装好了 RedisDump。

RedisDump 提供两个可执行命令,redis-dump 用于导出数据,redis-load 用于导入数据。

redis-dump

我们可以首先输入如下命令查看所有可选项:

redis-dump -h

运行结果如下:

Usage: redis-dump [global options] COMMAND [command options] 
    -u, --uri=S                      Redis URI (e.g. redis://hostname[:port])
    -d, --database=S                 Redis database (e.g. -d 15)
    -s, --sleep=S                    Sleep for S seconds after dumping (for debugging)
    -c, --count=S                    Chunk size (default: 10000)
    -f, --filter=S                   Filter selected keys (passed directly to redis' KEYS command)
    -O, --without_optimizations      Disable run time optimizations
    -V, --version                    Display version
    -D, --debug
        --nosafe

可以看到其参数,-u 代表 Redis 连接字符串,-d 代表数据库代号,默认全部,-s 代表导出之后的休眠时间,-c 代表分块大小,默认是 10000,-f 代表导出时的过滤器,-O 代表禁用运行时优化,-V 显示版本,-D 开启调试。

我们拿本地的 Redis 做测试,运行在 6379 端口上,密码为 foobared,导出命令如下:

redis-dump -u :foobared@localhost:6379

如果没有密码的话可以不加密码前缀,命令如下:

redis-dump -u localhost:6379

运行之后可以将本地 0-15号 数据库的所有数据输出出来,例如:

{"db":0,"key":"name","ttl":-1,"type":"string","value":"James","size":5}
{"db":0,"key":"name2","ttl":-1,"type":"string","value":"Durant","size":6}
{"db":0,"key":"name3","ttl":-1,"type":"string","value":"Durant","size":6}
{"db":0,"key":"name4","ttl":-1,"type":"string","value":"HelloWorld","size":10}
{"db":0,"key":"name5","ttl":-1,"type":"string","value":"James","size":5}
{"db":0,"key":"name6","ttl":-1,"type":"string","value":"James","size":5}
{"db":0,"key":"age","ttl":-1,"type":"string","value":"1","size":1}
{"db":0,"key":"age2","ttl":-1,"type":"string","value":"-5","size":2}

每条数据都包含五个字段,db 即数据库代号,key 即键名,ttl 即该键值对的有效时间,type 即键值类型,size 即占用空间。

如果想要将其输出为 Json 行文件,可以使用如下命令:

redis-dump -u :foobared@localhost:6379 > ./redis_data.jl

这样我们就可以成功将 Redis 的所有数据库的所有数据导出成 Json 行文件了。

另外我们可以使用 -d 参数指定某个数据库的导出,例如只导出 1 号数据库的内容:

redis-dump -u :foobared@localhost:6379 -d 1 > ./redis.data.jl

如果只想导出特定的内容,如想导出 adsl 开头的数据,可以加入 -f 参数用来过滤,命令如下:

redis-dump -u :foobared@localhost:6379 -f adsl:* > ./redis.data.jl

其中 -f 的参数即 Redis 的 keys 命令的参数,可以写一些过滤规则。

redis-load

我们同样可以首先输入如下命令查看所有可选项:

redis-load -h

运行结果如下:

redis-load --help
  Try: redis-load [global options] COMMAND [command options] 
    -u, --uri=S                      Redis URI (e.g. redis://hostname[:port])
    -d, --database=S                 Redis database (e.g. -d 15)
    -s, --sleep=S                    Sleep for S seconds after dumping (for debugging)
    -n, --no_check_utf8
    -V, --version                    Display version
    -D, --debug
        --nosafe

可以看到其参数,-u 代表 Redis 连接字符串,-d 代表数据库代号,默认全部,-s 代表导出之后的休眠时间,-n 代表不检测 UTF-8 编码,-V 显示版本,-D 开启调试。

我们可以将 Json 行文件导入到 Redis 数据库中:

< redis_data.json redis-load -u :foobared@localhost:6379

这样就可以成功将 Json 行文件导入到数据库中了。

另外如下命令同样可以达到同样的效果:

cat redis_data.json | redis-load -u :foobared@localhost:6379
Python资源分享qun 784758214 ,内有安装包,PDF,学习视频,这里是Python学习者的聚集地,零基础,进阶,都欢迎

以上便是 RedisDump 的使用概述,使用它我们可以高效便捷地实现 Redis 数据库的导入导出。

11. 结语

本节我们了解了 RedisPy 对 Redis 数据库的一些基本操作,另外还了解了 RedisDump 对数据导入导出做了演示,由于其便捷和高效性,在后文我们会利用 Redis 实现很多架构,如维护代理池、Cookies 池、ADSL 拨号代理池、ScrapyRedis 分布式架构等,所以 Redis 的操作需要好好掌握。

Guess you like

Origin blog.51cto.com/14445003/2426851