【进阶】【Python网络爬虫】【15.爬虫框架】scrapy入门(附大量案例代码)(建议收藏)

一、爬虫框架

1. 什么是框架?

所谓的框架,其实说白了就是一个【项目的半成品】,该项目的半成品需要被集成了各种功能且具有较强的通用性。

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,非常出名,非常强悍。所谓的框架就是一个已经被集成了各种功能(高性能异步下载,队列,分布式,解析,持久化等)的具有很强通用性的项目模板。对于框架的学习,重点是要学习其框架的特性、各个功能的用法即可。

2. 初期如何学习框架?

只需要学习框架集成好的各种功能的用法即可!前期切勿钻研框架的源码!

二、scrapy 入门

1. 网络爬虫

网络爬虫是指在互联网上自动爬取网站内容信息的程序,也被称作网络蜘蛛或网络机器人。大型的爬虫程序被广泛应用于搜索引擎、数据挖掘等领域,个人用户或企业也可以利用爬虫收集对自身有价值的数据。

一个网络爬虫程序的基本执行流程可以总结三个过程:请求数据解析数据保存数据

请求数据

请求的数据除了普通的HTML之外,还有 json 数据、字符串数据、图片、视频、音频等。

解析数据

当一个数据下载完成后,对数据中的内容进行分析,并提取出需要的数据,提取到的数据可以以多种形式保存起来,数据的格式有非常多种,常见的有csv、json、pickle等

保存数据

最后将数据以某种格式(CSV、JSON)写入文件中,或存储到数据库(MySQL、MongoDB)中。同时保存为一种或者多种。

  • 通常,我们想要获取的数据并不只在一个页面中,而是分布在多个页面中,这些页面彼此联系,一个页面中可能包含一个或多个到其他页面的链接,提取完当前页面中的数据后,还要把页面中的某些链接也提取出来,然后对链接页面进行爬取(循环1-3步骤)。

  • 设计爬虫程序时,还要考虑防止重复爬取相同页面(URL去重)、网页搜索策略(深度优先或广度优先等)、爬虫访问边界限定等一系列问题。

  • 从头开发一个爬虫程序是一项烦琐的工作,为了避免因制造轮子而消耗大量时间,在实际应用中我们可以选择使用一些优秀的爬虫框架,使用框架可以降低开发成本,提高程序质量,让我们能够专注于业务逻辑(爬取有价值的数据)。接下来,就带你学习目前非常流行的开源爬虫框架Scrapy

2. scrapy安装

scrapy官网: https://scrapy.org/
scrapy中文文档:https://www.osgeo.cn/scrapy/intro/overview.html

安装方式

在任意操作系统下,可以使用pip安装Scrapy,例如:

Linux/mac系统:

  • pip install scrapy(任意目录下)

Windows系统:可以直接pip install scrapy安装,如果安装出错可以采用如下方式:

  • 1.pip install wheel (任意目录下)
  • 2.下载 twisted 文件,下载网址如下: http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
  • 3.终端进入下载目录,执行 pip install Twisted-17.1.0-cp35-cp35m-win_amd64.whl
    注意:如果该步骤安装出错,则换一个版本的 whl 文件即可
  • 4.pip install pywin32 (任意目录下)

如果安装好后,在终端中录入 scrapy 指令按下回车,如果没有提示找到该指令,则表示安装成功

安装完成后我们需要测试安装是否成功,通过如下步骤确认:

  • 在 终端 中测试能否执行 scrapy 这条命令:
Scrapy 2.4.0 - no active project

Usage:
  scrapy <command> [options] [args]

Available commands:
  bench				Run quick benchmark test
  fetch				Fetch a URL using the Scrapy downloader
  genspider			 Generate new spider using pre-defined templates
  runspider			 Run a self-contained spider (without creating a project)
  settings			 Get settings values
  shell				Interactive scraping console
  startproject		  Create new project
  version			 Print Scrapy version
  view				Open URL in browser, as seen by Scrapy

  [ more ]      More commands available when run from project directory

