Python爬蟲-Redis

Python爬蟲-Redis

前言

做爲跟MongoDB一樣NoSQL陣營的Redis,也具備相似的「直爽快」特性。它自己讀取速度快,又提供豐富的數據結構,避免程序員重複造輪子。大名鼎鼎的分佈式scrapy也是基於redis,因此趕忙瞭解一下唄!html

啓動服務器

建議指定配置文件的方式啓動,個人配置文件所在路徑: /etc/redis/redis-server.conf 就不知道大家的是否是啦python

啓動方式:redis-server /etc/redis/redis-server.conf程序員

啓動客戶端

  1. 進入命令行:redis-cli
  2. 退出客戶端:exit

數據操做

redis是key-value的數據,key的類型是字符串,value類型能夠是:string,hash,list,set,zsetredis

string

最基本類型,最大存儲512M數據,可存儲任何數據:數字,圖片,序列化對象等數據庫


  1. 設置鍵值:set key value
    這裏寫圖片描述
  2. 也能夠一次設置多個數據:mset key1 value1 key2 value2 key3 value3...這裏寫圖片描述
  3. 獲取鍵值:get key;也能夠一次獲取多個鍵值:mget key1 key2 key3... 這裏寫圖片描述
    若是不存在,返回nil
  4. 甚至還能追加鍵值:append key value
    這裏寫圖片描述
  5. 也能夠獲取鍵值長度(有點像C語法哇):strlen key
    這裏寫圖片描述
  6. 也能夠在設置鍵值的時候設置過時時間:setex key seconds value
    這裏寫圖片描述
  7. 運算(鍵值要求爲數值):incr key 鍵值+1;incrby key increment 鍵值指定+increment ;相對應的就有decr key 鍵值-1,decrby key increment 指定-increment
    這裏寫圖片描述

鍵命令

(不只僅針對於string類型,其餘value類型的key都適用)服務器


  1. 查找鍵:keys pattern(支持正則),因此查看所有鍵能夠是keys *
    這裏寫圖片描述
  2. 查看鍵是否存在:exists key,存在返回1,不存在返回0
    這裏寫圖片描述
    也能夠一次查詢多個鍵:exists key1 key2 ...,返回值爲總和
    這裏寫圖片描述
  3. 查看鍵的類型:type key
  4. 刪除鍵:del key,成功返回1,失敗或鍵不存在返回0;或者刪除多個鍵:del key1 key2 ...,返回值爲總和,即使鍵不存在,亦不會報錯
    這裏寫圖片描述
  5. 設置過時時間:expire key seconds;查看鍵的剩餘存活時間:ttl key 這裏寫圖片描述
    expire操做後返回1表示設置成功,返回0表示設置失敗或是鍵不存在,設置時間單位秒;ttl操做後返回剩餘存貨時間,若是返回-2表示鍵不存在,若是返回-1表明永久存在
  6. 固然,也能清除過時時間:persist key
    這裏寫圖片描述
    若是persit操做以後返回1表示操做成功;若是返回0,鍵不存在或鍵自己就是永久

hash

用於存儲對象,對象格式爲鍵值對
1. hset key field value / hmset key field1 value1 field2 value2 ...,如何理解」對象」呢?即:一我的,這就是一個對象,有名字,年齡,性別等
這裏寫圖片描述
2. hget key field / hmget key field1 field2 ...
這裏寫圖片描述
3. 獲取指定key的全部字段和值: hgetall key
這裏寫圖片描述
4. 獲取指定key的全部字段:hkeys key
這裏寫圖片描述
5. 獲取指定key的全部值:hvals key
6. 獲取指定key的字段個數:hlen key
7. 判斷key的字段是否存在:hexists key field,存在返回1,不存在返回0
8. 刪除字段及對應值:hdel key field / hdel key field1 field2 ...
9. 刪除key:del key
10. 獲取值的字符串長度:hstrlen key field 我查了使用文檔,的確存在這個hstrlen命令,用Tab命令提示也能自動彈出來,可是——
這裏寫圖片描述
哈哈,布吉島布吉島,先佔位之後填坑吧數據結構

list

列表的元素類型是string,按照插入順序排序,可列表的頭或尾添加元素多線程


  1. 從頭/尾部插入:lpush/rpush key value,每次返回的值是列表中的元素個數
    這裏寫圖片描述
  2. 在一個元素的前/後插入元素:linsert key before/after pivot value,這裏的支點(pivot)就是原列表中的元素,value則是須要新添加的元素
    這裏寫圖片描述
    失敗則返回-1
  3. 移除並得到值:lpop/rpop key,這裏能夠用python的list類型的pop方法來理解
    這裏寫圖片描述
  4. 利用索引獲取元素:lindex key index
    這裏寫圖片描述
  5. 獲取key的長度(也就是列表中的元素個數):llen key
  6. 修改列表中的元素值:lset key index value,指定元素在列表中的索引(index),value是修改後的內容。==若是index值上並不存在元素,報索引錯誤==
  7. 返回指定範圍的元素:lrange key startIndex stopIndex
    這裏寫圖片描述
    超出索引範圍不報錯
  8. 裁剪列表:ltrim key startIndex stopIndex

set

