前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >python爬虫 scrapy爬虫框架的基本使用

python爬虫 scrapy爬虫框架的基本使用

作者头像
叶庭云
修改于 2021-01-23 05:38:23
修改于 2021-01-23 05:38:23
1.6K0
举报
文章被收录于专栏:Python进阶之路Python进阶之路

文章目录

一、scrapy爬虫框架介绍

在编写爬虫的时候,如果我们使用 requests、aiohttp 等库,需要从头至尾把爬虫完整地实现一遍,比如说异常处理、爬取调度等,如果写的多了,的确会比较麻烦。利用现有的爬虫框架,可以提高编写爬虫的效率,而说到 Python 的爬虫框架,Scrapy 当之无愧是最流行最强大的爬虫框架了。

scrapy介绍

Scrapy 是一个基于 Twisted 的异步处理框架,是纯 Python 实现的爬虫框架,其架构清晰,模块之间的耦合程度低,可扩展性极强,可以灵活完成各种需求。我们只需要定制开发几个模块就可以轻松实现一个爬虫。

scrapy爬虫框架的架构如下图所示:

它有如下几个部分:

  • Scrapy Engine(引擎):用来处理整个系统的数据流处理、触发事务,是整个框架的核心。
  • Item(项目):定义了爬取结果的数据结构,爬取的数据会被赋值成该对象。
  • Scheduler(调度器):用来接受引擎发过来的请求并加入队列中,并在引擎再次请求的时候提供给引擎。
  • Item Pipeline(项目管道):负责处理由蜘蛛从网页中抽取的项目,它的主要任务是清洗、验证和存储数据。
  • Downloader(下载器):用于下载网页内容,并将网页内容返回给Spiders。
  • Spiders(蜘蛛):其内定义了爬取的逻辑和网页的解析规则,它主要负责解析响应并生成提取结果和新的请求。
  • Downloader Middlewares(下载器中间件):位于引擎和下载器之间的钩子框架,主要是处理引擎与下载器之间的请求及响应。
  • Spider Middlewares(Spiders中间件):位于引擎和蜘蛛之间的钩子框架,主要工作是处理蜘蛛输入的响应和输出的结果及新的请求。

Scrapy数据流机制

scrapy 中的数据流由引擎控制,其过程如下:

  • Engine 首先打开一个网站,找到处理该网站的 Spider 并向该 Spider 请求第一个要爬取的 URL。
  • Engine 从 Spider 中获取到第一个要爬取的 URL 并通过 Scheduler 以 Request 的形式调度。
  • Engine 向 Scheduler 请求下一个要爬取的 URL。
  • Scheduler 返回下一个要爬取的 URL 给 Engine,Engine 将 URL 通过 Downloader Middlewares 转发给 Downloader 下载。
  • 一旦页面下载完毕, Downloader 生成一个该页面的 Response,并将其通过 Downloader Middlewares 发送给 Engine。
  • Engine 从下载器中接收到 Response 并通过 Spider Middlewares 发送给 Spider 处理。
  • Spider 处理 Response 并返回爬取到的 Item 及新的 Request 给 Engine。
  • Engine 将 Spider 返回的 Item 给 Item Pipeline,将新的 Request 给 Scheduler。
  • 重复第二步到最后一步,直到 Scheduler 中没有更多的 Request,Engine 关闭该网站,爬取结束。

通过多个组件的相互协作、不同组件完成工作的不同、组件很好地支持异步处理,scrapy 最大限度地利用了网络带宽,大大提高了数据爬取和处理的效率。

二、scrapy的安装和创建项目

代码语言:txt
AI代码解释
复制
pip install Scrapy -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

安装方法参考官方文档:https://docs.scrapy.org/en/latest/intro/install.html

安装完成之后,如果可以正常使用 scrapy 命令,那就是安装成功了。

Scrapy是框架,已经帮我们预先配置好了很多可用的组件和编写爬虫时所用的脚手架,也就是预生成一个项目框架,我们可以基于这个框架来快速编写爬虫。

Scrapy框架是通过命令行来创建项目的,创建项目的命令如下:

代码语言:txt
AI代码解释
复制
scrapy startproject practice

命令执行后,在当前运行目录下便会出现一个文件夹,叫作practice,这就是一个Scrapy 项目框架,我们可以基于这个项目框架来编写爬虫。

代码语言:txt
AI代码解释
复制
project/
	__pycache__
	 spiders/
	 	__pycache__
        __init__.py
        spider1.py
        spider2.py
        ...
    __init__.py
    items.py
    middlewares.py
    pipelines.py
    settings.py