Use "scrapy <command> -h" to see more info about a command
  • 输入 scrapy bench 测试连通性,如果出现以下情况表示安装成功:

在这里插入图片描述
通过了以上两项检测,说明Scrapy安装成功了。如上所示,我们安装的是当前最新版本2.4.0。

注意:
成功安装后,在CMD下运行scrapy出现上图不算真正成功,检测真正是否成功使用scrapy bench测试,如果没有提示错误,就代表成功安装。

具体Scrapy安装流程参考:http://doc.scrapy.org/en/latest/intro/install.html##intro-install-platform-notes 里面有各个平台的安装方法

全局命令

Scrapy 2.4.0 - no active project

Usage:
  scrapy <command> [options] [args]

Available commands:
  bench				Run quick benchmark test
  				   # 测试电脑性能
  fetch				Fetch a URL using the Scrapy downloader
  				   # 将源代码下载下来并显示出来
  genspider			 Generate new spider using pre-defined templates
  				   # 创建一个新的 spider 文件
  runspider			 Run a self-contained spider (without creating a project)
  				   # 这个和通过crawl启动爬虫不同,scrapy runspider 爬虫文件名称
  settings			 Get settings values
  				   # 获取当前的配置信息
  shell				Interactive scraping console
  				   # 进入 scrapy 的交互模式
  startproject		  Create new project
  					# 创建爬虫项目
  version			 Print Scrapy version
  					# 显示scrapy框架的版本
  view				Open URL in browser, as seen by Scrapy
  					# 将网页document内容下载下来,并且在浏览器显示出来

  [ more ]      More commands available when run from project directory

Use "scrapy <command> -h" to see more info about a command

项目命令

  • scrapy startproject projectname项目名称
## 创建一个项目
firstBlood   # 项目所在文件夹, 建议用pycharm打开该文件夹
    ├── firstBlood  		# 项目跟目录
    │   ├── __init__.py
    │   ├── items.py  		# 封装数据的格式
    │   ├── middlewares.py  # 所有中间件
    │   ├── pipelines.py	# 所有的管道
    │   ├── settings.py		# 爬虫配置信息
    │   └── spiders			# 爬虫文件夹, 稍后里面会写入爬虫代码
    │       └── __init__.py
    └── scrapy.cfg			# scrapy项目配置信息,不要删它,别动它,善待它. 
  • cd project_name(进入项目目录)

  • scrapy genspider 爬虫文件的名称 (自定义一个名字即可) 起始url (随便写一个网址即可)

    创建好爬虫项目以后,还需要创建爬虫。

  • scrapy crawl spidername

    运行爬虫。注意该命令运行时所在的目录

案例 - scrapy 下厨房网爬取
settings.py
BOT_NAME = "First"

SPIDER_MODULES = ["First.spiders"]
NEWSPIDER_MODULE = "First.spiders"
# 指定输出的日志类型
LOG_LEVEL = 'ERROR'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

REQUEST_FINGERPRINTER_IMPLEMENTATION = "2.7"
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
FEED_EXPORT_ENCODING = "utf-8"
spiders
blood.py
import scrapy

class BloodSpider(scrapy.Spider):
    # 爬虫文件的唯一标识
    name = "blood"
    # 允许的域名
    allowed_domains = ["www.baidu.com"]
    # 起始的 url 列表(重要):列表内部的 url 都会被框架进行异步的请求发送
    start_urls = ["https://www.xiachufang.com/category/40076/"]

    # 数据解析 : parse 调用的次数取决于 start_urls 列表元素的个数
    def parse(self, response):  # response 参数就表示响应对象
        # 如何实现数据解析 : Xpath
        li_list = response.xpath('/html/body/div[4]/div/div/div[1]/div[1]/div/div[2]/div[2]/ul/li')

        for li in li_list:
            # xpath 最终会返回的是 Selector 对象,想要的解析的数据是存储在该对象的 data 属性中(extract可以实现该功能)
            # title = li.xpath('./div/div/p[1]/a/text()')[0].extract()  # 一般不用

            # extract_first 可以将 xpath 返回类别中的第一个 Selector 对象中的 data 属性值获取
            # title = li.xpath('./div/div/p[1]/a/text()').extract_first()

            # extract 可以将 xpath 返回列表中的每一个 Selector 对象中的 data 属性值获取
            title = li.xpath('./div/div/p[1]/a/text()').extract()
            # 如果 xpath 返回的列表元素只有一个则使用 extract_first ,否则使用 extract
            print(title)
