Python中的爬取缓存


  想象这么一个情况(当然可能真实发生过😏),你部署了一个爬虫项目,运行了三五天,获得了你想要的数据,这个时候一个"讨人厌"的人出现😱,让你爬取的时候增加一些数据,会不会很崩溃?是不是前面几天的工作白做了? 😇爬虫避免此类问题的方式之一是从开始时就缓存被爬取的网页,这样就可以让每个网页只下载一次,但可以多次使用。
  但是,并不是所有的爬取需求都适用缓存,那具体要不要支持缓存、如何在爬虫项目中增加缓存支持呢?请看下文。

一、何时使用缓存

  缓存,还是不缓存?是一个问题。

  如果你需要执行一个大型爬取工作,那么它可能会由于错误或异常被中断,缓存可以帮助你无须重新爬取那些可能已经抓取过的页面。缓存还可以让你在离线时访问这些页面(出于数据分析或开发的目的)。
  不过,如果你的最高优先级是获得网站最新和当前的信息,那此时缓存就没有意义。此外,如果你没有计划实现大型或可重复的爬虫,那么可能只需要每次去抓取页面即可。
  那如果支持了缓存,多久清空缓存并抓取新页面?后面都会讲解,首先让我们学习如何使用缓存!

二、为爬虫添加缓存支持

三、磁盘缓存

import os
import re
from urllib.parse import urlsplit
import json
from Link_Crawler import link_crawler


class DiskCache:
    def __init__(self, cache_dir='cache', max_len=255):
        self.cache_dir = cache_dir
        self.max_len = max_len

    def url_to_path(self, url):
        """ Return file system path string for given URL"""
        components = urlsplit(url)
        # append index.html to empty paths
        path = components.path
        if not path:
            path = '/index.html'
        elif path.endswith('/'):
            path += 'index.html'

        filename = components.netloc + path + components.query
        # replace invalid characters
        filename = re.sub('[^/0-9a-zA-Z\-.,;_ ]', '_', filename)
        # restrict maximum number of characters
        filename = '/'.join(seg[:self.max_len] for seg in filename.split('/'))

        return os.path.join(self.cache_dir, filename)

    def __getitem__(self, url):
        """Load data from disk for given URL"""
        path = self.url_to_path(url)
        if os.path.exists(path):
            return json.load(path)
        else:
            # URL has not yet been cached
            raise KeyError(url + ' does not exist')

    def __setitem__(self, url, result):
        """Save data to disk for given url"""

        path = self.url_to_path(url)
        folder = os.path.dirname(path)
        if not os.path.exists(folder):
            os.makedirs(folder)
        json.dump(result, path)


if __name__ == '__main__':
    import time
    start = time.time()
    link_crawler('http://example.python-scraping.com/', '/view', cache=DiskCache())
    print("runing:%s" % (time.time()-start))

  从运行时间和运行结果来看,第二次没有去下载,而是从磁盘重读取出来,可以看出效率提高了许多.

缺点

  • 受限于本地文件系统的限制。
  • 一些URl会被映射为相同的文件名。
  • 如果文件数量过多的话,会很难实现

四、数据库存储缓存

  介于磁盘缓存的限制,爬取到的数据量比较大,但又无任何复杂的连接,所以选用NoSQL数据库,这种数据库相比常用的关系型数据库更容易扩展。我们将使用非常流行的键值对存储 Redis 作为我们的缓存。
  键值对存储类似于 Python 字典,存储中的每个元素都有一个键和一个值。在设计 DiskCache 时,键值对模型可以很好地解决该问题。Redis 实际上表示 REmote DIctionary Server(远程字典服务器)。

1. 安装Redis

  Redis官方不支持Windows系统,只能用微软开源部门移植的版本,笔者下载版本Windows Redis下载,下载解压之后,在其文件夹直接打开cmd窗口,输入redis-server.exe redis.windows.conf,然后你就可以看到redis的信息了。(已经安装完成)

  Python程序想使用,也需要单独安装库pip install redis,完成之后通过下面代码测试是否安装成功。

import redis

