你也可以手敲一个高速下载器(十二)使用解析器

99 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情


你也可以手敲一个高速下载器(十二)使用解析器

前言

我们上一节写了一个cUrl解析器,这一节就来把他用在我们的下载器中,让我们的下载器更加智能化

开始编码

我们先按照正常的常规的操作把Curl解析类引入进入并在__init__函数中进行初始化,代码如下:

    def __init__(
            self,
            url: str,
            *,
            save_path: str = None,
            save_name: str = None,
            concurrency: int = 64,
            headers: dict = None,
            method: str = None,
            data: dict = None
    ):
        """
        :param url: 要下载的地址
        :param save_path: 保存的文件路径
        :param save_path: 保存的文件名字
        :param concurrency: 并发的数量
        :param headers: 请求头
        :param method: 请求方法
        :param data: 请求的数据
        """
        # 解析curl字符串
        parser = CurlParser(url)
        self.url = parser.url
        self.headers = parser.headers or headers or {}
        self.method = parser.method or method or "GET"
        self.data = parser.data or data or {}

我们增加了两个参数,并且使用url初始化了解析器,在后面初始化属性的时候我们依次使用了解析了参数->传来的参数->默认值,这个来确保不会出问题。好了,接下来终端执行脚本的时候把url参数内容换成curl内容就好了,让我们来试一下:

开始失败

让我们来预测一下结果,看看会不会如我们预想的那样,直接成功:

可以看到,果然失败, 原因大家有应该也有所猜测,就是参数是很多行,而且里面既包含了单引号也包含了双引号,所以我们也没办法用双引号包裹内容的方式去解决这个问题。

解决问题

但已经走到了这一步了,肯定不能因为这点困难就放弃,所以经过一番思考和搜索有以下几种方案:

  • 既然是因为命令行参数有换行、引号的问题,那么我就让他没有这个就好了,比如把浏览器复制好的curl字符串转换成base64字符串,这样就可以被命令所识别了
  • 既然直接是经过命令无法直接输入,那么我们也可以把复制好的curl字符串保存成文件,然后我们直接读取文件即可
  • 问题是程序的输入参数无法正确识别,那么如果换成input方法输入呢?这个自由度更高一点,我们可以更好的去控制

我们上面提到了三种方案,都是可以解决问题的,但是我感觉前面两种方案都太麻烦了,用户使用起来需要去其他地方去转换编码或手动的去创建文件,太不优雅了,所以还是使用第三种方案

使用input方法

我们都知道input默认也输入一行的,也就是输入完一行后按回车键自动结束并返回输入的结果,这是与我们的需求不相符合的。这里会用到iter的另一种用法,众所周知,iter是用来迭代一个已经实现__next__方法的对象的,但是要注意的是这个方法使用第二个参数,而这个参数正是决定了使用方法的不同,我们来看下官方文档:

返回一个 iterator 对象。根据是否存在第二个实参,第一个实参的解释是非常不同的。如果没有第二个实参,object 必须是支持 iterable 协议(有 __iter__() 方法)的集合对象,或必须支持序列协议(有 __getitem__() 方法,且数字参数从 0 开始)。如果它不支持这些协议,会触发 TypeError。如果有第二个实参 sentinel,那么 object 必须是可调用的对象。这种情况下生成的迭代器,每次迭代调用它的 __next__() 方法时都会不带实参地调用 object;如果返回的结果是 sentinel 则触发 StopIteration,否则返回调用结果。

也就是说我们可以把input作为第一个参数,而第二个参数则定义一个停止的条件,然后把每次迭代的结果放在一起即可,代码如下:

        lines = []
    	print("请输入从浏览器复制的curl字符串,并输入:wq结束:", end='')
        for line in iter(input, ':wq'):
            lines.append(line)
        url = ''.join(lines).replace('\\', ' ')

这里我们使用:wq来结束输入,也是借鉴了vim中结束的语法,让大家更熟悉而已。

但是大家可能注意到了,这样用input就没办法使用参数了,也就没有提示了,这时大家可能会想到我们前面提到的偏函数,就可以把参数输入进去了,但我们要注意的一点是:这个函数的本质是循环调用input函数,也就是如果使用偏函数加了默认的参数,那么就会出现每一行都会出现提示的效果,这样显然不是我们想要的

print的end参数

所以这里我们就直接使用print参数打印想要提示的字符串,然后把print函数的end参数设置为:''空字符串,这个参数默认是\n换行符的,也就是输出一行后会默认换行,而我们不想换行所以,所以直接使用空字符串,

代码仓库:

本节的代码以上传至 Github,请自行下载及观看:第十二节代码

结语

这个curl解析器算了说完了,我们从需要分析到技术选择到敲代码一步一步为我们的下载器添加了一个智能化的快捷功能。下节更精彩,敬请期待!!!