案例 - scrapy爬取哔哩哔哩网
settings.py
BOT_NAME = "biliPro"

SPIDER_MODULES = ["biliPro.spiders"]
NEWSPIDER_MODULE = "biliPro.spiders"

# 指定输出的日志类型
LOG_LEVEL = 'ERROR'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"

# Obey robots.txt rules
ROBOTSTXT_OBEY = False


REQUEST_FINGERPRINTER_IMPLEMENTATION = "2.7"
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
FEED_EXPORT_ENCODING = "utf-8"
items.py
import scrapy

class BiliproItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()
pipelines.py
# 存储 txt 文件
class BiliproPipeline:# 一个管道类只负责将数据存储到一个载体中
    fp = None

    # 全程只会被调用一次
    def open_spider(self, spider):
        print('i am open_spider()')
        self.fp = open('bili.txt', 'w')

    # process_item 函数就是用来接受爬虫文件提交过来的item对象,且可以将item对象中的数据存储到任何载体中
    def process_item(self, item, spider):  # 参数 item 就是管道接收到item对象
        title = item['title']
        author = item['author']
        # 数据存储到文件里
        self.fp.write(author + ':' + title + '\n')
        return item

    # process_item 函数调用的次数取决于爬虫文件给管道提交的 item 的次数

    def close_spider(self, spider):
        print('i am close_spider()')
        # 该函数只会在爬虫结束前被调用一次
        self.fp.close()
iders
libi.py - 基于终端指令的持久化存储(简单)不推荐
import scrapy

class LibiSpider(scrapy.Spider):
    name = "libi"
    allowed_domains = ["www.xxx.com"]
    start_urls = [
        "https://search.bilibili.com/all?keyword=%E5%AE%8F%E8%A7%82%E7%BB%8F%E6%B5%8E&from_source=webtop_search&spm_id_from=333.1007&search_source=5"]

    # 基于终端指令的持久化存储(简单):只可以将 parse 方法的返回值存储写入到指定后缀的文本文件中
    def parse(self, response):
        div_list = response.xpath('//*[@id="i_cecream"]/div/div[2]/div[2]/div/div/div/div[3]/div/div')
        all_data = []
        for div in div_list:
            title = div.xpath('./div/div[2]/div/div/a/h3/text()').extract()
            title = ''.join(title)
            author = div.xpath('./div/div[2]/div/div/p/a/span[1]/text()').extract_first()

            dic = {
                'title': title,
                'author': author,
            }

            all_data.append(dic)
        return all_data  # all_data里面就存储了爬取到的数据
    
 # 指令 scrapy crawl bili -o bili.csv
libi,py - 基于管道的持久化存储方式(通用)
import scrapy

from ..items import BiliproItem

class LibiSpider(scrapy.Spider):
    name = "libi"
    allowed_domains = ["www.xxx.com"]
    start_urls = [
        "https://search.bilibili.com/all?keyword=%E5%AE%8F%E8%A7%82%E7%BB%8F%E6%B5%8E&from_source=webtop_search&spm_id_from=333.1007&search_source=5"]

    # 基于管道的持久化存储方式(通用)
    def parse(self, response):
        div_list = response.xpath('//*[@id="i_cecream"]/div/div[2]/div[2]/div/div/div/div[3]/div/div')
        all_data = []
        for div in div_list:
            title = div.xpath('./div/div[2]/div/div/a/h3/text()').extract()
            title = ''.join(title)
            author = div.xpath('./div/div[2]/div/div/p/a/span[1]/text()').extract_first()

            # 创建一个 item 类型的对象
            item = BiliproItem(title=title, author=author)
            yield item

    # 编码流程:1.解析数据 2.创建一个 item 类的对象(存储解析出来的数据)3.将解析出来的数据存储到该 item 类型的对象中 4.将item对象提交给管道

    # 爬虫文件:libi.py  进行请求发送和数据解析
    # item文件: items.py  定义n个变量
    # 管道文件: pipelines.py  接收item对象进行数据持久化存储