r = redis.StrictRedis(host='localhost', port=6379, db=0) 
r.set('test', 'answer')
True

r.get('test')

b'answer'

  像上面,可以正常导入,正常存取,即说明安装成功,服务也启动,就可以进行后续的操作了。

2. Redis的最基本操作

set命令:存数据
  只是简单地覆盖了之前的值,这对于类似网络爬虫这样的简单存储来说非常合适。

get命令:取数据
  从 Redis 存储中接收到的是 bytes 类型,即使我们插入的是字典或字符串。

keys():
  keys 方法返回了所有可用键的列表。

delete():
  delete 方法可以让我们传递一个(或多个)键并从存储中删除它们

flushdb():
  删除所有的键

3. Redis缓存实现

import json
from datetime import timedelta
from redis import StrictRedis
from Link_Crawler import link_crawler


class RedisCache:
    def __init__(self, client=None, expires=timedelta(days=30), encoding='utf-8'):
        # if a client object is not passed then try
        # connecting to redis at the default localhost port
        self.client = StrictRedis(host='localhost', port=6379, db=0) if client is None else client
        self.expires = expires
        self.encoding = encoding

    def __getitem__(self, url):

        """Load value from Redis for the given URL"""
        record = self.client.get(url)
        if record:
            return json.loads(record.decode(self.encoding))
        else:
            raise KeyError(url + ' does not exist')

    def __setitem__(self, url, result):
        """Save value in Redis for the given URL"""
        data = bytes(json.dumps(result), self.encoding)
        self.client.setex(url, self.expires, data)


if __name__ == '__main__':
    import time
    start = time.time()
    link_crawler('http://example.python-scraping.com/', '/view', cache=RedisCache())
    print("runing:%s" % (time.time()-start))

  setex 方法,能够使我们在设置键值时附带过期时间。setex 既可以接受 datetime.timedelta,也可以接受以秒为单位的数值。这是一个非常方便的 Redis 功能,可以在指定秒数后自动删除记录。这就意味着我们不再需要像 DiskCache 类那样手工检查记录是否在我们的过期规则内。

  通过测试发现,无缓存时,爬取页面需要2.057s,当存在缓存时,爬取相同页面只需要0.3640s,缓存的效果显而易见。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 下面是一个简单的 Python 代码网站视频的例子: ``` import requests url = "http://example.com/video.mp4" response = requests.get(url) with open("video.mp4", "wb") as f: f.write(response.content) ``` 这段代码使用了 `requests` 库来发送 HTTP 请求,并将响应内容写入到本地文件 `video.mp4` 。 请注意,网站视频可能违反网站的版权政策,并且不合法。请务必尊重网站的政策并遵守相关的法律法规。 ### 回答2: 要用Python网站视频,你可以使用第三方库(例如requests和beautifulsoup)来处理HTTP请求和解析HTML。 首先,你需要使用requests库发送HTTP请求获网页的源代码。你可以使用requests.get()方法,并将目标网页URL作为参数传递给该方法。然后,你可以使用response.text属性来获网页的原始HTML代码。 接下来,你需要使用beautifulsoup库来解析HTML代码,以便找到视频的URL。你可以使用BeautifulSoup()函数,并将之前获得的网页代码作为参数传递给它。然后,你可以使用CSS选择器或XPath表达式在网页找到视频元素。例如,如果视频元素具有特定的标签、类或ID,你可以使用.select()方法或.find()方法来找到它。之后,你可以使用.get()方法来获视频元素的URL属性。 一旦你获得了视频的URL,你可以使用requests库下载视频。你可以使用requests.get()方法,并将视频的URL作为参数传递给该方法。然后,你可以使用response.content属性获视频的二进制数据。 最后,你可以使用Python来保存视频文件。你可以使用open()函数创建一个新文件,然后使用.write()方法将二进制数据写入该文件。记得关闭文件以释放资源。 以上就是使用Python网站视频的基本步骤。当然,在实际应用,你可能需要处理一些异常情况,例如处理缓存、验证、登录等。此外,在下载视频时,请确保你遵循了相关网站的使用条款和法律法规。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值