scrapy.cfg

各个文件的功能描述如下:

  • scrapy.cfg:它是 Scrapy 项目的配置文件,其内定义了项目的配置文件路径、部署相关信息等内容。
  • items.py:它定义 Item 数据结构,所有的 Item 的定义都可以放这里。
  • pipelines.py:它定义 Item Pipeline 的实现,所有的 Item Pipeline 的实现都可以放这里。
  • settings.py:它定义项目的全局配置。
  • middlewares.py:它定义 Spider Middlewares 和 Downloader Middlewares 的实现。
  • spiders:其内包含一个个 Spider 的实现,每个 Spider 都有一个文件。

三、scrapy的基本使用

实例1:爬取 Quotes
  • 创建一个 Scrapy 项目。
  • 创建一个 Spider 来抓取站点和处理数据。
  • 通过命令行运行,将抓取的内容导出。

目标URL:http://quotes.toscrape.com/

创建项目

创建一个scrapy项目,项目文件可以直接用scrapy命令生成,命令如下所示:

代码语言:txt
AI代码解释
复制
scrapy startproject practice	

创建Spider

Spider是自己定义的类,scrapy用它从网页里抓取内容,并解析抓取的结果。这个类必须继承 Scrapy 提供的Spider类scrapy.Spider,还要定义Spider的名称和起始请求,以及怎样处理爬取后的结果的方法。

使用命令行创建一个Spider,命令如下:

代码语言:txt
AI代码解释
复制
cd practice
scrapy genspider quotes quotes.toscrape.com

切换路径到刚才创建的practice文件夹,然后执行genspider命令。第一个参数是Spider的名称,第二个参数是网站域名。执行完毕之后,spiders 文件夹中多了一个quotes.py,它就是刚刚创建的Spider,内容如下:

代码语言:txt
AI代码解释
复制
import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response):
        pass

可以看到quotes.py里有三个属性——name、allowed_domains 和 start_urls,还有一个方法 parse。

  • name:它是每个项目唯一的名字,用来区分不同的 Spider。
  • allowed_domains:它是允许爬取的域名,如果初始或后续的请求链接不是这个域名下的,则请求链接会被过滤掉。
  • start_urls:它包含了 Spider 在启动时爬取的 url 列表,初始请求是由它来定义的。
  • parse:它是 Spider 的一个方法。默认情况下,被调用时 start_urls 里面的链接构成的请求完成下载执行后,返回的响应就会作为唯一的参数传递给这个函数。该方法负责解析返回的响应、提取数据或者进一步生成要处理的请求。

创建 Item

Item 是保存爬取数据的容器,它的使用方法和字典类似。不过,相比字典,Item 多了额外的保护机制,可以避免拼写错误或者定义字段错误。

创建 Item 需要继承 scrapy.Item 类,并且定义类型为 scrapy.Field 的字段。观察目标网站,我们可以获取到的内容有 text、author、tags。

定义Item,此时进入items.py修改如下:

代码语言:txt
AI代码解释
复制
import scrapy

class QuoteItem(scrapy.Item):
    text = scrapy.Field()
    author = scrapy.Field()
    tags = scrapy.Field()

定义了三个字段,并将类的名称修改为QuoteItem,接下来爬取时会使用到这个 Item。

解析 Response

parse 方法的参数 response 是 start_urls 里面的链接爬取后的结果。所以在 parse 方法中,我们可以直接对 response 变量包含的内容进行解析,比如浏览请求结果的网页源代码,或者进一步分析源代码内容,或者找出结果中的链接而得到下一个请求。

可以看到网页中既有想要提取的数据,又有下一页的链接,这两部分内容都可以进行处理。

首先看看网页结构,如图所示。每一页都有多个 class 为 quote 的区块,每个区块内都包含 text、author、tags。那么我们先找出所有的 quote,然后提取每一个 quote 中的内容。

提取数据的方式可以是 CSS 选择器 或 XPath 选择器

使用 Item

上文定义了 Item,接下来就要使用它了。Item 可以理解为一个字典,不过在声明的时候需要实例化。然后依次用刚才解析的结果赋值 Item 的每一个字段,最后将 Item 返回即可。

代码语言:txt
AI代码解释
复制
import scrapy
from practice.items import QuoteItem


class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response, **kwargs):
        quotes = response.css('.quote')
        for quote in quotes:
            item = QuoteItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item

后续 Request