案例 - scrapy数据保存到数据库
  • 如何将数据存储到数据库
    • 注意:一个管道类负责将数据存储到一个具体的载体中。如果想要将爬取到的数据存储到多个不同的载体/数据库中,则需要定义多个管道类。
  • 思考:
    • 在有多个管道类的前提下,爬虫文件提交的item会同时给每一个管道类还是单独的管道类?
      • 爬虫文件只会将item提交给优先级最高的那一个管道类。优先级最高的管道类的process_item中需要写return item操作,该操作就是表示将item对象传递给下一个管道类,下一个管道类获取了item对象,才可以将数据存储成功!
settings.py
BOT_NAME = "biliPro"
SPIDER_MODULES = ["biliPro.spiders"]
NEWSPIDER_MODULE = "biliPro.spiders"

# 指定输出的日志类型
LOG_LEVEL = 'ERROR'

USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

ITEM_PIPELINES = {
   # value 值表示的数字代表了管道类的优先级,数字越小表示优先级越高
   "biliPro.pipelines.BiliproPipeline": 300,
   "biliPro.pipelines.MysqlPipeline": 301,
   "biliPro.pipelines.RedisPipeLine": 302,
   "biliPro.pipelines.MongoPipeline": 303,
}

REQUEST_FINGERPRINTER_IMPLEMENTATION = "2.7"
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
FEED_EXPORT_ENCODING = "utf-8"
items.py
import scrapy

class BiliproItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()
pipelines.py
import pymysql  # pip install pymysql

''' 第一个管道类:存储 txt 文件 '''
class BiliproPipeline:  # 一个管道类只负责将数据存储到一个载体中
    fp = None

    # 全程只会被调用一次
    def open_spider(self, spider):
        print('i am open_spider()')
        self.fp = open('bili.txt', 'w')

    # process_item 函数就是用来接受爬虫文件提交过来的item对象,且可以将item对象中的数据存储到任何载体中
    def process_item(self, item, spider):  # 参数 item 就是管道接收到item对象
        title = item['title']
        author = item['author']
        # 数据存储到文件里
        self.fp.write(author + ':' + title + '\n')
        return item

    # process_item 函数调用的次数取决于爬虫文件给管道提交的 item 的次数

    def close_spider(self, spider):
        print('i am close_spider()')
        # 该函数只会在爬虫结束前被调用一次
        self.fp.close()


''' 第二个管道类:存储到 mysql 数据库 '''
class MysqlPipeline:
    conn = None  # 链接对象
    cursor = None  # 游标对象

    def open_spider(self, spider):
        # 链接数据库的操作只需要被执行一次
        self.conn = pymysql.Connect(
            host='127.0.0.1',  # mysql 数据库服务器的ip地址
            port=3306,  # 端口号
            user='root',  # 用户名
            password='root',  # 密码
            db='spider',  # 数据仓库名称
        )
        # 创建一个游标对象(用来使用python程序执行sql语句)
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):  # 参数 item 就是管道接收到item对象,由上级优先级高的管道类传递过来
        title = item['title']
        author = item['author']
        # 使用游标对象 cursor 执行 sql语句
        sql = 'insert into bili values ("%s","%s")' % (title, author)
        self.cursor.execute(sql)
        # 提交事物
        self.conn.commit()
        return item

    def close_spider(self, spider):
        self.conn.close()
        self.cursor.close()
        
        