無序集合,元素類型string,元素具備惟一性,不重複app


  1. 添加元素:sadd key member;或者一次添加多個:sadd key member1 member2 ...,若是添加的元素已存在,返回0
    這裏寫圖片描述
  2. 移除元素:srem key member / srem key member1 member2 ...
  3. 獲取全部元素:smembers key
  4. 獲取集合元素個數:scard key
  5. 求多個集合的交集:sinter key1 key2 ...
  6. 求集合與其餘集合的差集:sdiff key1 key2 ...
  7. 求多個集合的合集:sunion key1 kye2 ...
  8. 判斷元素是否在集合中:sismember key member,存在返回1,不存在返回0
    這裏寫圖片描述

zset

有序集合,惟一性,每一個元素都會關聯到一個double類型的score,表示權重,根據權重對元素排序,元素的score能夠相同python爬蟲


  1. zadd key score memberzadd key socre1 member1 score2 member2 ...
  2. zrem key member/zrem key member1 member2 ...
  3. zrange key start stop
  4. zcard key
  5. 統計score值在min與max的個數:zcount key min max
  6. 返回member的score值:zscore key member

發佈訂閱

Redis 發佈訂閱(pub/sub)是一種消息通訊模式:發送者(pub)發送消息,訂閱者(sub)接收消息。

  1. 消息格式:
    a. subscribe 頻道名1 [頻道名2 ...] 訂閱
    b. unsubscribe 頻道名1 [頻道名2 ...] 退訂
    c. message以後顯示頻道,再以後顯示正文
    d. publish 頻道 消息 發佈

發佈消息
這裏寫圖片描述

接受消息
這裏寫圖片描述

主從配置

每一個主均可以設置許多的從,每一個從又能夠設置許多的從;經過設置主從,搭建分佈式,如scrapy-redis分佈式爬蟲

  1. 對主機修改配置文件:bind 主機Ip
  2. 對從機修改配置文件:
    bind 從機Ip
    slaveof 主機Ip port

與python交互

  1. 安裝包redis,導入:import redis
  2. 鏈接redis:r = redis.StrictRedis(host="hostname", prot=6379)
  3. 使用方法1:根據數據類型,使用對應方法,如:r.set("name", "kaihui") / r.get("name")
  4. 使用方法2:
    p = r.pipeline()
    p.set(...)
    p.get(...)
    p.execute()
    ==法2緩衝多條命令,而後一次性執行,減小服務器-客戶端之間TCP數據庫包,從而提升效率==

以前在redis客戶端操做的命令,都很好的封裝到了鏈接數據庫的對象裏,能夠直接使用,如:r.hset() r.sadd()…

利用redis實戰

以前抓取過電影排行榜,句子迷,QQ空間,音樂熱評等等,其實大多操做相似,今天想換別的方向(其實操做也相似)。
衆所周知,爬蟲是容易封ip的,爲了應對如此強硬的反扒措施,有了利用代理ip爬取信息的方法。既然有了需求,固然就有了市場,我也沒非要不可的數據須要爬取,便不至於花錢購買代理。
這裏寫圖片描述
西刺網站提供免費代理,既然有「免費」二字,效果你們就應該心知肚明的。或許人公司提供的效果不至於那麼差,卻奈何全國爬蟲都想「好好」利用。

分析網頁一如既往,這個網頁毫無難度,requests發起get請求,利用xpath解析響應,提取ip和端口號,再存入redis。稍微不一樣的是,咱們拿到的代理ip能不能用呢?這裏須要作一個測試,我寫了一個filter_ip()函數進行過濾,主要思想是利用代理去訪問百度,若是返回狀態碼是200,那麼OK,存起來;不然丟棄

def filter_ip(proxyData):

    # 剔除https類型的
    if proxyData["type"].upper() == "HTTPS":
        return

    del proxyData["type"]
    # 構造requests模塊ip代理的參數結構
    proxyData = {
        "http":"http://"+proxyData["ip"]+":"+proxyData["port"]
    }

    try:
        response = requests.get(url="http://www.baidu.com/", proxies=proxyData)
        response.raise_for_status()
    except:
        print(f"{proxyData}不可用")
        return None

    # 若可用,存入redis
    to_redis(proxyData)

因爲構建ip池只是爲了更好的輔助爬蟲,因此效率方面要求嚴格,爲此我利用了多進程+多線程來達到目的

# 設置進程池
pool = Pool(10)
for item in parse_html(html):
    pool.apply_async(set_threading, (item, ))

pool.close()
pool.join()
def set_threading(item):
    # 設置線程函數
    t = Thread(target=filter_ip, args=(item, ))
    t.start()
    t.join()

總體邏輯以下
這裏寫圖片描述

反思

我抓取了代理網頁前三頁,然而僅9個寫入數據庫,其免費可想而知
這裏寫圖片描述

最初寫的單進程+單線程,運行速度極慢,纔想到多進程+多線程。多番調試,速度提高了6倍。然而也不過對300個ip處理而已,竟須要200s上下。與GitHub上最高star的開源項目差之千里
這裏寫圖片描述

想起一晚趴在牀上看《愛你就像愛生命》,有多少人知道王小波也是個程序員呢?他在給朋友曉陽的信中這樣寫道:個人圖像部分也是彙編寫的,反覆優化,也達不到他的水平,不得不認可技不如人。

路漫漫其修遠兮呢!

相關文章
相關標籤/搜索