上面的操作实现了从初始页面抓取内容。实现翻页爬取,这就需要从当前页面中找到信息来生成下一个请求,然后在下一个请求的页面里找到信息再构造下一个请求。这样循环往复迭代,从而实现整站的爬取。

查看网页源代码,可以发现下一页的链接是 /page/2/,但实际上全链接为:http://quotes.toscrape.com/page/2/,通过这个链接就可以构造下一个请求。

构造请求时需要用到 scrapy.Request。这里我们传递两个参数——url 和 callback,这两个参数的说明如下:

  • url:它是请求链接
  • callback:它是回调函数。当指定了该回调函数的请求完成之后,获取到响应,引擎会将该响应作为参数传递给这个回调函数。回调函数进行解析或生成下一个请求,回调函数如上文的 parse() 所示。

由于 parse 就是解析 text、author、tags 的方法,而下一页的结构和刚才已经解析的页面结构是一样的,所以我们可以再次使用 parse 方法来做页面解析。

代码语言:txt
AI代码解释
复制
import scrapy
from practice.items import QuoteItem


class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response, **kwargs):
        quotes = response.css('.quote')
        for quote in quotes:
            item = QuoteItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item
        next_page = response.css('.pager .next a::attr("href")').extract_first()
        next_url = response.urljoin(next_page)
        yield scrapy.Request(url=next_url, callback=self.parse)

运行

接下来,进入目录,运行如下命令:

代码语言:txt
AI代码解释
复制
scrapy crawl quotes -o quotes.csv

命令运行后,项目内多了一个 quotes.csv文件,文件包含了刚才抓取的所有内容。

输出格式还支持很多种,例如 json、xml、pickle、marshal 等,还支持 ftp、s3 等远程输出,另外还可以通过自定义 ItemExporter 来实现其他的输出。

代码语言:txt
AI代码解释
复制
scrapy crawl quotes -o quotes.json
scrapy crawl quotes -o quotes.xml
scrapy crawl quotes -o quotes.pickle
scrapy crawl quotes -o quotes.marshal
scrapy crawl quotes -o ftp://user:pass@ftp.example.com/path/to/quotes.csv

其中,ftp 输出需要正确配置用户名、密码、地址、输出路径,否则会报错。

通过 scrapy 提供的 Feed Exports,我们可以轻松地输出抓取结果到文件,对于一些小型项目来说,这应该足够了。不过如果想要更复杂的输出,如输出到数据库等,可以灵活使用 Item Pileline 来完成。

实例2:爬取图片

目标URL:http://sc.chinaz.com/tupian/dangaotupian.html

创建项目

代码语言:txt
AI代码解释
复制
scrapy startproject get_img
cd get_img
scrapy genspider img_spider sc.chinaz.com

构造请求

img_spider.py 中定义 start_requests() 方法,比如爬取这个网站里的蛋糕图片,爬取页数为10,生成10次请求,如下所示:

代码语言:txt
AI代码解释
复制
    def start_requests(self):
        for i in range(1, 11):
            if i == 1:
                url = 'http://sc.chinaz.com/tupian/dangaotupian.html'
            else:
                url = f'http://sc.chinaz.com/tupian/dangaotupian_{i}.html'
            yield scrapy.Request(url, self.parse)

编写 items.py

代码语言:txt
AI代码解释
复制
import scrapy


class GetImgItem(scrapy.Item):
    img_url = scrapy.Field()
    img_name = scrapy.Field()

编写 img_spider.py

Spider类定义了如何爬取某个(或某些)网站,包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(抓取item)

代码语言:txt
AI代码解释
复制
import scrapy
from get_img.items import GetImgItem


class ImgSpiderSpider(scrapy.Spider):
    name = 'img_spider'

    def start_requests(self):
        for i in range(1, 11):
            if i == 1:
                url = 'http://sc.chinaz.com/tupian/dangaotupian.html'
            else:
                url = f'http://sc.chinaz.com/tupian/dangaotupian_{i}.html'
            yield scrapy.Request(url, self.parse)

    def parse(self, response, **kwargs):
        src_list = response.xpath('//div[@id="container"]/div/div/a/img/@src2').extract()
        alt_list = response.xpath('//div[@id="container"]/div/div/a/img/@alt').extract()
        for alt, src in zip(alt_list, src_list):
            item = GetImgItem()       # 生成item对象
            # 赋值
            item['img_url'] = src
            item['img_name'] = alt
            yield item

编写管道文件 pipelines.py