''' 第三个管道类:存储 Redis 数据库 '''
class RedisPipeLine:
    conn = None

    def open_spider(self, spider):
        # 创建 redis 的链接对象
        self.conn = Redis(
            host='127.0.0.1',
            port=3308
        )

    def process_item(self, item, spider):  # 参数 item 就是管道接收到item对象,由上级优先级高的管道类传递过来
        # item 本身就是一个字典
        self.conn.lpush('libi', item)
        return item

    def close_spider(self, spider):
        pass


''' 第四个管道类:存储 MongoDB 数据库 '''
import pymongo
class MongoPipeline:
    conn = None  # 链接对象
    db_sanqi = None  # 数据仓库

    def open_spider(self, spider):
        self.conn = pymongo.MongoClient(
            host='127.0.0.1',
            port=27017
        )
        self.db_sanqi = self.conn['sanqi']

    def process_item(self, item, spider):
        self.db_sanqi['xiaoshuo'].insert_one({'title': item['title']})
        print('插入成功!')
        return item
spiders
libi.py
import scrapy

from ..items import BiliproItem


class LibiSpider(scrapy.Spider):
    name = "libi"
    allowed_domains = ["www.xxx.com"]
    start_urls = [
        "https://search.bilibili.com/all?keyword=%E5%AE%8F%E8%A7%82%E7%BB%8F%E6%B5%8E&from_source=webtop_search&spm_id_from=333.1007&search_source=5"]

    # 基于管道的持久化存储方式(通用)
    def parse(self, response):
        div_list = response.xpath('//*[@id="i_cecream"]/div/div[2]/div[2]/div/div/div/div[3]/div/div')
        all_data = []
        for div in div_list:
            title = div.xpath('./div/div[2]/div/div/a/h3/text()').extract()
            title = ''.join(title)
            author = div.xpath('./div/div[2]/div/div/p/a/span[1]/text()').extract_first()

            # 创建一个 item 类型的对象
            item = BiliproItem(title=title, author=author)
            yield item  # item会提交给那个管道类?一定是提交给优先级最高的管道类!!

    # 编码流程:1.解析数据 2.创建一个 item 类的对象(存储解析出来的数据)3.将解析出来的数据存储到该 item 类型的对象中 4.将item对象提交给管道

    # 爬虫文件:libi.py  进行请求发送和数据解析
    # item文件: items.py  定义n个变量
    # 管道文件: pipelines.py  接收item对象进行数据持久化存储
  1. 在爬虫文件中进行数据爬取和数据解析
  2. 在 items.py 文件中进行相关变量的定义(变量的个数取决于爬虫文件中解析字段的个数)
  3. 在爬虫文件中将解析到的数据存储到item类型的对象中
  4. 将 item 类型的对象提交给管道
  5. 管道的 process_item 函数中接收item对象,且将 item 对象的数据存储到指定的平台或者载体中
  6. 在配置文件中开启管道的机制
案例 - scrapy爬取二进制数据

使用一个专有的管道类ImagesPipeline

  • http://pic.netbian.com/4kmeinv/

首先安装插件 : pip install PIL / pip install Pillow

  • 具体的编码流程:
    • 1.在爬虫文件中进行图片/视频的链接提取
    • 2.将提取到的链接封装到items对象中,提交给管道
    • 3.在管道文件中自定义一个父类为ImagesPipeline的管道类,且重写三个方法即可:
def get_media_requests(self, item, info):接收爬虫文件提交过来的item对象,然后对图片地址发起网路请求,返回图片的二进制数据

def file_path(self, request, response=None, info=None, *, item=None):指定保存图片的名称
def item_completed(self, results, item, info):返回item对象给下一个管道类
settings.py
BOT_NAME = "imgPro"

SPIDER_MODULES = ["imgPro.spiders"]
NEWSPIDER_MODULE = "imgPro.spiders"

# 指定输出的日志类型
LOG_LEVEL = 'ERROR'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False
IMAGES_STORE = 'girlsLib'

