Skip to content

Latest commit

 

History

History
66 lines (51 loc) · 2.93 KB

68.存儲數據.md

File metadata and controls

66 lines (51 loc) · 2.93 KB

存儲數據

存儲海量數據

數據持久化的首選方案應該是關係型數據庫,關係型數據庫的產品很多,包括:Oracle、MySQL、SQLServer、PostgreSQL等。如果要存儲海量的低價值數據,文檔數據庫也是不錯的選擇,MongoDB是文檔數據庫中的佼佼者,之前我們已經講解過MongDB的相關知識,在此不再進行贅述。

數據緩存

通過《網絡數據採集和解析》一文,我們已經知道了如何從指定的頁面中抓取數據,以及如何保存抓取的結果,但是我們沒有考慮過這麼一種情況,就是我們可能需要從已經抓取過的頁面中提取出更多的數據,重新去下載這些頁面對於規模不大的網站倒是問題也不大,但是如果能夠把這些頁面緩存起來,對應用的性能會有明顯的改善。可以使用Redis來提供高速緩存服務,關於Redis的知識,我們在《NoSQL入門》一文中已經做過簡要的介紹。

實例 - 緩存知乎發現上的鏈接和頁面代碼

from hashlib import sha1
from urllib.parse import urljoin

import pickle
import re
import requests
import zlib

from bs4 import BeautifulSoup
from redis import Redis


def main():
    # 指定種子頁面
    base_url = 'https://www.zhihu.com/'
    seed_url = urljoin(base_url, 'explore')
    # 創建Redis客戶端
    client = Redis(host='1.2.3.4', port=6379, password='1qaz2wsx')
    # 設置用戶代理(否則訪問會被拒絕)
    headers = {'user-agent': 'Baiduspider'}
    # 通過requests模塊發送GET請求並指定用戶代理
    resp = requests.get(seed_url, headers=headers)
    # 創建BeautifulSoup對象並指定使用lxml作爲解析器
    soup = BeautifulSoup(resp.text, 'lxml')
    href_regex = re.compile(r'^/question')
    # 將URL處理成SHA1摘要(長度固定更簡短)
    hasher_proto = sha1()
    # 查找所有href屬性以/question打頭的a標籤
    for a_tag in soup.find_all('a', {'href': href_regex}):
        # 獲取a標籤的href屬性值並組裝完整的URL
        href = a_tag.attrs['href']
        full_url = urljoin(base_url, href)
        # 傳入URL生成SHA1摘要
        hasher = hasher_proto.copy()
        hasher.update(full_url.encode('utf-8'))
        field_key = hasher.hexdigest()
        # 如果Redis的鍵'zhihu'對應的hash數據類型中沒有URL的摘要就訪問頁面並緩存
        if not client.hexists('zhihu', field_key):
            html_page = requests.get(full_url, headers=headers).text
            # 對頁面進行序列化和壓縮操作
            zipped_page = zlib.compress(pickle.dumps(html_page))
            # 使用hash數據類型保存URL摘要及其對應的頁面代碼
            client.hset('zhihu', field_key, zipped_page)
    # 顯示總共緩存了多少個頁面
    print('Total %d question pages found.' % client.hlen('zhihu'))


if __name__ == '__main__':
    main()