Scrapy 提供了专门处理下载的 Pipeline,包括文件下载和图片下载。下载文件和图片的原理与抓取页面的原理一样,因此下载过程支持异步和多线程,十分高效。

代码语言:txt
AI代码解释
复制
from scrapy.pipelines.images import ImagesPipeline  # scrapy图片下载器
from scrapy import Request
from scrapy.exceptions import DropItem


class GetImgPipeline(ImagesPipeline):
    # 请求下载图片
    def get_media_requests(self, item, info):
        yield Request(item['img_url'], meta={'name': item['img_name']})

    def item_completed(self, results, item, info):
        # 分析下载结果并剔除下载失败的图片
        image_paths = [x['path'] for ok, x in results if ok]
        if not image_paths:
            raise DropItem("Item contains no images")
        return item

    # 重写file_path方法,将图片以原来的名称和格式进行保存
    def file_path(self, request, response=None, info=None):
        name = request.meta['name']  # 接收上面meta传递过来的图片名称
        file_name = name + '.jpg'  # 添加图片后缀名
        return file_name

在这里实现了 GetImagPipeline,继承 Scrapy 内置的 ImagesPipeline,重写了下面几个方法:

  • get_media_requests()。它的第一个参数 item 是爬取生成的 Item 对象。我们将它的 url 字段取出来,然后直接生成 Request 对象。此 Request 加入调度队列,等待被调度,执行下载。
  • item_completed(),它是当单个 Item 完成下载时的处理方法。因为可能有个别图片未成功下载,所以需要分析下载结果并剔除下载失败的图片。该方法的第一个参数 results 就是该 Item 对应的下载结果,它是一个列表形式,列表每一个元素是一个元组,其中包含了下载成功或失败的信息。这里我们遍历下载结果找出所有成功的下载列表。如果列表为空,那么说明该 Item 对应的图片下载失败了,随即抛出异常DropItem,该 Item 忽略。否则返回该 Item,说明此 Item 有效。
  • file_path(),它的第一个参数 request 就是当前下载对应的 Request 对象。这个方法用来返回保存的文件名,接收上面meta传递过来的图片名称,将图片以原来的名称和定义格式进行保存。

配置文件 settings.py

代码语言:txt
AI代码解释
复制
# setting.py

BOT_NAME = 'get_img'

SPIDER_MODULES = ['get_img.spiders']
NEWSPIDER_MODULE = 'get_img.spiders'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# Configure maximum concurrent requests performed by Scrapy (default: 16)
CONCURRENT_REQUESTS = 32

# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 0.25

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'get_img.pipelines.GetImgPipeline': 300,
}

IMAGES_STORE = './images'   # 设置保存图片的路径 会自动创建

运行程序:

代码语言:txt
AI代码解释
复制
# 切换路径到img_spider的目录
scrapy crawl img_spider

scrapy框架爬虫一边爬取一边下载,下载速度非常快。

查看本地 images 文件夹,发现图片都已经成功下载,如图所示:

到现在为止我们就大体知道了 Scrapy 的基本架构并实操创建了一个 Scrapy 项目,编写代码进行了实例抓取,熟悉了scrapy爬虫框架的基本使用。之后还需要更加详细地了解和学习scrapy的用法,感受它的强大。