ITEM_PIPELINES = {
    "imgPro.pipelines.BytesPipeLine": 300,
}

REQUEST_FINGERPRINTER_IMPLEMENTATION = "2.7"
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
FEED_EXPORT_ENCODING = "utf-8"
items.py
import scrapy

class ImgproItem(scrapy.Item):
    img_src = scrapy.Field()
pipelines.py
import scrapy
from scrapy.pipelines.images import ImagesPipeline

# 普通的管道类:将文本数据持久化
class ImgproPipeline:
    def process_item(self, item, spider):
        return item

# 特殊的管道类:将二进制数据持久化
# 自定义了一个管道类,该类的父类为 ImagesPipeline
class BytesPipeLine(ImagesPipeline):
    # 重写三个父类的方法来完成图片二进制数据的请求和持久化存储
    # 可以根据图片地址,对其进行请求,获取图片数据
    # 接收爬虫文件提交过来的item对象,并且可以对相关的多媒体资源进行网络请求
    def get_media_requests(self, item, info):
        # 提取图片地址或者视频地址
        img_src = item['img_src']
        # 可以对 img_src 进行网络请求获取图片数据
        yield scrapy.Request(img_src)

    def file_path(self, request, response=None, info=None, *, item=None):  # 指定保存图片的名称
        # 用来将请求到的多媒体数据进行指定路径的存储
        # 返回存储文件的名字
        img_src = request.url  # 图片地址
        img_title = img_src.split('/')[-1]
        print(img_title, '下载保存成功!')
        return img_title

    # 如果没有下一个管道类,该方法可以不写
    def item_completed(self, results, item, info):  # 返回item对象给下一个管道类
        return item  # 可以将当前的管道类接收到item对象传递给下一个管道类2.
spiders
img.py
import scrapy
from ..items import ImgproItem

class ImgSpider(scrapy.Spider):
    name = "img"
    # allowed_domains = ["www.xxx.com"]
    start_urls = ["http://pic.netbian.com/4kmeinv/"]

    def parse(self, response):
        # 解析图片地址
        li_list = response.xpath('//*[@id="main"]/div[3]/ul/li')
        for li in li_list:
            img_src = 'http://pic.netbian.com' + li.xpath('./a/img/@src').extract_first()
            # 图片地址封装到item对象中,且将item提交给管道即可
            item = ImgproItem(img_src=img_src)
            print(item)
            yield item
            # 特殊的管道类:主要是对二进制的数据进行持久化存储
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python网络爬虫框架Scrapy入门到精通》是一本非常实用的教材,它全面介绍了Scrapy框架的使用方法和技巧,适合各种程度的Python开发者学习和使用。 该书首先从入门级内容开始,介绍了Scrapy的基本概念、安装和配置,以及如何创建一个最简单的爬虫。接着,逐步深入介绍了Scrapy的核心组成部分,包括如何定义Item、编写Spider、使用Pipeline等。通过丰富的示例代码和详细解释,读者可以快速掌握Scrapy的基本用法。 除了基础知识,该书还详细介绍了Scrapy的高级特性和扩展能力。比如,如何处理动态网页、如何利用Scrapy行数据清洗和处理、如何使用中间件和扩展Scrapy的功能等等。这些内容对于想要行更复杂网页爬取和数据处理的开发者非常有帮助。 除了框架本身的介绍外,该书还强调了Scrapy开发中的一些实践经验和技巧。比如,如何设计良好的爬虫结构、如何处理反爬虫措施、如何设置合理的请求频率等。这些经验可以帮助开发者更高效地开展爬虫工作,避免一些常见的问题。 总的来说,《Python网络爬虫框架Scrapy入门到精通》是一本非常实用的教材,能够帮助读者系统学习和掌握Scrapy框架的使用。无论是对于初学者还是有一定经验的开发者,都值得一读。对于想要从事网络爬虫开发的人来说,这本书是一份不可多得的宝藏。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

My.ICBM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值