【Go】变量

变量是什么 变量指定了某存储单元(Memory Location)的名称,该存储单元会存储特定类型的值。在 Go 中,有多种语法用于声明变量。 声明单个变量 var name type 是声明单个变量的语法。 package main import "fmt" func main() { var age int // 变量声明 fmt.Println("my age is", age) } 语句 var age int 声明了一个 int 类型的变量,名字为 age。我们还没有给该变量赋值。如果变量未被赋值,Go 会自动地将其初始化,赋值该变量类型的零值(Zero Value)。本例中 age 就被赋值为 0。如果你运行该程序,你会看到如下输出: my age is 0 变量可以赋值为本类型的任何值。上一程序中的 age 可以赋值为任何整型值(Integer Value)。 package main import "fmt" func main() { var age int // 变量声明 fmt.Println("my age is", age) age = 29 // 赋值 fmt.Println("my age is", age) age = 54 // 赋值 fmt.Println("my new age is", age) } 上面的程序会有如下输出: ...

2019年12月9日 · 3 分钟

【Go】常量

定义 在 Go 语言中,术语"常量"用于表示固定的值。比如 5 、-89、 I love Go、67.89 等等。 看看下面的代码: var a int = 50 var b string = "I love Go" 在上面的代码中,变量 a 和 b 分别被赋值为常量 50 和 I love GO。关键字 const 被用于表示常量,比如 50 和 I love Go。即使在上面的代码中我们没有明确的使用关键字 const,但是在 Go 的内部,它们是常量。 顾名思义,常量不能再重新赋值为其他的值。因此下面的程序将不能正常工作,它将出现一个编译错误: cannot assign to a.。 package main func main() { const a = 55 // 允许 a = 89 // 不允许重新赋值 } 常量的值会在编译的时候确定。因为函数调用发生在运行时,所以不能将函数的返回值赋值给常量。 package main import ( "fmt" "math" ) func main() { fmt.Println("Hello, playground") var a = math.Sqrt(4) // 允许 const b = math.Sqrt(4) // 不允许 } 在上面的程序中,因为 a 是变量,因此我们可以将函数 math.Sqrt(4) 的返回值赋值给它(我们将在单独的地方详细讨论函数)。 ...

2019年12月9日 · 3 分钟

【Go】函数

函数是什么? 函数是一块执行特定任务的代码。一个函数是在输入源基础上,通过执行一系列的算法,生成预期的输出。 函数的声明 在 Go 语言中,函数声明通用语法如下: func functionname(parametername type) returntype { // 函数体(具体实现的功能) } 函数的声明以关键词 func 开始,后面紧跟自定义的函数名 functionname (函数名)。函数的参数列表定义在 ( 和 ) 之间,返回值的类型则定义在之后的 returntype (返回值类型)处。声明一个参数的语法采用 参数名 参数类型 的方式,任意多个参数采用类似 (parameter1 type, parameter2 type) 即(参数1 参数1的类型,参数2 参数2的类型)的形式指定。之后包含在 { 和 } 之间的代码,就是函数体。 函数中的参数列表和返回值并非是必须的,所以下面这个函数的声明也是有效的 func functionname() { // 译注: 表示这个函数不需要输入参数,且没有返回值 } 示例函数 我们以写一个计算商品价格的函数为例,输入参数是单件商品的价格和商品的个数,两者的乘积为商品总价,作为函数的输出值。 func calculateBill(price int, no int) int { var totalPrice = price * no // 商品总价 = 商品单价 * 数量 return totalPrice // 返回总价 } 上述函数有两个整型的输入 price 和 no,返回值 totalPrice 为 price 和 no 的乘积,也是整数类型。 ...

2019年12月9日 · 2 分钟

【Go】开发环境搭建

一 下载地址 安装包下载地址为:https://golang.org/dl/。 如果打不开可以使用这个地址:https://golang.google.cn/dl/。 各个系统对应的包名: 操作系统 包名 Windows go1.13.3.windows-amd64.msi Linux go1.13.3.linux-amd64.tar.gz Mac go1.13.3.darwin-amd64.pkg FreeBSD go1.13.3.freebsd-amd64.tar.gz 二 安装 Linux安装 1、下载二进制包:go1.13.3.linux-amd64.tar.gz 2、将下载的二进制包解压至 /usr/local目录。 tar -C /usr/local -xzf go1.13.3.linux-amd64.tar.gz 3、将 /usr/local/go/bin 目录添加至PATH环境变量: export PATH=$PATH:/usr/local/go/bin Windows安装 Windows 下可以使用 .msi 后缀(在下载列表中可以找到该文件,如go1.13.3.windows-amd64.msi)的安装包来安装。 默认情况下 .msi 文件会安装在 c:\Go 目录下。你可以将 c:\Go\bin 目录添加到 Path 环境变量中。添加后你需要重启命令窗口才能生效 Mac安装 Mac下直接双击go1.13.3.darwin-amd64.pkg,一路下一步安装即可 三 测试安装 1、创建工作目录 C:>Go_Project。 2、 创建文件test.go,写入如下代码 package main import "fmt" func main() { fmt.Println("Hello, World!") } 3、打开cmd,切换目录到C:>Go_Project下,执行如下命令: go run test.go 看到打印结果: ...

2019年12月9日 · 2 分钟

【Go】类型

类型 下面是 Go 支持的基本类型: bool 数字类型 int8, int16, int32, int64, int uint8, uint16, uint32, uint64, uint float32, float64 complex64, complex128 byte rune string bool bool 类型表示一个布尔值,值为 true 或者 false。 package main import "fmt" func main() { a := true b := false fmt.Println("a:", a, "b:", b) c := a && b fmt.Println("c:", c) d := a || b fmt.Println("d:", d) } 在上面的程序中,a 赋值为 true,b 赋值为 false。 c 赋值为 a && b。仅当 a 和 b 都为 true 时,操作符 && 才返回 true。因此,在这里 c 为 false。 ...

2019年12月9日 · 4 分钟

【Go】语言介绍

Go语言介绍 Go 即Golang,是Google公司2009年11月正式对外公开的一门编程语言。 Go是静态强类型语言,是区别于解析型语言的编译型语言。 解析型语言——源代码是先翻译为中间代码,然后由解析器对代码进行解释执行。 编译型语言——源代码编译生成机器语言,然后由机器直接执行机器码即可执行。 Go语言特性 跨平台的编译型语言 语法接近C语言 管道(channel),切片(slice),并发(routine) 有垃圾回收的机制 支持面向对象和面向过程的编程模式 Go语言发展(版本/特性) 2009年11月7日 weekly.2009-11-06 —— 早期的版本 2012年3月28日 go1 —— 稳定版版的发布 2013年5月14日 go1.1 —— 语言本身的变化、库的变化等。 2013年12月01日 go1.2 —— 提供更好的调度和一个新的语言特性。 2014年6月18日 go1.3 —— 主要是在实现的工作上的变化,以及精准的垃圾回收。 2014年12月10日 go1.4 —— 包含了2个很小的语言变更。 2015年8月19日 go1.5 —— 实现的架构变化,同时保留了和旧版本的兼容性。 2016年2月7日 go1.6 —— 语言本身、运行时、和库的实现的变化。 2016年8月15日 go1.7 —— 标准库有显着的性能改进和变化。 2017年2月26日 go1.8 —— 标准库有显着的性能改进和变化。 2017年8月24日 go1.9 —— 是包含语言,标准库,以及运行时的诸多变化。这个版本中的大部分工作都是对运行时和工具的改进。 2018年2月16日 go1.10 —— 大部分更改都在工具链,运行时和库的实现中。 2018年8月24日 go1.11 —— modules和WebAssembly支持。 Go语言应用 谁在用 Google 这个不用多做介绍,作为开发Go语言的公司,当仁不让。Google基于Go有很多优秀的项目,比如:https://github.com/kubernetes/kubernetes ,大家也可以在Github上 https://github.com/google/ 查看更多Google的Go开源项目。 ...

2019年12月9日 · 1 分钟

【爬虫】存储库之MongoDB

一 简介 MongoDB是一款强大、灵活、且易于扩展的通用型数据库 1、易用性 MongoDB是一个面向文档(document-oriented)的数据库,而不是关系型数据库。 不采用关系型主要是为了获得更好得扩展性。当然还有一些其他好处,与关系数据库相比,面向文档的数据库不再有“行“(row)的概念取而代之的是更为灵活的“文档”(document)模型。 通过在文档中嵌入文档和数组,面向文档的方法能够仅使用一条记录来表现复杂的层级关系,这与现代的面向对象语言的开发者对数据的看法一致。 另外,不再有预定义模式(predefined schema):文档的键(key)和值(value)不再是固定的类型和大小。由于没有固定的模式,根据需要添加或删除字段变得更容易了。通常由于开发者能够进行快速迭代,所以开发进程得以加快。而且,实验更容易进行。开发者能尝试大量的数据模型,从中选一个最好的。 2、易扩展性 应用程序数据集的大小正在以不可思议的速度增长。随着可用带宽的增长和存储器价格的下降,即使是一个小规模的应用程序,需要存储的数据量也可能大的惊人,甚至超出 了很多数据库的处理能力。过去非常罕见的T级数据,现在已经是司空见惯了。 由于需要存储的数据量不断增长,开发者面临一个问题:应该如何扩展数据库,分为纵向扩展和横向扩展,纵向扩展是最省力的做法,但缺点是大型机一般都非常贵,而且 当数据量达到机器的物理极限时,花再多的钱也买不到更强的机器了,此时选择横向扩展更为合适,但横向扩展带来的另外一个问题就是需要管理的机器太多。 MongoDB的设计采用横向扩展。面向文档的数据模型使它能很容易地在多台服务器之间进行数据分割。MongoDB能够自动处理跨集群的数据和负载,自动重新分配文档,以及将 用户的请求路由到正确的机器上。这样,开发者能够集中精力编写应用程序,而不需要考虑如何扩展的问题。如果一个集群需要更大的容量,只需要向集群添加新服务器,MongoDB就会自动将现有的数据向新服务器传送 3、丰富的功能 MongoDB作为一款通用型数据库,除了能够创建、读取、更新和删除数据之外,还提供了一系列不断扩展的独特功能 #1、索引 支持通用二级索引,允许多种快速查询,且提供唯一索引、复合索引、地理空间索引、全文索引 #2、聚合 支持聚合管道,用户能通过简单的片段创建复杂的集合,并通过数据库自动优化 #3、特殊的集合类型 支持存在时间有限的集合,适用于那些将在某个时刻过期的数据,如会话session。类似地,MongoDB也支持固定大小的集合,用于保存近期数据,如日志 #4、文件存储 支持一种非常易用的协议,用于存储大文件和文件元数据。MongoDB并不具备一些在关系型数据库中很普遍的功能,如链接join和复杂的多行事务。省略 这些的功能是处于架构上的考虑,或者说为了得到更好的扩展性,因为在分布式系统中这两个功能难以高效地实现 4、卓越的性能 MongoDB的一个主要目标是提供卓越的性能,这很大程度上决定了MongoDB的设计。MongoDB把尽可能多的内存用作缓存cache,视图为每次查询自动选择正确的索引。 总之各方面的设计都旨在保持它的高性能 虽然MongoDB非常强大并试图保留关系型数据库的很多特性,但它并不追求具备关系型数据库的所有功能。只要有可能,数据库服务器就会将处理逻辑交给客户端。这种精简方式的设计是MongoDB能够实现如此高性能的原因之一 二 MongoDB基础知识 1、文档是MongoDB的核心概念。文档就是键值对的一个有序集{‘msg’:‘hello’,‘foo’:3}。类似于python中的有序字典。 需要注意的是: #1、文档中的键/值对是有序的。 #2、文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。 #3、MongoDB区分类型和大小写。 #4、MongoDB的文档不能有重复的键。 #5、文档中的值可以是多种不同的数据类型,也可以是一个完整的内嵌文档。文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。 文档键命名规范: #1、键不能含有\0 (空字符)。这个字符用来表示键的结尾。 #2、.和$有特别的意义,只有在特定环境下才能使用。 #3、以下划线"_"开头的键是保留的(不是严格要求的)。 2、集合就是一组文档。如果将MongoDB中的一个文档比喻为关系型数据的一行,那么一个集合就是相当于一张表 #1、集合存在于数据库中,通常情况下为了方便管理,不同格式和类型的数据应该插入到不同的集合,但其实集合没有固定的结构,这意味着我们完全可以把不同格式和类型的数据统统插入一个集合中。 #2、组织子集合的方式就是使用“.”,分隔不同命名空间的子集合。 比如一个具有博客功能的应用可能包含两个集合,分别是blog.posts和blog.authors,这是为了使组织结构更清晰,这里的blog集合(这个集合甚至不需要存在)跟它的两个子集合没有任何关系。 在MongoDB中,使用子集合来组织数据非常高效,值得推荐 #3、当第一个文档插入时,集合就会被创建。合法的集合名: 集合名不能是空字符串""。 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。 集合名不能以"system."开头,这是为系统集合保留的前缀。 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。 3、数据库:在MongoDB中,多个文档组成集合,多个集合可以组成数据库 数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串: #1、不能是空字符串("")。 #2、不得含有' '(空格)、.、$、/、\和\0 (空字符)。 #3、应全部小写。 #4、最多64字节。 有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。 #1、admin: 从身份认证的角度讲,这是“root”数据库,如果将一个用户添加到admin数据库,这个用户将自动获得所有数据库的权限。再者,一些特定的服务器端命令也只能从admin数据库运行,如列出所有数据库或关闭服务器 #2、local: 这个数据库永远都不可以复制,且一台服务器上的所有本地集合都可以存储在这个数据库中 #3、config: MongoDB用于分片设置时,分片信息会存储在config数据库中 4、强调:把数据库名添加到集合名前,得到集合的完全限定名,即命名空间 ...

2019年12月3日 · 7 分钟

【爬虫】高性能相关

一 背景知识 爬虫的本质就是一个socket客户端与服务端的通信过程,如果我们有多个url待爬取,只用一个线程且采用串行的方式执行,那只能等待爬取一个结束后才能继续下一个,效率会非常低。 需要强调的是:对于单线程下串行N个任务,并不完全等同于低效,如果这N个任务都是纯计算的任务,那么该线程对cpu的利用率仍然会很高,之所以单线程下串行多个爬虫任务低效,是因为爬虫任务是明显的IO密集型程序。 关于IO模型详见链接:http://www.cnblogs.com/linhaifeng/articles/7454717.html 那么该如何提高爬取性能呢?且看下述概念 二 同步、异步、回调机制 1、同步调用:即提交一个任务后就在原地等待任务结束,等到拿到任务的结果后再继续下一行代码,效率低下 # 同步调用 import requests def parse_page(res): print('解析 %s' %(len(res))) def get_page(url): print('下载 %s' %url) response=requests.get(url) if response.status_code == 200: return response.text urls=['https://www.baidu.com/','http://www.sina.com.cn/','https://www.python.org'] for url in urls: res=get_page(url) #调用一个任务,就在原地等待任务结束拿到结果后才继续往后执行 parse_page(res) 2、一个简单的解决方案:多线程或多进程 #在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接。 # 多进程或多线程 #IO密集型程序应该用多线程 import requests from threading import Thread,current_thread def parse_page(res): print('%s 解析 %s' %(current_thread().getName(),len(res))) def get_page(url,callback=parse_page): print('%s 下载 %s' %(current_thread().getName(),url)) response=requests.get(url) if response.status_code == 200: callback(response.text) if __name__ == '__main__': urls=['https://www.baidu.com/','http://www.sina.com.cn/','https://www.python.org'] for url in urls: t=Thread(target=get_page,args=(url,)) t.start() 该方案的问题是: ...

2019年12月3日 · 4 分钟

【爬虫】解析库之beautifulsoup库

一 介绍 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.你可能在寻找 Beautiful Soup3 的文档,Beautiful Soup 3 目前已经停止开发,官网推荐在现在的项目中使用Beautiful Soup 4, 移植到BS4 #安装 Beautiful Soup pip install beautifulsoup4 #安装解析器 Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml: $ apt-get install Python-lxml $ easy_install lxml $ pip install lxml 另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib: $ apt-get install Python-html5lib $ easy_install html5lib $ pip install html5lib 下表列出了主要的解析器,以及它们的优缺点,官网推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定. 中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html 二 基本使用 html_doc = """ <html><head><title>The Dormouse's story</title></head> <body> <p class="title"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> """ #基本使用:容错处理,文档的容错能力指的是在html代码不完整的情况下,使用该模块可以识别该错误。使用BeautifulSoup解析上述代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出 from bs4 import BeautifulSoup soup=BeautifulSoup(html_doc,'lxml') #具有容错功能 res=soup.prettify() #处理好缩进,结构化显示 print(res) 三 遍历文档树 #遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个 #1、用法 #2、获取标签的名称 #3、获取标签的属性 #4、获取标签的内容 #5、嵌套选择 #6、子节点、子孙节点 #7、父节点、祖先节点 #8、兄弟节点 #遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个 html_doc = """ <html><head><title>The Dormouse's story</title></head> <body> <p id="my p" class="title"><b id="bbb" class="boldest">The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> """ #1、用法 from bs4 import BeautifulSoup soup=BeautifulSoup(html_doc,'lxml') # soup=BeautifulSoup(open('a.html'),'lxml') print(soup.p) #存在多个相同的标签则只返回第一个 print(soup.a) #存在多个相同的标签则只返回第一个 #2、获取标签的名称 print(soup.p.name) #3、获取标签的属性 print(soup.p.attrs) #4、获取标签的内容 print(soup.p.string) # p下的文本只有一个时,取到,否则为None print(soup.p.strings) #拿到一个生成器对象, 取到p下所有的文本内容 print(soup.p.text) #取到p下所有的文本内容 for line in soup.stripped_strings: #去掉空白 print(line) ''' 如果tag包含了多个子节点,tag就无法确定 .string 方法应该调用哪个子节点的内容, .string 的输出结果是 None,如果只有一个子节点那么就输出该子节点的文本,比如下面的这种结构,soup.p.string 返回为None,但soup.p.strings就可以找到所有文本 <p id='list-1'> 哈哈哈哈 <a class='sss'> <span> <h1>aaaa</h1> </span> </a> <b>bbbbb</b> </p> ''' #5、嵌套选择 print(soup.head.title.string) print(soup.body.a.string) #6、子节点、子孙节点 print(soup.p.contents) #p下所有子节点 print(soup.p.children) #得到一个迭代器,包含p下所有子节点 for i,child in enumerate(soup.p.children): print(i,child) print(soup.p.descendants) #获取子孙节点,p下所有的标签都会选择出来 for i,child in enumerate(soup.p.descendants): print(i,child) #7、父节点、祖先节点 print(soup.a.parent) #获取a标签的父节点 print(soup.a.parents) #找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲... #8、兄弟节点 print('=====>') print(soup.a.next_sibling) #下一个兄弟 print(soup.a.previous_sibling) #上一个兄弟 print(list(soup.a.next_siblings)) #下面的兄弟们=>生成器对象 print(soup.a.previous_siblings) #上面的兄弟们=>生成器对象 四 搜索文档树 1、五种过滤器 ...

2019年12月3日 · 4 分钟

利用腾讯云函数设置定时任务实现腾讯视频自动签到获得V力值

腾讯视频vip花了钱,还不能自动升级,要每天签到才涨V力值。升级VIP等级。。实在蛋疼。这次又是云服务器函数,搞了个脚本COOKIES方式登录。测试了40多天。还没到期,感觉自用够了。分享出来吧。。 cookies获取麻烦点。不过也就一两分钟的事,能用1个月以上就够了。 准备工具: chrome浏览器 qq或微信登录腾讯云 腾讯视频会员一枚 第一步:获取cookies 1.浏览器打开腾讯视频官网: https://v.qq.com/ 登录VIP账号(这里我就不详写了。应该都会。我是直接手机扫码登录) 2.VIP账号登录成功后,打开另一个地址: https://vip.video.qq.com/fcgi-bin/comm_cgi?name=hierarchical_task_system&cmd=2 (没错这个就是签到地址。APP抓出来的。) 3.在第二个地址,按下快捷键:CTRL+SHIFT+J 在>后面输入:document.cookie 回车,复制【引号里】的内容(脚本要用的cookies): pgv_pvi=513475……..(中间打码了。。看个开头和结尾吧)…. uid=59985555 第二部:腾讯云部署脚本 用qq或者微信登录腾讯云scf(无服务器云函数) https://console.cloud.tencent.com/scf 函数服务=》(选择区域,上海,广州,成都,香港,北京) =》新建=》空白函数=》函数名称(随便写,比如txsp_qiandao)=》运行环境(python3.6)=》下一步 复制下面代码: # -*- coding: utf8 -*- import requests import re import time from urllib.parse import quote def start(): try: s = requests.session() cookie1 = 'TXSP_COOKIE' this_time = int(round(time.time() * 1000)) login_url = 'https://vip.video.qq.com/fcgi-bin/comm_cgi?name=hierarchical_task_system&cmd=2&_=' + str(this_time) headers={ 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.204 Safari/537.36', 'Cookie': cookie1 } res =s.get(login_url,headers=headers).text print('访问结果:'+res) if 'Account Verify Error' in res: print('cookies失效,通知SERVER酱!') requests.get('https://sc.ftqq.com/SCKEY.send?text=' + quote('腾讯视频自动签到失败~'+time.strftime('%Y.%m.%d',time.localtime(time.time()))) +'&desp='+quote('cookies失效,请更新!\n')) else: print('签到完成') except Exception as e: print("地址访问失败,通知SERVER酱!") requests.get('https://sc.ftqq.com/SCKEY.send?text=' + quote('腾讯视频自动签到失败~'+time.strftime('%Y.%m.%d',time.localtime(time.time()))) +'&desp='+quote('异常代码:\n'+str(e))) def main_handler(event, context): return start() if __name__ == '__main__': start() 代码需要修改的地方3处, TXSP_COOKIE (一处,刚才获取的cookies字符串) https://sc.ftqq.com/SCKEY.send (两处,server酱的地址,申请地址:http://sc.ftqq.com/) ...

2019年12月2日 · 1 分钟