作者:叶庭云 微信公众号:修炼Python CSDN:https://yetingyun.blog.csdn.net/ 本文仅用于交流学习,未经作者允许,禁止转载,更勿做其他用途,违者必究。 觉得文章对你有帮助、让你有所收获的话,期待你的点赞呀,不足之处,也可以在评论区多多指正。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/08/27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
ES6 主要的新特性
本文基于lukehoban/es6features ,同时参考了大量博客资料,具体见文末引用。 ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony(和谐之意,显然没有跟上我国的步伐,我们已经进入中国梦版本了)。上一次标准的制订还是2009年出台的ES5。目前ES6的标准化工作正在进行中,预计会在14年12月份放出正式敲定的版本。但大部分标准已经就绪,且各浏览器对ES6的支持也正在实现中。要查看ES6的支持情况请点此。 目前想要运行ES6代码的话,可以用go
庞小明
2018/03/09
1K0
ECMAScript 6 新特性总结
个人感觉ECMAScript 6总体上来说:添加了块级作用域,增加了一些语法糖,增强了字符串的处理,引入Generator函数控制函数的内部状态的变化,原生提供了Promise对象,引入了Class(类)的概念,并且在语言规格的层面上实现了模块功能。 注:
IMWeb前端团队
2019/12/03
8520
(转)ES6新特性概览
ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony(和谐之意,显然没有跟上我国的步伐,我们已经进入中国梦版本了)。上一次标准的制订还是2009年出台的ES5。目前ES6的标准化工作正在进行中,预计会在14年12月份放出正式敲定的版本。但大部分标准已经就绪,且各浏览器对ES6的支持也正在实现中。要查看ES6的支持情况请点此。 目前想要运行ES6代码的话,可以用google/traceur-compiler将代码转译。点此访问traceur-compiler
前端黑板报
2018/01/29
9710
ES6 常用知识总结
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
EchoROne
2022/08/15
5490
重读 ES6 标准入门(第3版)
仅将自己的理解做整理、归类并结合实际遇到的问题做记录,更推荐阅读 ECMAScript 6 入门。
掘金安东尼
2024/01/28
1640
es6入门
es6作为最新的js语言版本,有很多特性是不得不晓的。下面将语法中常用的分析出来,对应到基本对象类型的会在对象里描述。
RobinsonZhang
2018/08/28
5660
ECMAScript 6 学习笔记
IMWeb前端团队
2017/12/29
9100
es6学习笔记
ECMAScript 6.0( 以下简称ES6) 是JavaScript语言的下一代标准。
earthchen
2020/09/24
9920
用简单的方法学习ECMAScript 6
这里是ECMAScript 6 简要概览 本文大量参考了es6特性代码仓库,请允许我感谢其作者Luke Hoban的卓越贡献,也感谢Axel Rauschmayer所作的优秀书籍。
疯狂的技术宅
2019/03/28
1.8K0
用简单的方法学习ECMAScript 6
ES6新特性概览
前言 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。 标准的制定者有计划,以后每年发布一次标准,使用年份作为标准的版本。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。也就是说,ES6就是ES2015,下一年应该会发布小幅修订的ES2016。 废话不多说,直接开始介绍ES6中的新特性,让你一睹新生代JS的风采。
laixiangran
2018/04/11
1K0
ES6的语法
世间万物皆对象
2024/03/20
1930
1w5000字概括ES6全部特性
第三次阅读阮一峰老师的《ECMAScript 6 入门》了,以前阅读时不细心,很多地方都是一目十行。最近这次阅读都是逐个逐个字来读,发现很多以前都没有注意到的知识点,为了方便记忆和预览全部ES6特性,所以写下本文。
前端迷
2020/02/25
1.7K0
从ES6到ES10的新特性万字大总结(不得不收藏)
ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会)在标准ECMA-262中定义的脚本语言规范。这种语言在万维网上应用广泛,它往往被称为JavaScript或JScript,但实际上后两者是ECMA-262标准的实现和扩展。
陈大鱼头
2020/04/16
2.4K0
ES6总结
var命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。
愤怒的小鸟
2020/12/15
5950
ES6
在cmd命令窗口初始化项目-y代表全部默认同意,就不用一次次按回车了。命令执行完成后,会在项目根目录下生产package.json文件。
楠楠
2018/09/11
2.8K0
ES6面试、复习干货知识点汇总
https://juejin.cn/post/6844903734464495623
@超人
2021/07/29
5550
Babel下的ES6兼容性与规范
IMWeb前端团队
2017/12/28
2.1K0
前端面试必备ES6全方位总结
学习ES6需要掌握的路线,了解什么是ECMAScript概述,了解Symbol数据类型,掌握let和const,以及变量的解构赋值,Set和Map的原理。
达达前端
2022/04/13
1.3K0
前端面试必备ES6全方位总结
「建议收藏」送你一份精心总结的3万字ES6实用指南(上)
写本篇文章目的是为了夯实基础,基于阮一峰老师的著作 ECMAScript 6 入门 以及 tc39-finished-proposals 这两个知识线路总结提炼出来的重点和要点,涉及到从 ES2015 到 ES2021 的几乎所有知识,基本上都是按照一个知识点配上一段代码的形式来展示,所以篇幅较长,也正是因为篇幅过长,所以就没把 Stage 2 和 Stage 3 阶段的提案写到这里,后续 ES2021 更新了我再同步更新。
用户4456933
2021/06/01
8650
「建议收藏」送你一份精心总结的3万字ES6实用指南(上)
学习ES6 你必须知道的新特性!!关于数组的扩展
扩展运算符(spread)是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
我只会写Bug啊
2023/12/25
1570
相关推荐
ES6 主要的新特性
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档