存储数据

存储海量数据

数据持久化的首选方案应该是关系型数据库,关系型数据库的产品很多,包括:Oracle、MySQL、SQLServer、PostgreSQL等。如果要存储海量的低价值数据,文档数据库也是不错的选择,MongoDB是文档数据库中的佼佼者,之前我们已经讲解过MongDB的相关知识,在此不再进行赘述。

数据缓存

通过《网络数据采集和解析》一文,我们已经知道了如何从指定的页面中抓取数据,以及如何保存抓取的结果,但是我们没有考虑过这么一种情况,就是我们可能需要从已经抓取过的页面中提取出更多的数据,重新去下载这些页面对于规模不大的网站倒是问题也不大,但是如果能够把这些页面缓存起来,对应用的性能会有明显的改善。可以使用Redis来提供高速缓存服务,关于Redis的知识,我们在《NoSQL入门》一文中已经做过简要的介绍。

实例 - 缓存知乎发现上的链接和页面代码

  1. from hashlib import sha1
  2. from urllib.parse import urljoin
  3. import pickle
  4. import re
  5. import requests
  6. import zlib
  7. from bs4 import BeautifulSoup
  8. from redis import Redis
  9. def main():
  10. # 指定种子页面
  11. base_url = 'https://www.zhihu.com/'
  12. seed_url = urljoin(base_url, 'explore')
  13. # 创建Redis客户端
  14. client = Redis(host='1.2.3.4', port=6379, password='1qaz2wsx')
  15. # 设置用户代理(否则访问会被拒绝)
  16. headers = {'user-agent': 'Baiduspider'}
  17. # 通过requests模块发送GET请求并指定用户代理
  18. resp = requests.get(seed_url, headers=headers)
  19. # 创建BeautifulSoup对象并指定使用lxml作为解析器
  20. soup = BeautifulSoup(resp.text, 'lxml')
  21. href_regex = re.compile(r'^/question')
  22. # 将URL处理成SHA1摘要(长度固定更简短)
  23. hasher_proto = sha1()
  24. # 查找所有href属性以/question打头的a标签
  25. for a_tag in soup.find_all('a', {'href': href_regex}):
  26. # 获取a标签的href属性值并组装完整的URL
  27. href = a_tag.attrs['href']
  28. full_url = urljoin(base_url, href)
  29. # 传入URL生成SHA1摘要
  30. hasher = hasher_proto.copy()
  31. hasher.update(full_url.encode('utf-8'))
  32. field_key = hasher.hexdigest()
  33. # 如果Redis的键'zhihu'对应的hash数据类型中没有URL的摘要就访问页面并缓存
  34. if not client.hexists('zhihu', field_key):
  35. html_page = requests.get(full_url, headers=headers).text
  36. # 对页面进行序列化和压缩操作
  37. zipped_page = zlib.compress(pickle.dumps(html_page))
  38. # 使用hash数据类型保存URL摘要及其对应的页面代码
  39. client.hset('zhihu', field_key, zipped_page)
  40. # 显示总共缓存了多少个页面
  41. print('Total %d question pages found.' % client.hlen('zhihu'))
  42. if __name__ == '__main__':
  43. main()