GO语言的进阶之路-协程和Channel
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
看过我之前几篇博客小伙伴可能对Golang语言的语法上了解的差不多了,但是,如果想要你的代码和性能更高,那还得学点晋升的本来,这个时候我们就需要引入Golang的协成这个概念了,其实,你可能早就听说了Golang的优势就是处理大并发,我们可以用它来做日志收集系统,也可以用它做业务上的“秒杀系统”,当然我们还可以用它来做“监控系统”。好了,下面跟我一起来体会一下Golang的五味杂陈吧。
一.什么是协程;
再说协成之前,我们需要了解两个概念,即用户态和内核态。
1.什么是用户态;
官方解释:用户态(user mode)在计算机结构指两项类似的概念。在CPU的设计中,用户态指非特权状态。在此状态下,执行的代码被硬件限定,不能进行某些操作,比如写入其他进程的存储空间,以防止给操作系统带来安全隐患。在操作系统的设计中,用户态也类似,指非特权的执行状态。内核禁止此状态下的代码进行潜在危险的操作,比如写入系统配置文件、杀掉其他用户的进程、重启系统等。
应用程序在用户态下运行,仅仅只能执行cpu整个指令集的一个子集,该子集中不包含操作硬件功能的部分,因此,一般情况下,在用户态中有关I/O和内存保护(操作系统占用的内存是受保护的,不能被别的程序占用)。
如果感兴趣的朋友可以参考:https://baike.baidu.com/item/%E7%94%A8%E6%88%B7%E6%80%81/9548791?fr=aladdin
2.什么是内核态;
内核态也叫和核心态。
官方解释:在处理器的存储保护中,主要有两种权限状态,一种是核心态(管态),也被称为特权态;一种是用户态(目态)。核心态是操作系统内核所运行的模式,运行在该模式的代码,可以无限制地对系统存储、外部设备进行访问。
操作系统在内核态运行情况下可以访问硬件上所有的内容。
如果感兴趣的朋友可以参考:https://baike.baidu.com/item/%E6%A0%B8%E5%BF%83%E6%80%81/6845908?fr=aladdin
3.什么是协成;
官方解释:一个程序可以包含多个协程,可以对比与一个进程包含多个线程,因而下面我们来比较协程和线程。我们知道多个线程相对独立,有自己的上下文,切换受系统控制;而协程也相对独立,有自己的上下文,但是其切换由自己控制,由当前协程切换到其他协程由当前协程来控制。
协程(coroutine)是Go语言中的轻量级线程实现,由Go运行时(runtime)管理。在一个函数调用前加上go关键字,这次调用就会在一个新的goroutine中并发执行。当被调用的函数返回时,这个goroutine也自动结束。需要注意的是,如果这个函数有返回值,那么这个返回值会被丢弃。协成工作在用户态,它类似于现场的运行方式可以并行处理任务。
如果感兴趣的朋友可以参考:http://baike.baidu.com/link?url=MKRg3Ca7Bokkqv5EarU1JO7Oz6Wn8jMhmJcoivDG27dOFeznk3gVDSl5SfN6P191GSwGDInEfDPVkQ6j3pJNbICpy04U0F1TkLOZHVzs1-u
二.创建一个协程;
在一个函数调用前加上go关键字,这次调用就会在一个新的goroutine中并发执行,下面我们一起来看段代码的执行结果:
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "time" 12 "fmt" 13 ) 14 15 func sayhi(s string) { 16 for i := 0; i < 5; i++ { 17 time.Sleep(100*time.Millisecond) //表示每次循环后都要休息100毫秒。 18 fmt.Println(s) 19 } 20 } 21 22 func main() { 23 go sayhi("尹正杰") //在函数执行前加个go,表示单独起了一个协程,表示和当前主协程(main)并驾齐驱运行代码。 24 sayhi("Golang") 25 } 26 27 28 #以上代码执行结果如下: 29 Golang 30 尹正杰 31 尹正杰 32 Golang 33 Golang 34 尹正杰 35 尹正杰 36 Golang 37 Golang 38 尹正杰
相信大家已经看到了一些端倪,我们先定义了一个“sayhi”函数,这个函数的功能就是将传入的字符串打印5遍,然后我们在主程序上调用的时候,发现在函数面前加"go"关键字时,就会打印输出,但是奇怪的是没有按照顺序打,它没有先打印五遍“尹正杰”然后在打印5遍“Golang”,而是函数执行结果是不规律的打印了两个字符串。这就是并发的效果,两个函数同事运行效果。这也是我们的并发之路的初体验。哈哈~
三.协程的局限性;
发现让两端代码同事运行貌似听起来很高大上的样子,但是有个局限性,就是当主进程结束后,协成也会跟着结束,其实这个很好理解,我们通过一段代码就知道了:
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "time" 12 "fmt" 13 ) 14 15 func main() { 16 s := []int{2,7,1,6,4,3,11,15,17,5,8,9,12} 17 for _,n := range s{ 18 go func(n int) { //定义一个匿名函数,并对该函数开启协程,每次循环都会开启一个协成,也就是说它开启了13个协程。 19 time.Sleep(time.Duration(n) * time.Second) /*表示每循环一次就需要睡1s,睡的总时间是由n来控制的, 20 总长度是由s切片数组中最大的一个数字决定,也就是说这个协成最少需要17秒才会结束哟*/ 21 fmt.Println(n) 22 }(n) //由于这个函数是匿名函数,所以调用方式就直接:(n)调用,不用输入函数名。 23 } 24 time.Sleep(12*time.Second) //主进程要执行的时间是12秒 25 } 26 27 28 29 #以上代码执行结果如下: 30 1 31 2 32 3 33 4 34 5 35 6 36 7 37 8 38 9 39 11 40 12
是不是很神奇,直接就进行排序了,但是15和17没有在终端输出,为什么呢?这就是我所说的主进程结束,那么整个程序也终将结束,因为主程序的时间只有12s,如果你想让所有的数据都排序出来,就得把数字换成一个大于或等于17的,这样才会对所有的数字进行排序。因为协成13个协程都要执行完毕的话需要17s才好使。
四.锁;
1.为什么要引入锁;
在线上生活中,我们为了避免多个用户操作同一个文件,就会定义一个锁,为什么我们需要一个锁呢?我们可以看以下的案例:
1 package main 2 3 import ( 4 "time" 5 "fmt" 6 ) 7 8 type Accout struct { 9 money int 10 } 11 12 func (a *Accout) Do_Prepare() { 13 time.Sleep(time.Second) 14 } 15 16 func (a *Accout) Get_Gongzi(n int) { 17 a.money += n 18 } 19 20 func (a *Accout) Give_Wife(n int) { 21 if a.money > n { 22 a.Do_Prepare() 23 a.money -= n 24 } 25 } 26 27 func (a *Accout) Buy(n int) { 28 if a.money >n { 29 a.Do_Prepare() 30 a.money -= n 31 } 32 } 33 34 func (a *Accout) Left()int { 35 return a.money 36 } 37 38 func main() { 39 var account Accout 40 account.Get_Gongzi(10000) 41 go account.Give_Wife(6000) 42 go account.Buy(5000) 43 time.Sleep(2 * time.Second) //不能让主程序结束掉,因为主进程一结束go的协程也就跟着结束啦。 44 fmt.Println(account.Left()) 45 } 46 47 48 49 #以上代码执行结果如下: 50 -1000
估计大家都看出来端倪了,在让两个协程并发跑起来,发现你得到的10000块钱都让给花出去了,是不是老尴尬了,写的判断语句也是没有生效的,最终10000块钱的工资,它竟然花了11000,如果银行这么干早就倒闭了,哈哈~那么问题来了,如果解决这一种现象呢?目前有四种常见的处理方案即:互斥锁,读写锁和channel锁以及waitgroup等等。
2.互斥锁;
互斥锁是传统的并发程序对共享资源进行访问控制的主要手段。它由标准库代码包sync中的Mutex结构体类型代表。sync.Mutex类型(确切地说,是*sync.Mutex类型)只有两个公开方法——Lock和Unlock。顾名思义,前者被用于锁定当前的互斥量,而后者则被用来对当前的互斥量进行解锁。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "time" 12 "fmt" 13 "sync" 14 ) 15 16 17 type Accout struct { 18 flag sync.Mutex 19 money int 20 } 21 22 func (a *Accout) Do_Prepare() { 23 time.Sleep(time.Second) 24 } 25 26 func (a *Accout) Get_Salary(n int) { //定义发的工资 27 a.money += n 28 } 29 30 func (a *Accout) Give_Wife(n int) { //上交给妻子的工资 31 a.flag.Lock() 32 defer a.flag.Unlock() 33 if a.money > n { 34 a.Do_Prepare() 35 a.money -= n 36 }else { 37 fmt.Println("您的余额已不足!请及时充值~") 38 } 39 } 40 41 func (a *Accout) Buy(n int) { //自己买的工资 42 a.flag.Lock() 43 defer a.flag.Unlock() 44 if a.money >n { 45 a.Do_Prepare() 46 a.money -= n 47 }else { 48 fmt.Println("您的余额已不足!请及时充值~") 49 } 50 } 51 52 func (a *Accout) Left()int { 53 return a.money 54 } 55 56 func main() { 57 var account Accout 58 account.Get_Salary(10000) 59 go account.Give_Wife(6000) 60 go account.Buy(5000) 61 time.Sleep(2 * time.Second) //不能让主程序结束掉,因为主进程一结束go的协程也就跟着结束啦。 62 fmt.Printf("您的剩余工资是\033[31;1m%d\033[0m",account.Left()) 63 64 } 65 66 67 68 #以上代码解析如下: 69 您的余额已不足!请及时充值~ 70 您的剩余工资是4000
3.读写锁;
在Go语言中,读写锁由结构体类型sync.RWMutex代表。与互斥锁类似,sync.RWMutex类型的零值就已经是立即可用的读写锁了。
读写锁即是针对于读写操作的互斥锁。它与普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作。读写锁控制下的多个写操作之间都是互斥的,并且写操作与读操作之间也都是互斥的。但是,多个读操作之间却不存在互斥关系。
A.多个读操作之间却不存在互斥关系;
我们会发现读取操作没有存在互斥的关系。5个进程同事进行读取,最终都顺利并行跑完了。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "sync" 12 "time" 13 ) 14 15 var m *sync.RWMutex //定义m的类型为读写锁。 16 17 func main() { 18 m = new(sync.RWMutex) 19 go read("第一次读取:") //开启5个协程进行读取操作。如果不能并发跑最少需要5秒钟时间。 20 go read("第二次读取:") 21 go read("第三次读取:") 22 go read("第四次读取:") 23 go read("第五次读取:") 24 time.Sleep(2* time.Second) //主进程只有2s,意味着这个程序最多能运行2s的时间。 25 } 26 27 func read(i string) { 28 println(i, "read start") 29 m.RLock() //读锁定 30 println(i, "资料正在读取中....") 31 time.Sleep(1 * time.Second) //改函数执行完毕最少需要睡1秒。 32 m.RUnlock() //读解锁 33 println(i, "read end") 34 } 35 36 37 38 #以上代码执行结果如下: 39 第二次读取: read start 40 第二次读取: 资料正在读取中.... 41 第一次读取: read start 42 第一次读取: 资料正在读取中.... 43 第三次读取: read start 44 第三次读取: 资料正在读取中.... 45 第四次读取: read start 46 第四次读取: 资料正在读取中.... 47 第五次读取: read start 48 第五次读取: 资料正在读取中.... 49 第一次读取: read end 50 第三次读取: read end 51 第二次读取: read end 52 第四次读取: read end 53 第五次读取: read end
B.读写锁控制下的多个写操作之间都是互斥的,并且写操作与读操作之间也都是互斥的;
我们发现,读的时候不能写,写的时候不能读,我们将主程序设置的时间是10秒钟,一次读两次写花费的总时间是12秒钟,因此肯定有一个是无法完成度或是写的部分。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "sync" 12 "time" 13 ) 14 15 var m *sync.RWMutex 16 17 func read(i string) { 18 println(i, "read start") 19 m.RLock() 20 println(i, "资料正在读取中.....") 21 time.Sleep(4 * time.Second) 22 m.RUnlock() 23 println(i, "read end") 24 } 25 26 func write(i string) { 27 println(i, "write start") 28 m.Lock() //写操作锁定 29 println(i, "数据正在写入硬盘中.....") 30 time.Sleep(4 * time.Second) 31 m.Unlock() //写操作解锁 32 println(i, "write end") 33 } 34 35 func main(){ 36 m = new(sync.RWMutex) 37 go write("第一次写入") //写的时候啥都不能干,即其他协程无法写入,也无法读取。 38 go read("第一次读取") 39 go write("第二次写入") 40 time.Sleep(10 * time.Second) //主进程只给出10秒的时间,但是整个进程跑完最少需要12秒的时间。 41 } 42 43 44 45 46 #以上代码直接结果如下: 47 第一次写入 write start 48 第一次写入 数据正在写入硬盘中..... 49 第一次读取 read start 50 第二次写入 write start 51 第一次写入 write end 52 第一次读取 资料正在读取中..... 53 第一次读取 read end 54 第二次写入 数据正在写入硬盘中.....
4.channel锁;
channel锁的工作原理就是让2个协成互相通信,一会我们会详细介绍。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "time" 12 "fmt" 13 "sync" 14 ) 15 16 17 type Accout struct { 18 flag sync.Mutex 19 money int 20 } 21 22 func (a *Accout) Do_Prepare() { 23 time.Sleep(time.Second) 24 } 25 26 func (a *Accout) Get_Gongzi(n int) { 27 a.money += n 28 } 29 30 func (a *Accout) Give_Wife(n int) { 31 a.flag.Lock() 32 defer a.flag.Unlock() 33 if a.money > n { 34 a.Do_Prepare() 35 a.money -= n 36 }else { 37 fmt.Println("您的余额已不足,请及时充值!") 38 } 39 } 40 41 func (a *Accout) Buy(n int) { 42 a.flag.Lock() 43 defer a.flag.Unlock() 44 if a.money >n { 45 a.Do_Prepare() 46 a.money -= n 47 }else { 48 fmt.Println("您的余额已不足,请及时充值!") 49 } 50 } 51 52 func (a *Accout) Left()int { 53 return a.money 54 } 55 56 func main() { 57 var account Accout 58 account.Get_Gongzi(10000) 59 60 var work_info chan string 61 work_info = make(chan string ,2) //定义一个channel 62 63 go func() { 64 account.Give_Wife(6000) 65 work_info <- "I done" //如果该进程执行完毕就发送一条数据给channel,下面的那个也一样 66 }() 67 68 go func() { 69 account.Buy(50000) 70 work_info <- "I have done too!" 71 }() 72 73 cnt := 0 74 for i := range work_info { 75 fmt.Println(i) 76 cnt++ //每次循环都叠加1,当2个协程都工作完就让主程序结束。 77 if cnt >= 2 { 78 break 79 } 80 81 } 82 defer close(work_info) 83 fmt.Printf("您的剩余工资是\033[31;1m%d\033[0m",account.Left()) 84 } 85 86 87 88 89 #以上代码直接结果如下: 90 您的余额已不足,请及时充值! 91 I have done too! 92 I done 93 您的剩余工资是4000
其实channel还有一个好处就是解决超时问题,就是如果在规定的时间没有完成进程的内容,我们就返回给用户超时的状态。以下是示例代码:
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "time" 12 "fmt" 13 "sync" 14 ) 15 16 17 type Accout struct { 18 flag sync.Mutex 19 money int 20 } 21 22 func (a *Accout) Do_Prepare() { 23 time.Sleep(time.Second) 24 } 25 26 func (a *Accout) Get_Gongzi(n int) { 27 a.money += n 28 } 29 30 func (a *Accout) Give_Wife(n int) { 31 a.flag.Lock() 32 defer a.flag.Unlock() 33 if a.money > n { 34 a.Do_Prepare() 35 a.money -= n 36 }else { 37 fmt.Println("您的余额已不足,请及时充值!") 38 } 39 } 40 41 func (a *Accout) Buy(n int) { 42 a.flag.Lock() 43 defer a.flag.Unlock() 44 if a.money >n { 45 a.Do_Prepare() 46 a.money -= n 47 }else { 48 fmt.Println("您的余额已不足,请及时充值!") 49 } 50 } 51 52 func (a *Accout) Left()int { 53 return a.money 54 } 55 56 func main() { 57 var account Accout 58 account.Get_Gongzi(10000) 59 60 var work_info chan string 61 work_info = make(chan string ,2) //定义一个channel 62 63 go func() { 64 account.Give_Wife(6000) 65 work_info <- "I done" //如果该进程执行完毕就发送一条数据给channel,下面的那个也一样 66 }() 67 68 go func() { 69 account.Buy(50000) 70 work_info <- "I have done too!" 71 }() 72 73 cnt := 0 74 for i := range work_info { 75 fmt.Println(i) 76 cnt++ //每次循环都叠加1,当2个协程都工作完就让主程序结束。 77 if cnt >= 2 { 78 fmt.Println("操作超时") 79 return 80 } 81 82 } 83 defer close(work_info) 84 fmt.Printf("您的剩余工资是\033[31;1m%d\033[0m",account.Left()) 85 } 86 87 88 89 #以上代码执行结果如下: 90 您的余额已不足,请及时充值! 91 I have done too! 92 I done 93 操作超时
5.waitgroup进行同步;
WaitGroup在go语言中,用于线程同步,它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "time" 12 "fmt" 13 "sync" 14 ) 15 16 type Accout struct { 17 flag sync.Mutex 18 money int 19 } 20 21 func (a *Accout) Do_Prepare() { 22 time.Sleep(time.Second) 23 } 24 25 func (a *Accout) Get_Gongzi(n int) { 26 a.money += n 27 } 28 29 func (a *Accout) Give_Wife(n int) { 30 a.flag.Lock() 31 defer a.flag.Unlock() 32 if a.money > n { 33 a.Do_Prepare() 34 a.money -= n 35 }else { 36 fmt.Println("您的余额已不足,请及时充值!") 37 } 38 } 39 40 func (a *Accout) Buy(n int) { 41 a.flag.Lock() 42 defer a.flag.Unlock() 43 if a.money >n { 44 a.Do_Prepare() 45 a.money -= n 46 }else { 47 fmt.Println("您的余额已不足,请及时充值!") 48 } 49 } 50 51 func (a *Accout) Left()int { 52 return a.money 53 } 54 55 func main() { 56 var account Accout 57 account.Get_Gongzi(10000) 58 wg := new(sync.WaitGroup) //定义一个WaitGroup,就是用来等待都 59 wg.Add(2) //有几个进程需要等待就写几个,写多或写少都会报错哟~ 60 go func() { 61 account.Give_Wife(6000) 62 wg.Done() //该进程结束就发送结束标志。 63 }() 64 go func() { 65 account.Buy(5000) 66 wg.Done() 67 }() 68 wg.Wait() //等待所有协程结束后在执行以下都代码。 69 fmt.Printf("您的剩余工资是\033[31;1m%d\033[0m",account.Left()) 70 } 71 72 73 74 #以上代码执行结果如下: 75 您的余额已不足,请及时充值! 76 您的剩余工资是5000
五.协程池;
协程池可以控制并行度,复用协程。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "sync" 12 "net/http" 13 "log" 14 ) 15 16 func work(ch chan string, wg *sync.WaitGroup) { //ch是用来接受数据,wg是用来同步协程的. 17 for u := range ch{ 18 resp,err := http.Get(u) //将channel中的数据读取出来 19 if err != nil { 20 log.Print(err) 21 return 22 } 23 log.Printf("访问的网站是:%s,网页的大小是:%v",u,resp.ContentLength) 24 resp.Body.Close() // 25 } 26 wg.Done() 27 } 28 29 func main() { 30 wg := new(sync.WaitGroup) //定义WaitGroup为了进行协程同步。 31 wg.Add(5) //开启5个协程池。 32 taskch := make(chan string) //创建一个channel 33 for i := 0; i < 5; i++ { 34 go work(taskch,wg) 35 } 36 urls := []string{"http://www.baidu.com","http://www.zhihu.com","http://www.cnblogs.com/yinzhengjie/p/7201980.html"} //定义需要访问的网站。 37 for _,url := range urls{ 38 taskch <- url //往channel发送数据。 39 } 40 close(taskch) 41 wg.Wait() //等待程序结束 42 } 43 44 45 46 #以上代码执行结果如下: 47 2017/07/24 15:23:02 访问的网站是:http://www.baidu.com,网页的大小是:-1 48 2017/07/24 15:23:03 访问的网站是:http://www.cnblogs.com/yinzhengjie/p/7201980.html,网页的大小是:-1 49 2017/07/24 15:23:03 访问的网站是:http://www.zhihu.com,网页的大小是:-1
六.channel的引入;
Go 语言中的 channel 是实现 goroutine 间无锁通信的关键机制,他使得写多线程并发程序变得简单、灵活、触手可得。channel是Go语言在语言级别提供的goroutine间的通信方式,我们可以使用channel在多个goroutine之间传递消息。channel是进程内的通信方式,因此通过channel传递对象的过程和调用函数时的参数传递行为比较一致,比如也可以传递指针等。
1.实现channel的Receive与Sender;
初学者可以理解成:channel实际上就是接受和发送数据。channel是类型相关的,一个channel只能传递一种类型的值,这个类型需要在声明channel时指定。有了这些就够了,我们一起来看段代码来感受下channel吧。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import "fmt" 11 12 13 14 func sum(s []int, c chan int) { //该函数是对切片数组求和,需要传入一个切片数组和一个channel。 15 sum := 0 16 for _,v := range s { 17 sum += v //表示对切片数组进行求和。 18 } 19 c <- sum //将sum的数据送给名称为c的channel,也就是说将数组中的数字的值传给channel。给channle赋值的时候,其应该在左边。 20 } 21 22 func main() { 23 Slice_array := []int{1,2,3,4,-9,4,2,0} 24 channel_name := make(chan int) //用chan定义一个channel对象名称为channel_name,其类型是int。 25 go sum(Slice_array[:len(Slice_array)/2],channel_name) //在函数上开启协成,注意格式。是在函数前面加个go参数即可。 26 go sum(Slice_array[len(Slice_array)/2:],channel_name) 27 x,y := <-channel_name, <-channel_name //将channel_name中的数据接收并复制给x和y,当然你也可以定义两个变量名不同的channle,要注意到是取channel的值时,其应该在右边, 28 fmt.Println(x,y,x+y) 29 } 30 31 32 33 #以上代码执行结果如下: 34 -3 10 7
2.channel的缓冲大小;
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import "fmt" 11 12 13 14 func main() { 15 ch := make(chan int,5) /*定义缓冲大小容量为5。下面给channel发送了3个值,如果接受当值超过预定义的5时,就会 16 报错哟!如果你不写的化就会报错:"fatal error: all goroutines are asleep - deadlock!"*/ 17 ch <- 100 18 ch <- 200 19 ch <- 300 20 fmt.Println(<-ch) //第一次取值 21 fmt.Println(<-ch) //第二次取值 22 fmt.Println(<-ch) //第三次取值 23 } 24 25 26 27 #以上代码执行结果如下: 28 100 29 200 30 300
3.channel的应用;
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import "fmt" 11 12 func fibonacci(n int,c chan int) { //定义斐波拉契数列函数。 13 x,y := 0,1 14 for i := 0; i < n; i++ { 15 c <- x 16 x,y = y,x+y 17 if x > 100 { //表示当循环到两个数字之和大于100时就终止循环。 18 break 19 } 20 } 21 close(c) //关闭channel,如果不关闭就会被锁,出现报错:"deadlock!" 22 } 23 24 func main() { 25 channel_name := make(chan int,15) //定义channel缓冲大小时为15,表示最多存取15个元素。 26 go fibonacci(cap(channel_name),channel_name) 27 for i := range channel_name{ //遍历channel_name 28 fmt.Println(i) 29 } 30 } 31 32 33 34 #以上代码执行结果如下: 35 0 36 1 37 1 38 2 39 3 40 5 41 8 42 13 43 21 44 34 45 55 46 89
4.Channeld的select语法;
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import "fmt" 11 12 func fibonacci(channel_name,quit chan int) { //定义两个channle对象channel_name和quit。 13 x,y := 0,1 14 for{ 15 select { 16 case channel_name <- x: //用channel_name接受数据。 17 x,y = y,x+y 18 19 case <-quit: //表示当接收到quit的channel时,就执行以下代码。其实就是实现关闭channel的功能。 20 fmt.Println("EXIT") 21 return //函数一退出协程也就跟着退出了 22 } 23 } 24 } 25 26 func main() { 27 channel_name := make(chan int) 28 quit := make(chan int) 29 go func() { 30 for i := 0; i < 11; i++ { 31 fmt.Println(<-channel_name) //"<-channel_name"表示读取channel_name中的参数。 32 } 33 quit<- 100 /*当for循环结束后,我们随便给quit的channel传一个值就可以实现退出函数的功能。我们之前需要 34 用close(c)来退出发信号的功能,主动权在"fibonacci",而我们现在我们用quit来主动退出协程。*/ 35 }() //这里加个括号是在调用当前函数。 36 fibonacci(channel_name,quit) //将channel_name和quit传递给fibonacci函数 37 } 38 39 40 41 #以上代码珍惜结果如下: 42 0 43 1 44 1 45 2 46 3 47 5 48 8 49 13 50 21 51 34 52 55 53 EXIT
5.default语法;
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "time" 12 "fmt" 13 ) 14 15 func main() { 16 tick := time.Tick(1000*time.Millisecond) //也可以这样写:“tick := time.NewTicker(1000*time.Millisecond).C”其中这个点C就是一个channel。 17 boom := time.After(5000*time.Millisecond) 18 for { 19 select { 20 case <-tick: 21 fmt.Println("滴答。。。") 22 case <-boom: 23 fmt.Println("砰~") 24 return 25 default: 26 fmt.Println("吃一口凉皮") 27 time.Sleep(500*time.Millisecond) 28 } 29 } 30 } 31 32 33 34 #以上代码执行结果如下: 35 吃一口凉皮 36 吃一口凉皮 37 滴答。。。 38 吃一口凉皮 39 吃一口凉皮 40 滴答。。。 41 吃一口凉皮 42 吃一口凉皮 43 滴答。。。 44 吃一口凉皮 45 吃一口凉皮 46 滴答。。。 47 吃一口凉皮 48 吃一口凉皮 49 砰~
6.channel扩展;
A.time.NewTicker用法展示:
当我们在写一个监控系统的时候,需要实施监控,但是定义巡检时间的话,需要我们自定义巡检周期性。这个时候我们就可以用到一个叫时间设置器的函数,即:time.NewTicker。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "time" 12 "fmt" 13 ) 14 15 func main() { 16 timer := time.NewTicker(3 * time.Second) //设置定时器,定义timer的基本单位是三秒。 17 cnt := 0 18 for _ = range timer.C{ //其中timer.C就是一个channel 19 cnt++ 20 if cnt > 3 { 21 timer.Stop() //调用方式 22 return //这里是手动停下来,一般是不会让他停下来,比如在监控的时候,但是有结束条件的时候用return的话是不会报错的 23 } 24 fmt.Println("yinzhengjie") 25 } 26 } 27 28 29 30 #以上代码执行结果如下: 31 32 yinzhengjie 33 yinzhengjie 34 yinzhengjie
B.time.After用法展示:
要注意的是,“time.NewTicker”需要调用"Stop"方法才会被执行,而“time.After”调用的姿势也不一样,我们一起来体验一下吧。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "time" 12 "fmt" 13 ) 14 15 func main() { 16 c := time.After(time.Second*3) //表示让其睡眠3秒钟。 17 <-c //调用方式 18 fmt.Println("主进程执行完毕") 19 } 20 21 22 23 #以上代码执行结果如下: 24 主进程执行完毕
C.channel的深入浅出;
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "net/http" 12 "log" 13 "fmt" 14 "time" 15 ) 16 17 /* 18 1.channel就好像一个传送带,可以源源不断的往里面放数据,只要不close就可以永远发送数据。 19 2.如果channel里面没有数据,接收方会阻塞。 20 3.如果没有人正在等待channel的数据,发送方会阻塞。 21 4.从一个close的channel取数据永远不会阻塞,同时获取的是默认值 22 */ 23 24 25 func Print_url(url string) { 26 res,err := http.Get(url) 27 if err != nil { 28 log.Fatal("11111",err) 29 } 30 defer res.Body.Close() 31 fmt.Printf("网页的状态返回码是:%v\n",res.Status) 32 33 } 34 35 func work(resave chan string) { 36 37 for { 38 url,ok := <- resave //如果channel里面没有数据,接收方会阻塞。用url,ok两个参数来接受channel,可以从channel会返回两个参数。url表示接受的数据。ok接受的信息是channel是否结束。 39 //fmt.Println(url,ok) 40 if !ok { //判断channel是否关闭。 41 break 42 } 43 Print_url(url) 44 } 45 46 //for i := range resave { //range语法一值在接受数据,而channel可以源源不断的往里面添加数据。从一个close的channel取数据永远不会阻塞,同时获取的是默认值。 47 // Print_url(i) 48 //} 49 } 50 51 func main() { 52 make_string := make(chan string) 53 for i := 0;i<3 ;i++ { 54 go work(make_string) 55 } 56 urls := []string{"http://www.baidu.com","http://www.qq.com","http://www.weixin.com"} 57 for _,i := range urls { 58 make_string <- i //如果没有人正在等待channel的数据,发送方会阻塞。 59 } 60 close(make_string) //channel就好像一个传送带,可以源源不断的往里面放数据,只要不close就可以永远发送数据。 61 time.Sleep(5 * time.Second) 62 } 63 64 65 66 67 #以上代码输出结果如下: 68 网页的状态返回码是:200 OK 69 网页的状态返回码是:200 OK 70 网页的状态返回码是:200 OK
D.waitgroup+channel配合使用;
我们可以对C进行优化,在实际生产环境中,我们最好不要用"time.sleep"这个方法来实现主程序等待子程序执行完毕,因为会出现异响不到的bug哟~推荐是用waitgrout来取代这个sleep时间。
1 package main 2 3 import ( 4 "net/http" 5 "log" 6 "fmt" 7 //"time" 8 "sync" 9 ) 10 11 /* 12 1.channel就好像一个传送带,可以源源不断的往里面放数据,只要不close就可以永远发送数据。 13 2.如果channel里面没有数据,接收方会阻塞。 14 3.如果没有人正在等待channel的数据,发送方会阻塞。 15 4.从一个close的channel取数据永远不会阻塞,同时获取的是默认值 16 */ 17 18 19 func Print_url(url string) { 20 res,err := http.Get(url) 21 if err != nil { 22 log.Fatal("11111",err) 23 } 24 defer res.Body.Close() 25 fmt.Printf("网页的状态返回码是:%v\n",res.Status) 26 27 } 28 29 func work(resave chan string,wg *sync.WaitGroup) { 30 31 for { 32 url,ok := <- resave //如果channel里面没有数据,接收方会阻塞。用url,ok两个参数来接受channel,可以从channel会返回两个参数。url表示接受的数据。ok接受的信息是channel是否结束。 33 //fmt.Println(url,ok) 34 if !ok { //判断channel是否关闭。 35 break 36 } 37 Print_url(url) 38 } 39 40 //for i := range resave { //range语法一值在接受数据,而channel可以源源不断的往里面添加数据。从一个close的channel取数据永远不会阻塞,同时获取的是默认值。 41 // Print_url(i) 42 //} 43 wg.Done() 44 } 45 46 func main() { 47 wg := new(sync.WaitGroup) 48 //var num = 3 49 //make_string := make(chan string) 50 //for i := 0;i{ 51 // go work(make_string,wg) 52 //} 53 //wg.Add(num) 54 55 make_string := make(chan string) 56 for i := 0;i<3 ;i++ { 57 wg.Add(1) //启用的协程数和add的进程池保持一致。 58 go work(make_string,wg) 59 } 60 61 urls := []string{"http://www.baidu.com","http://www.qq.com","http://www.weixin.com"} 62 for _,i := range urls { 63 make_string <- i //如果没有人正在等待channel的数据,发送方会阻塞。 64 } 65 close(make_string) //channel就好像一个传送带,可以源源不断的往里面放数据,只要不close就可以永远发送数据。 66 //time.Sleep(5 * time.Second) 67 wg.Wait() //等待 68 } 69 70 71 72 #以上代码执行结果如下: 73 网页的状态返回码是:200 OK 74 网页的状态返回码是:200 OK 75 网页的状态返回码是:200 OK
七.爬虫进阶之路;
在我们想要写出来一个爬虫出来,我们首先得了解几个模块,知道它的用法,这样我们才能写出一个真正的爬虫,接下来跟我一起看看常用的几个模块吧。
1."net/http"模块用法展示;
"net/http"模块可用于爬去url的内容。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:[email protected] 6 */ 7 8 package main 9 10 import ( 11 "net/http" 12 "log" 13 "io" 14 "os" 15 ) 16 17 func main() { 18 url := "http://www.xiaohuar.com" //定义一个URl,也就是我们要爬的网站。 19 resp,err := http.Get(url) //获取url的内容。 20 if err != nil { 21 log.Fatal(err) 22 } 23 defer resp.Body.Close() //千万要关闭链接,不然会造成资源泄露。 24 if resp.StatusCode != http.StatusOK{ //如果返回状态出现错误,就抛出错误。 25 log.Fatal(resp.Status) 26 } 27 io.Copy(os.Stdout,resp.Body) //将正常的结果输出到屏幕上,并不会占用内存。 28 }
1 [root@yinzhengjie tmp]# more http.go 2 package main 3 4 import ( 5 "net/http" 6 "log" 7 "io" 8 "os" 9 ) 10 11 func main() { 12 url := "http://www.xiaohuar.com" //定义一个URl,也就是我们要爬的网站。 13 resp,err := http.Get(url) 14 if err != nil { 15 log.Fatal(err) 16 } 17 defer resp.Body.Close() //千万要关闭链接,不然会造成资源泄露。 18 if resp.StatusCode != http.StatusOK{ //如果返回状态出现错误,就抛出错误。 19 log.Fatal(resp.Status) 20 } 21 io.Copy(os.Stdout,resp.Body) //将结果输出到屏幕上,并不会占用内存。 22 } 23 24 [root@yinzhengjie tmp]# 25 [root@yinzhengjie tmp]# 26 [root@yinzhengjie tmp]# go run http.go 27 "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 28 "http://www.w3.org/1999/xhtml"> 29 30 "Content-Type" content="text/html; charset=gb2312"/> 31 "Cache-Control" content="no-transform"/> 32 "Cache-Control" content="no-siteapp"/> 33 "alternate" media="only screen and(max-width: 640px)" href="http://m.xiaohuar.com/"> 34-УУtitle>"keywords" content="УУ 35 36 "description" content="2015УУУƬУѧУУ"> 37 "Shortcut Icon" type="image/x-icon" href="http://www.xiaohuar.com/favicon.ico"/> 38 "text/css" rel="stylesheet" href="http://www.xiaohuar.com/skin/meizi/css/global.css"/> 39 "text/css" rel="stylesheet" href="http://www.xiaohuar.com/skin/meizi/css/index2.css"/> 40 "http://www.xiaohuar.com/skin/meizi/css/a.css" rel="stylesheet" type="text/css"/> 41 42 43 44 45 46 47 "qc:admins" content="10572731676011705126375"/> 48 49 50class="g-hd">51class="m-nav">class="m-logo">"http://www.xiaohuar.com" title="У">У
"menu-nav" class="main-menu">
- "menu-item-14599" class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-14599">"" href="http://www.xiaohuar.com/">
- "menu-item-32780" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-32780">"Уhref="http://www.xiaohuar.com/hua/">Уa>
- "menu-item-32781" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-32781">"Уhref="http://www.xiaohuar.com/2014.html">Уa>
- "menu-item-32783" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-32783">"Уhref="http://www.xiaohuar.com/xiaocao/">Уa>
- "menu-item-32782" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-32782">"УƵ" href="http://www.xiaohuar.com/v/">
- "menu-item-14595">"У href="http://www.xiaohuar.com/mm/">Уa>
- "menu-item-14596" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-14596">"Уhref="http://www.xiaohuar.com/nvshen/" target="_blank">Ůa>
"searchform">"margin-top:80px;"> 52class="jiaodian"> 53 5472"inner"> 5567 70 71class="hot-event"> 5666class="switch-nav">"#" οnclick="return false;" class="prev">class="ico i-prev">class="hide-clip">span>class="blackbg">"#" οnclick="return false;" class="next">class="ico i-next">class="hide-clip">span>class="blackbg">57class="event-item" style="display: block;">"http://www.xiaohuar.com/html/zhongxue/" target="_blank" class="banner">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/images/banner/2.jpg" class="photo" style="width: 1000px; height: 400px;" alt="Ůϲ˽>"event-item" style="display: none;">"http://www.xiaohuar.com/html/dasai/" target="_blank" class="banner">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/images/banner/3.jpg" class="photo" style="width: 1000px; height: 400px;" alt="д>class="event-item" style="display: none;">"http://www.xiaohuar.com/p-6-27.html" target="_blank" class="banner">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/images/banner/4.jpg" class="photo" style="width: 1000px; height: 400px;" alt="ɭ>"event-item" style="display: none;">"http://www.xiaohuar.com/p-6-26.html" target="_blank" class="banner">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/images/banner/5.jpg" class="photo" style="width: 1000px; height: 400px;" alt=""/>"event-item" style="display: none;">"http://www.xiaohuar.com/p-6-25.html" target="_blank" class="banner">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/images/banner/6.jpg" class="photo" style="width: 1000px; height: 400px;" alt="ʷ欶/>58class="switch-tab"> 59 "#" οnclick="return false;" hidefocus="true" class="current">1 60 "#" οnclick="return false;" hidefocus="true">2 61 "#" οnclick="return false;" hidefocus="true">3 62 "#" οnclick="return false;" hidefocus="true">4 63 "#" οnclick="return false;" hidefocus="true">5 6465class="all_1000"> 73class="jingxuan "> 74以上代码执行结果在这里class="title1000">83class="jingxuan ">79class="title1000"> 7578class="titleleft">"http://www.xiaohuar.com/news/" target="_blank">Уa>|"http://www.xiaohuar.com/meinv/" target="_blank">|"http://www.xiaohuar.com/2014.html" target="_blank">У|"http://www.xiaohuar.com/daxue/" target="_blank">Уa>|"http://www.xiaohuar.com/hot/" target="_blank">"float:right;padding-top:10px;">77class="img1000"> 808281
- "http://www.xiaohuar.com/hua/" target="_blank" title="У"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/images/banner/a.jpg" alt="У>
- "http://www.xiaohuar.com/xiaocao/" target="_blank" title="У"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/images/banner/b.jpg" alt="У>
- "http://www.xiaohuar.com/mm/" target="_blank" title="У"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/images/banner/c.jpg" alt="У>
- "http://www.xiaohuar.com/meinv/" target="_blank" title="">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/images/banner/d.jpg" alt=""/>
class="clear">class="adv100090" style="margin-top: 15px;text-align: center;padding: 20px 0px;background-color: #f5f5f5;"> 87 8889class="all_lanmu "> 90 92105class="twoline"> 93
104- "http://www.xiaohuar.com/p-1-1933.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170628/f3d06ef49965aedbe18286a2f221fd9f.jpg"/>"http://www.xiaohuar.com/p-1-1933.html" target="_blank">ҵѧԺУspan>class="b1">ҵѧԺclass="b2">81
94- "http://www.xiaohuar.com/p-1-1932.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170626/0ab1d89f54c90df477a90aa533ceea36.jpg"/>"http://www.xiaohuar.com/p-1-1932.html" target="_blank">ְҵѧԺУclass="b1">ְҵѧԺclass="b2">4
95- "http://www.xiaohuar.com/p-1-1931.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170619/e0456729d4dcbea569a1acbc6a47ab69.jpg"/>"http://www.xiaohuar.com/p-1-1931.html" target="_blank">ְҵѧԺУclass="b1">ְҵѧԺclass="b2">21
96- "http://www.xiaohuar.com/p-1-1928.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170612/1f6620771e2815d21f37d481fa8311e6.png"/>"http://www.xiaohuar.com/p-1-1928.html" target="_blank">ɽУclass="b1">ɽclass="b2">32
97- "http://www.xiaohuar.com/p-1-1926.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170604/ec3794d0d42b538bf4461a84dac32509.jpg"/>"http://www.xiaohuar.com/p-1-1926.html" target="_blank">ʵclass="b1">ʵb>class="b2">36
98- "/p-1-338.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150313150700127.jpg"/>"/p-1-338.html" target="_blank">ѧԺУѩccclass="b1">ѧԺclass="b2">106
99- "/p-1-165.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150306205302174.jpg"/>"/p-1-165.html" target="_blank">ѧԺУclass="b1">ѧԺclass="b2">78
100- "http://www.xiaohuar.com/p-1-667.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150716115704192.jpg"/>"http://www.xiaohuar.com/p-1-667.html" target="_blank">ѧԺУspan>class="b1">ѧԺclass="b2">150
101- "/p-1-390.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150313162704133.jpg"/>"/p-1-390.html" target="_blank">Уclass="b1">class="b2">351
102- "/p-1-363.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/aaa5491c03fce0c6c3806c838fd64980.jpg"/>"/p-1-363.html" target="_blank">Уclass="b1">class="b2">220
103class="all_1000"> 106254class="title1000">108class="more">107class="mx_left"> 109123class="mx240"> 110117class="img240 piclunbo"> 111 "http://www.xiaohuar.com/hot/188.html" class='on' target="_blank">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20160328/1459134125894888.jpg" width="240" height="150" alt="ǫעǫעpan>"http://www.xiaohuar.com/p-5-148.html" target="_blank">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20151027/1445918569133368.jpg" width="240" height="150" alt="ѧԺУ>ѧԺУspan> 112 "http://www.xiaohuar.com/p-5-145.html" target="_blank">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20151026/1445832517110699.jpg" width="240" height="150" alt="pan> 113114
- class='kuang'>"javascript:;">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20160328/1459134125894888.jpg" width="72" height="50" alt="ǫע
- "javascript:;">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20151027/1445918569133368.jpg" width="72" height="50" alt="ѧԺУ>
115- "javascript:;">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20151026/1445832517110699.jpg" width="72" height="50" alt="
116class="mx240_list"> 118 119122120
121- "http://www.xiaohuar.com/news-1-1933.html" target="_blank" title="">ҵѧԺУa>
- "http://www.xiaohuar.com/news-1-1932.html" target="_blank" title="ְҵѧԺУ
- "http://www.xiaohuar.com/news-1-1931.html" target="_blank" title="֣">ְҵѧԺУ
- "http://www.xiaohuar.com/news-1-1928.html" target="_blank" title="ɽУ
- "http://www.xiaohuar.com/hot/188.html" target="_blank" title="ǫע
- "http://www.xiaohuar.com/hot/183.html" target="_blank" title="ϲ">ϲ
- "http://www.xiaohuar.com/hot/182.html" target="_blank" title="MM">MM
- "http://www.xiaohuar.com/hot/179.html" target="_blank" title="ŮChoi Somi)ʾ">ŮChoi Somi)ʾ
- "http://www.xiaohuar.com/hot/168.html" target="_blank" title="ô">ô
class="mx_con"> 124176class="mx_con_top"> 125 126130class="div2">128class="img125120"> 127 "http://www.xiaohuar.com/p-1-1548.html" target="_blank">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" width="125" lazysrc="/d/file/20160412/434d0f660ad823fa3d0b12b115a6af99.jpg"/>ӯclass="clearh10">class="div2">129class="clearh10">class="mx_con_down"> 131139class="title470">Ůdiv> 132138class="ulbox"> 133137136
- "http://www.xiaohuar.com/p-5-48.html" target="_blank">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/news/20150815/1439615307134745.jpg" alt=">span>
- "http://www.xiaohuar.com/p-5-49.html" target="_blank">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/news/20150815/1439615732117201.jpg" alt=">span>
- "http://www.xiaohuar.com/p-5-47.html" target="_blank">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/news/20150815/1439615048116633.jpg" alt=">span>
- "http://www.xiaohuar.com/p-1-681.html" target="_blank">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/news/20150815/1439616247184348.jpg" alt=">span>
- "http://www.xiaohuar.com/p-1-749.html" target="_blank">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://img.1985t.com/uploads/previews/2014/12/0-rcAIKA.jpg" alt=">span>
- "http://www.xiaohuar.com/p-1-136.html" target="_blank">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://img.1985t.com/uploads/previews/2014/12/0-ywgsac.jpg" alt=">span>
134class="clear">135class="mx_right"> 140175class="mx_alaal">153class="title240">Уѯclass="mx_search"> 141 148149class="taglist_outer">152class="taglist">
150- /dt>
- "div_genre" data='quyu'>"#" data="1">"#" data="2">"#" data="3">Ůa>"#" data="4">
class="tagsearch">Уa href="http://www.xiaohuar.com/p-1-3.html" target="_blank">MM"http://www.xiaohuar.com/p-1-563.html" target="_blank">С"http://www.xiaohuar.com/daxue/xiamen/" target="_blank">"http://www.xiaohuar.com/p-1-95.html" target="_blank">a>"http://www.xiaohuar.com/p-1-136.html" target="_blank">a>"http://www.xiaohuar.com/p-1-169.html" target="_blank">a>"http://www.xiaohuar.com/p-1-290.html" target="_blank">a>"http://www.xiaohuar.com/p-1-5.html" target="_blank">151class="big_lunhuan"> 154 155174class="mod-hd">156 157 158 159 167class="mod-hd-title">class="accordion-news-side"> 168172 173class="mypicchange"> 169171170
- class='on'>
class="all_lanmu "> 177191class="title1000">178class="twoline"> 179
190- "http://www.xiaohuar.com/p-4-639.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150221175512120.jpg"/>"http://www.xiaohuar.com/p-4-639.html" target="_blank">ʯʨѧУclass="b1">ʯʨѧclass="b2">91
180- "http://www.xiaohuar.com/p-4-706.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/d33b2cae4fdfa7110fa8049db325838f.jpg"/>"http://www.xiaohuar.com/p-4-706.html" target="_blank">loly~~~~~~~У~~~~class="b1">loly~~~~~~~class="b2">69
181- "http://www.xiaohuar.com/p-4-486.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150414092659161.jpg"/>"http://www.xiaohuar.com/p-4-486.html" target="_blank">УֱгŴ˽span>class="b1">class="b2">75
182- "http://www.xiaohuar.com/p-4-691.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/9bfe870df5ea859c219b6f2733e513b1.jpg"/>"http://www.xiaohuar.com/p-4-691.html" target="_blank">Уclass="b1">class="b2">85
183- "http://www.xiaohuar.com/p-4-1122.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20160109/7f860f71d979a57531132f91677376bb.jpg"/>"http://www.xiaohuar.com/p-4-1122.html" target="_blank">Уspan>class="b1">class="b2">84
184- "http://www.xiaohuar.com/p-4-867.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20151003/11f8c32b40eab5269d18e68d51185d8d.jpg"/>"http://www.xiaohuar.com/p-4-867.html" target="_blank">class="b1">b>class="b2">64
185- "http://www.xiaohuar.com/p-4-1099.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20151231/ddb79b6dcdbc876059cd6db9730d7656.jpg"/>"http://www.xiaohuar.com/p-4-1099.html" target="_blank">DZɽҰկУclass="b1">DZɽҰկclass="b2">48
186- "http://www.xiaohuar.com/p-4-797.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20150902/890c8a533c0346c19bb84ff90a36e4fd.jpg"/>"http://www.xiaohuar.com/p-4-797.html" target="_blank">Уclass="b1">class="b2">58
187- "http://www.xiaohuar.com/p-4-922.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20151103/d89e18e42269f9169dfcffba836f2795.jpg"/>"http://www.xiaohuar.com/p-4-922.html" target="_blank">ְҵѧԺУclass="b1">ְҵѧԺclass="b2">58
188- "http://www.xiaohuar.com/p-4-1114.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20160107/776911c54ae5ed4f0fe1c3652ce755da.jpg"/>"http://www.xiaohuar.com/p-4-1114.html" target="_blank">Уclass="b1">class="b2">188
189class="all_lanmu "> 192206class="title1000">193class="twoline"> 194
205- "http://www.xiaohuar.com/p-2-1930.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170613/814725f45667309a6066e93b1ad2e378.jpg"/>"http://www.xiaohuar.com/p-2-1930.html" target="_blank">Уclass="b1">class="b2">1
195- "http://www.xiaohuar.com/p-2-1927.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170608/f07501a9d1fe9945e2fb96f0890a8d23.jpg"/>"http://www.xiaohuar.com/p-2-1927.html" target="_blank">ʦѧУspan>class="b1">ʦѧclass="b2">1600
196- "http://www.xiaohuar.com/p-2-1915.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170601/b5ceb0d78d4e2d15f5bf3e9085fdc638.jpg"/>"http://www.xiaohuar.com/p-2-1915.html" target="_blank">Уclass="b1">class="b2">1
197- "http://www.xiaohuar.com/p-2-1907.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170528/68f95c381d71baeb3290cf686f75cf6e.jpg"/>"http://www.xiaohuar.com/p-2-1907.html" target="_blank">ѧУ˼class="b1">ѧclass="b2">1
198- "http://www.xiaohuar.com/p-2-1900.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170505/6de1dfa7b06149a8e4f58d4531f1e0a6.jpg"/>"http://www.xiaohuar.com/p-2-1900.html" target="_blank">һСУclass="b1">һСclass="b2">1
199- "http://www.xiaohuar.com/p-2-1899.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170504/b44a79761757d24941c3f1205630f265.jpg"/>"http://www.xiaohuar.com/p-2-1899.html" target="_blank">ѧԺУkeyclass="b1">ѧԺclass="b2">3
200- "http://www.xiaohuar.com/p-2-1880.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170416/55e0a68c6d7b985dca286f24b4a0b4ed.jpg"/>"http://www.xiaohuar.com/p-2-1880.html" target="_blank">Уclass="b1">class="b2">2
201- "http://www.xiaohuar.com/p-2-1877.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170413/31572d773f2117c4dd3c1a4552fb64c9.jpg"/>"http://www.xiaohuar.com/p-2-1877.html" target="_blank">ѧУУԣspan>class="b1">ѧУclass="b2">2
202- "http://www.xiaohuar.com/p-2-1876.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170413/aaeaa82b8eccb31323153201f0d35c69.jpg"/>"http://www.xiaohuar.com/p-2-1876.html" target="_blank">ѧԺУspan>class="b1">ѧԺclass="b2">3
203- "http://www.xiaohuar.com/p-2-1868.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20170404/e1bc3ee2190f02b13a4b65fa78839df8.jpg"/>"http://www.xiaohuar.com/p-2-1868.html" target="_blank">У.Уclass="b1">У.class="b2">3
204class="all_lanmu "> 207221class="title1000">208class="twoline"> 209
220- "http://www.xiaohuar.com/p-6-36.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20151112/6c4f48884832ea2700695b2849628ac5.jpg"/>"http://www.xiaohuar.com/p-6-36.html" target="_blank">ԡclass="b1">2015-11-12class="b2">7445
210- "http://www.xiaohuar.com/p-6-4.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150503184242161.jpg"/>"http://www.xiaohuar.com/p-6-4.html" target="_blank">90rbieͯҡclass="b1">2015-05-03class="b2">4499
211- "http://www.xiaohuar.com/p-6-26.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150814223831181.jpg"/>"http://www.xiaohuar.com/p-6-26.html" target="_blank">class="b1">2015-08-14class="b2">10647
212- "http://www.xiaohuar.com/p-6-44.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20160408/40e4e29b7156e316d4f877d8d0906ff7.jpg"/>"http://www.xiaohuar.com/p-6-44.html" target="_blank">Ϫдspan>class="b1">2016-04-08class="b2">4635
213- "http://www.xiaohuar.com/p-6-12.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150630151831172.jpg"/>"http://www.xiaohuar.com/p-6-12.html" target="_blank">̨ƷShowGirlҦ span>class="b1">2015-06-30class="b2">5374
214- "http://www.xiaohuar.com/p-6-24.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150713212708135.jpg"/>"http://www.xiaohuar.com/p-6-24.html" target="_blank">MiuMiu class="b1">2015-07-13class="b2">5493
215- "http://www.xiaohuar.com/p-6-43.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20160408/8434145de5a9bcd6f06e06a780b8a8b3.jpg"/>"http://www.xiaohuar.com/p-6-43.html" target="_blank">class="b1">2016-04-08class="b2">2137
216- "http://www.xiaohuar.com/p-6-17.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150702184343113.jpg"/>"http://www.xiaohuar.com/p-6-17.html" target="_blank">34E~ʯùpan>class="b1">2015-07-02class="b2">2935
217- "http://www.xiaohuar.com/p-6-11.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="http://www.xiaohuar.com/d/file/20150602175624110.jpg"/>"http://www.xiaohuar.com/p-6-11.html" target="_blank">һ˿COSspan>class="b1">2015-06-02class="b2">3419
218- "http://www.xiaohuar.com/p-6-42.html" target="_blank" class="xhpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20160408/bf5819982372761ea8c2bcade410fb9b.jpg"/>"http://www.xiaohuar.com/p-6-42.html" target="_blank">ģѩдspan>class="b1">2016-04-08class="b2">2587
219class="all_lanmu "> 222235class="title1000">223class="oneline" style="height: 230px;">
234- "http://www.xiaohuar.com/p-3-97.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20161208/878a9b4f94d401a8c2651f2b04f8c94e.jpg"/>"http://www.xiaohuar.com/p-3-97.html" target="_blank">,СŶclass="b1">2016-12-08class="b2">9356
224- "http://www.xiaohuar.com/p-3-96.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20161113/adbdd1dd3924922398f2f6efc31ffee7.jpg"/>"http://www.xiaohuar.com/p-3-96.html" target="_blank">ҡƵclass="b1">2016-11-13class="b2">6575
225- "http://www.xiaohuar.com/p-3-95.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20161103/c7b58bfaf538f2ede89a4f60b1ecc29b.jpg"/>"http://www.xiaohuar.com/p-3-95.html" target="_blank">ֱ˿class="b1">2016-11-03class="b2">10782
226- "http://www.xiaohuar.com/p-3-94.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20161102/68e926a6a685b1ee0a012e89d626397a.jpg"/>"http://www.xiaohuar.com/p-3-94.html" target="_blank">class="b1">2016-11-02class="b2">5220
227- "http://www.xiaohuar.com/p-3-93.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20161102/4bb76725c4d4ac5077b9a1c594c5cbb2.jpg"/>"http://www.xiaohuar.com/p-3-93.html" target="_blank">Ƶclass="b1">2016-11-02class="b2">14255
228- "http://www.xiaohuar.com/p-3-92.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20161027/f070412c9571ee1e5cbde31a816f3bad.jpg"/>"http://www.xiaohuar.com/p-3-92.html" target="_blank">˿span>class="b1">2016-10-27class="b2">7523
229- "http://www.xiaohuar.com/p-3-91.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20161027/185dc525e53fcd53cc30dd9e94f41114.jpg"/>"http://www.xiaohuar.com/p-3-91.html" target="_blank">class="b1">2016-10-27class="b2">8720
230- "http://www.xiaohuar.com/p-3-90.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20161016/e846aa103fe104b54b4e8a9ede378b9d.jpg"/>"http://www.xiaohuar.com/p-3-90.html" target="_blank">ԡspan>class="b1">2016-10-16class="b2">8271
231- "http://www.xiaohuar.com/p-3-89.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20161016/64a7e1893ccbc07a302a176480df3e79.jpg"/>"http://www.xiaohuar.com/p-3-89.html" target="_blank">ɬ ͬһŮclass="b1">2016-10-16class="b2">8097
232- "http://www.xiaohuar.com/p-3-88.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20160619/5c3ede0e1d50f38adbfe8c34afd46771.jpg"/>"http://www.xiaohuar.com/p-3-88.html" target="_blank">class="b1">2016-06-19class="b2">14526
233class="all_lanmu "> 236249class="title1000">237class="oneline" style="height: 230px;">
248- "http://www.xiaohuar.com/p-5-25.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/bac1f0d8253b4e157fbf40b8a3edab56.jpg"/>"http://www.xiaohuar.com/p-5-25.html" target="_blank">У/span>class="b1">2015-07-16class="b2">2147
238- "http://www.xiaohuar.com/p-5-50.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/a0bbfc787c3179a029155871063cee0f.jpg"/>"http://www.xiaohuar.com/p-5-50.html" target="_blank">span>class="b1">2015-08-15class="b2">3856
239- "http://www.xiaohuar.com/p-5-33.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20150807/1438960820583080.jpg"/>"http://www.xiaohuar.com/p-5-33.html" target="_blank">̨ ̨class="b1">2015-08-07class="b2">2874
240- "http://www.xiaohuar.com/p-5-51.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/9520c71801cd4896ff3c7346b542b84d.jpg"/>"http://www.xiaohuar.com/p-5-51.html" target="_blank">Уclass="b1">2015-08-15class="b2">2430
241- "http://www.xiaohuar.com/p-5-71.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20150830/576cf065a7d34716f0a8c3b27c546098.jpg"/>"http://www.xiaohuar.com/p-5-71.html" target="_blank">רԺУspan>class="b1">2015-08-30class="b2">3263
242- "http://www.xiaohuar.com/p-5-105.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20151017/1445074354107162.jpg"/>"http://www.xiaohuar.com/p-5-105.html" target="_blank">ѧԺУ˭class="b1">2015-10-17class="b2">1639
243- "http://www.xiaohuar.com/p-5-54.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20150817/1439782814996443.jpg"/>"http://www.xiaohuar.com/p-5-54.html" target="_blank">Ƭclass="b1">2015-08-17class="b2">2582
244- "http://www.xiaohuar.com/p-5-39.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20150812/1439349313115531.jpg"/>"http://www.xiaohuar.com/p-5-39.html" target="_blank">¶ǰspan>class="b1">2015-08-12class="b2">1251
245- "http://www.xiaohuar.com/p-5-69.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/20150828/533b346740f18ad15551a3983f3ec333.jpg"/>"http://www.xiaohuar.com/p-5-69.html" target="_blank">УУԪspan>class="b1">2015-08-28class="b2">1465
246- "http://www.xiaohuar.com/p-5-145.html" target="_blank" class="vpic">"http://www.xiaohuar.com/skin/meizi/images/grey.gif" lazysrc="/d/file/news/20151026/1445832517110699.jpg"/>"http://www.xiaohuar.com/p-5-145.html" target="_blank">pan>class="b1">2015-10-26class="b2">2540
247class="friendlinks">253class="linkbt">"http://www.dxsabc.com/" target="_blank"> "http://www.7kk.com/" target="_blank">ͼƬ 250 "http://hufu.onlylady.com/" target="_blank"> "http://www.cooltuku.com" target="_blank"> "http://www.4j4j.cn" target="_blank"> "http://www.omtxw.com" target="_blank">ŷ"http://www.17sucai.com" target="_blank">a> "http://www.iqingren.com" target="_blank">a> "http://www.zhw123.cc">ŮͼƬ "http://www.xiaohuar.com/" target="_blank">Уa>"http://jiaoyu.baidu.com/beauty/index/" rel="nofollow" target="_blank">ѧa> "http://www.sumiaozhijia.com/" target="_blank"> "http://www.zeihaoxiao.com/" target="_blank">Ц "http://www.showself.com" target="_blank"> "http://www.xiannvw.com" target="_blank"> 251
252class="indexfooter"> 255259 260 261 272 284 288 289 290 [root@yinzhengjie tmp]#class="foot">258class="f_about">256"http://www.xiaohuar.com/">У href="http://www.xiaohuar.com/">ȫѧУƬɢͬУͼƬ href="http://www.xiaohuar.com/">УƬԭУƬr/>"http://www.xiaohuar.com/html/sitemap.htm">Уa> © 2009-2015 All Rights Reserved www.xiaohuar.com class="__cf_email__" href="/cdn-cgi/l/email-protection" data-cfemail="c0f2f1f1f2f4f9f2f3f680b1b1eea3afad">[email protected] P006982
257
2.“net/url”模块用法展示;
“net/url”模块中我们会用到一个解析方法,它可以解析url使用的协议,主机名,当前路径,请求信息,用户信息,当前锚点等等。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import ( 11 "os" 12 "net/url" 13 "log" 14 "fmt" 15 ) 16 17 func main() { 18 s := os.Args[1] 19 u,err := url.Parse(s) 20 if err != nil { 21 log.Fatal(err) 22 } 23 fmt.Println("使用的协议是:",u.Scheme) 24 fmt.Println("主机名称是:",u.Host) 25 fmt.Println("当前路径是:",u.Path) 26 fmt.Println("请求信息是:",u.RawQuery) 27 fmt.Println("用户信息是:",u.User) 28 fmt.Println("当前的锚点是:",u.Fragment) 29 }以上代码用法展示戳这里1 [root@yinzhengjie tmp]# more url.go 2 /* 3 #!/usr/bin/env gorun 4 @author :yinzhengjie 5 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 6 EMAIL:y1053419035@qq.com 7 */ 8 9 package main 10 11 import ( 12 "os" 13 "net/url" 14 "log" 15 "fmt" 16 ) 17 18 func main() { 19 s := os.Args[1] 20 u,err := url.Parse(s) 21 if err != nil { 22 log.Fatal(err) 23 } 24 fmt.Println("使用的协议是:",u.Scheme) 25 fmt.Println("主机名称是:",u.Host) 26 fmt.Println("当前路径是:",u.Path) 27 fmt.Println("请求信息是:",u.RawQuery) 28 fmt.Println("用户信息是:",u.User) 29 fmt.Println("当前的锚点是:",u.Fragment) 30 } 31 [root@yinzhengjie tmp]# 32 [root@yinzhengjie tmp]# 33 [root@yinzhengjie tmp]# go run url.go http://www.cnblogs.com/yinzhengjie/p/7202796.html 34 使用的协议是: http 35 主机名称是: www.cnblogs.com 36 当前路径是: /yinzhengjie/p/7202796.html 37 请求信息是: 38 用户信息是:39 当前的锚点是: 40 [root@yinzhengjie tmp]#
3.goquery模块用法展示;
做过 Web 开发的,应该都用过或听过 jQuery,它提供了方便的操作 DOM 的 API。使用 Go 语言做服务器端开发,有时候需要解析 HTML 文件,比如抓取网站内容、写一个爬虫等。这时候如果有一个类似 jQuery 的库可以使用,操作 DOM 会很方便,而且,上手也会很快。github.com/PuerkitoBio/goquery 这个库就实现了类似 jQuery 的功能,让你能方便的使用 Go 语言操作 HTML 文档。
首先,要强调一点,要执行以下代码需要安装一个goquery模块,该模块用来爬去网站的内容的简直就是一个神器啊。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import ( 11 "net/http" 12 "log" 13 "github.com/PuerkitoBio/goquery" 14 "fmt" 15 ) 16 17 18 /* 19 用goquery可以快速获取url的标签。 20 */ 21 22 func main() { 23 url := "http://www.xiaohuar.com" //定义一个URl,也就是我们要爬的网站。 24 resp,err := http.Get(url) 获取url的内容,包括请求头信息都在里面放着的。 25 26 if err != nil { 27 log.Fatal(err) 28 } 29 defer resp.Body.Close() //千万要关闭链接,不然会造成资源泄露。 30 if resp.StatusCode != http.StatusOK{ //如果返回状态出现错误,就抛出错误并终止程序。 31 log.Fatal(resp.Status) 32 } 33 //io.Copy(os.Stdout,resp.Body) //将结果输出到屏幕上,并不会占用内存。 34 doc,err := goquery.NewDocumentFromResponse(resp) //对resp进行过滤,最终会拿到首页路径url 35 if err != nil { 36 log.Fatal(err) 37 } 38 doc.Find("img").Each(func(i int, s *goquery.Selection) { /*表示找到"img"的标签然后用Each方法遍历每一个图片路径。*/ 39 link,ok := s.Attr("src") //找到“img”标签后会将其的“src”的路径找到,最终也就找到了图片的路径。 40 if ok { 41 fmt.Println(link) //如果存在“src”路径就打印 42 }else { 43 fmt.Println("抱歉,没有发现该路径。") 44 } 45 }) 46 }以上代码执行方式结果戳这里哟1 [root@yinzhengjie tmp]# more goquery.go 2 /* 3 #!/usr/bin/env gorun 4 @author :yinzhengjie 5 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 6 EMAIL:y1053419035@qq.com 7 */ 8 9 package main 10 11 import ( 12 "net/http" 13 "log" 14 "github.com/PuerkitoBio/goquery" 15 "fmt" 16 ) 17 18 19 /* 20 用goquery可以快速获取url的标签。 21 */ 22 23 func main() { 24 url := "http://www.xiaohuar.com" //定义一个URl,也就是我们要爬的网站。 25 resp,err := http.Get(url) 获取url的内容,包括请求头信息都在里面放着的。 26 27 if err != nil { 28 log.Fatal(err) 29 } 30 defer resp.Body.Close() //千万要关闭链接,不然会造成资源泄露。 31 if resp.StatusCode != http.StatusOK{ //如果返回状态出现错误,就抛出错误并终止程序。 32 log.Fatal(resp.Status) 33 } 34 //io.Copy(os.Stdout,resp.Body) //将结果输出到屏幕上,并不会占用内存。 35 doc,err := goquery.NewDocumentFromResponse(resp) //对resp进行过滤,最终会拿到首页路径url 36 if err != nil { 37 log.Fatal(err) 38 } 39 doc.Find("img").Each(func(i int, s *goquery.Selection) { /*表示找到"img"的标签然后用Each方法遍历每一个图片路径。*/ 40 link,ok := s.Attr("src") //找到“img”标签后会将其的“src”的路径找到,最终也就找到了图片的路径。 41 if ok { 42 fmt.Println(link) //如果存在“src”路径就打印 43 }else { 44 fmt.Println("抱歉,没有发现该路径。") 45 } 46 }) 47 } 48 49 [root@yinzhengjie tmp]# 50 [root@yinzhengjie tmp]# 51 [root@yinzhengjie tmp]# go run goquery.go 52 http://www.xiaohuar.com/skin/meizi/images/grey.gif 53 http://www.xiaohuar.com/skin/meizi/images/grey.gif 54 http://www.xiaohuar.com/skin/meizi/images/grey.gif 55 http://www.xiaohuar.com/skin/meizi/images/grey.gif 56 http://www.xiaohuar.com/skin/meizi/images/grey.gif 57 http://www.xiaohuar.com/skin/meizi/images/grey.gif 58 http://www.xiaohuar.com/skin/meizi/images/grey.gif 59 http://www.xiaohuar.com/skin/meizi/images/grey.gif 60 http://www.xiaohuar.com/skin/meizi/images/grey.gif 61 http://www.xiaohuar.com/skin/meizi/images/grey.gif 62 http://www.xiaohuar.com/skin/meizi/images/grey.gif 63 http://www.xiaohuar.com/skin/meizi/images/grey.gif 64 http://www.xiaohuar.com/skin/meizi/images/grey.gif 65 http://www.xiaohuar.com/skin/meizi/images/grey.gif 66 http://www.xiaohuar.com/skin/meizi/images/grey.gif 67 http://www.xiaohuar.com/skin/meizi/images/grey.gif 68 http://www.xiaohuar.com/skin/meizi/images/grey.gif 69 http://www.xiaohuar.com/skin/meizi/images/grey.gif 70 http://www.xiaohuar.com/skin/meizi/images/grey.gif 71 http://www.xiaohuar.com/skin/meizi/images/grey.gif 72 http://www.xiaohuar.com/skin/meizi/images/grey.gif 73 http://www.xiaohuar.com/skin/meizi/images/grey.gif 74 http://www.xiaohuar.com/skin/meizi/images/grey.gif 75 http://www.xiaohuar.com/skin/meizi/images/grey.gif 76 http://www.xiaohuar.com/skin/meizi/images/grey.gif 77 http://www.xiaohuar.com/skin/meizi/images/grey.gif 78 http://www.xiaohuar.com/skin/meizi/images/grey.gif 79 http://www.xiaohuar.com/skin/meizi/images/grey.gif 80 http://www.xiaohuar.com/skin/meizi/images/grey.gif 81 http://www.xiaohuar.com/skin/meizi/images/grey.gif 82 http://www.xiaohuar.com/skin/meizi/images/grey.gif 83 http://www.xiaohuar.com/skin/meizi/images/grey.gif 84 http://www.xiaohuar.com/skin/meizi/images/grey.gif 85 http://www.xiaohuar.com/skin/meizi/images/grey.gif 86 http://www.xiaohuar.com/skin/meizi/images/grey.gif 87 http://www.xiaohuar.com/skin/meizi/images/grey.gif 88 http://www.xiaohuar.com/skin/meizi/images/grey.gif 89 http://www.xiaohuar.com/skin/meizi/images/grey.gif 90 http://www.xiaohuar.com/skin/meizi/images/grey.gif 91 http://www.xiaohuar.com/skin/meizi/images/grey.gif 92 http://www.xiaohuar.com/skin/meizi/images/grey.gif 93 http://www.xiaohuar.com/skin/meizi/images/grey.gif 94 http://www.xiaohuar.com/skin/meizi/images/grey.gif 95 http://www.xiaohuar.com/skin/meizi/images/grey.gif 96 http://www.xiaohuar.com/skin/meizi/images/grey.gif 97 http://www.xiaohuar.com/skin/meizi/images/grey.gif 98 http://www.xiaohuar.com/skin/meizi/images/grey.gif 99 http://www.xiaohuar.com/skin/meizi/images/grey.gif 100 http://www.xiaohuar.com/skin/meizi/images/grey.gif 101 http://www.xiaohuar.com/skin/meizi/images/grey.gif 102 http://www.xiaohuar.com/skin/meizi/images/grey.gif 103 http://www.xiaohuar.com/skin/meizi/images/grey.gif 104 http://www.xiaohuar.com/skin/meizi/images/grey.gif 105 http://www.xiaohuar.com/skin/meizi/images/grey.gif 106 http://www.xiaohuar.com/skin/meizi/images/grey.gif 107 http://www.xiaohuar.com/skin/meizi/images/grey.gif 108 http://www.xiaohuar.com/skin/meizi/images/grey.gif 109 http://www.xiaohuar.com/skin/meizi/images/grey.gif 110 http://www.xiaohuar.com/skin/meizi/images/grey.gif 111 http://www.xiaohuar.com/skin/meizi/images/grey.gif 112 http://www.xiaohuar.com/skin/meizi/images/grey.gif 113 http://www.xiaohuar.com/skin/meizi/images/grey.gif 114 http://www.xiaohuar.com/skin/meizi/images/grey.gif 115 http://www.xiaohuar.com/skin/meizi/images/grey.gif 116 http://www.xiaohuar.com/skin/meizi/images/grey.gif 117 http://www.xiaohuar.com/skin/meizi/images/grey.gif 118 http://www.xiaohuar.com/skin/meizi/images/grey.gif 119 http://www.xiaohuar.com/skin/meizi/images/grey.gif 120 http://www.xiaohuar.com/skin/meizi/images/grey.gif 121 http://www.xiaohuar.com/skin/meizi/images/grey.gif 122 http://www.xiaohuar.com/skin/meizi/images/grey.gif 123 http://www.xiaohuar.com/skin/meizi/images/grey.gif 124 http://www.xiaohuar.com/skin/meizi/images/grey.gif 125 http://www.xiaohuar.com/skin/meizi/images/grey.gif 126 http://www.xiaohuar.com/skin/meizi/images/grey.gif 127 http://www.xiaohuar.com/skin/meizi/images/grey.gif 128 http://www.xiaohuar.com/skin/meizi/images/grey.gif 129 http://www.xiaohuar.com/skin/meizi/images/grey.gif 130 http://www.xiaohuar.com/skin/meizi/images/grey.gif 131 http://www.xiaohuar.com/skin/meizi/images/grey.gif 132 http://www.xiaohuar.com/skin/meizi/images/grey.gif 133 http://www.xiaohuar.com/skin/meizi/images/grey.gif 134 http://www.xiaohuar.com/skin/meizi/images/grey.gif 135 http://www.xiaohuar.com/skin/meizi/images/grey.gif 136 http://www.xiaohuar.com/skin/meizi/images/grey.gif 137 http://www.xiaohuar.com/skin/meizi/images/grey.gif 138 http://www.xiaohuar.com/skin/meizi/images/grey.gif 139 http://www.xiaohuar.com/skin/meizi/images/grey.gif 140 http://www.xiaohuar.com/skin/meizi/images/grey.gif 141 http://www.xiaohuar.com/skin/meizi/images/grey.gif 142 http://www.xiaohuar.com/skin/meizi/images/grey.gif 143 http://www.xiaohuar.com/skin/meizi/images/grey.gif 144 [root@yinzhengjie tmp]#如果你想要的代码扩展性更高,可以将main函数的代码定义成一个函数,这样在主函数调用该函数就好了,代码如下:
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import ( 11 "net/http" 12 "log" 13 "github.com/PuerkitoBio/goquery" 14 "fmt" 15 "errors" 16 ) 17 18 func fetch(url string) ([]string,error) { 19 var urls []string //定义一个空切片数组 20 resp,err := http.Get(url) 21 if err != nil { 22 log.Fatal(err) 23 } 24 defer resp.Body.Close() 25 if resp.StatusCode != http.StatusOK{ 26 return nil,errors.New(resp.Status) //表示当出现错误是,返回空列表,并将错误状态返回。 27 } 28 doc,err := goquery.NewDocumentFromResponse(resp) 29 if err != nil { 30 log.Fatal(err) 31 } 32 doc.Find("img").Each(func(i int, s *goquery.Selection) { 33 link,ok := s.Attr("src") 34 if ok { 35 urls = append(urls,link) //将过滤出来的图片路径都追加到urls的数组中去,最终返回给用户。 36 }else { 37 fmt.Println("抱歉,没有发现该路径。") 38 } 39 40 }) 41 return urls,nil 42 } 43 44 func main() { 45 url := "http://m.xiaohuar.com" //定义一个URl,也就是我们要爬的网站。注意这里不要用www,而要用m,因为m是用手机端方式访问。而www是电脑方式访问。 46 urls,err := fetch(url) 47 if err != nil { 48 log.Fatal(err) 49 } 50 for _,u := range urls { 51 fmt.Println(u) 52 } 53 54 }以上代码执行结果戳这里哟1 [root@yinzhengjie tmp]# more goquery.go 2 /* 3 #!/usr/bin/env gorun 4 @author :yinzhengjie 5 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 6 EMAIL:y1053419035@qq.com 7 */ 8 9 package main 10 11 import ( 12 "net/http" 13 "log" 14 "github.com/PuerkitoBio/goquery" 15 "fmt" 16 "errors" 17 ) 18 19 func fetch(url string) ([]string,error) { 20 var urls []string //定义一个空切片数组 21 resp,err := http.Get(url) 22 if err != nil { 23 log.Fatal(err) 24 } 25 defer resp.Body.Close() 26 if resp.StatusCode != http.StatusOK{ 27 return nil,errors.New(resp.Status) //表示当出现错误是,返回空列表,并将错误状态返回。 28 } 29 doc,err := goquery.NewDocumentFromResponse(resp) 30 if err != nil { 31 log.Fatal(err) 32 } 33 doc.Find("img").Each(func(i int, s *goquery.Selection) { 34 link,ok := s.Attr("src") 35 if ok { 36 urls = append(urls,link) //将过滤出来的图片路径都追加到urls的数组中去,最终返回给用户。 37 }else { 38 fmt.Println("抱歉,没有发现该路径。") 39 } 40 41 }) 42 return urls,nil 43 } 44 45 func main() { 46 url := "http://m.xiaohuar.com" //定义一个URl,也就是我们要爬的网站。注意这里不要用www,而要用m,因为m是用手机端方式访问。而w 47 ww是电脑方式访问。 48 urls,err := fetch(url) 49 if err != nil { 50 log.Fatal(err) 51 } 52 for _,u := range urls { 53 fmt.Println(u) 54 } 55 56 } 57 58 [root@yinzhengjie tmp]# 59 [root@yinzhengjie tmp]# 60 [root@yinzhengjie tmp]# go run goquery.go 61 http://www.xiaohuar.com/d/file/20170715/61110ba027f004fb503ff09cdee44d0c.jpg 62 http://www.xiaohuar.com/d/file/20170707/f7ca636f73937e33836e765b7261f036.jpg 63 http://www.xiaohuar.com/d/file/20170701/fb18711a6af87f30942d6a19f6da6b3e.jpg 64 http://www.xiaohuar.com/d/file/20170628/f3d06ef49965aedbe18286a2f221fd9f.jpg 65 http://www.xiaohuar.com/d/file/20170626/0ab1d89f54c90df477a90aa533ceea36.jpg 66 http://www.xiaohuar.com/d/file/20170619/e0456729d4dcbea569a1acbc6a47ab69.jpg 67 http://www.xiaohuar.com/d/file/20170612/1f6620771e2815d21f37d481fa8311e6.png 68 http://www.xiaohuar.com/d/file/20170604/ec3794d0d42b538bf4461a84dac32509.jpg 69 http://www.xiaohuar.com/d/file/20170603/e55f77fb3aa3c7f118a46eeef5c0fbbf.jpg 70 http://www.xiaohuar.com/d/file/20170603/c34b29f68e8f96d44c63fe29bf4a66b8.jpg 71 http://www.xiaohuar.com/d/file/20170529/e5902d4d3e40829f9a0d30f7488eab84.jpg 72 http://www.xiaohuar.com/d/file/20170529/8140c4ad797ca01f5e99d09c82dd8a42.jpg 73 http://www.xiaohuar.com/d/file/20170528/b352258c83776b9a2462277dec375d0c.jpg 74 http://www.xiaohuar.com/d/file/20170527/4a7a7f1e6b69f126292b981c90110d0a.jpg 75 http://www.xiaohuar.com/d/file/20170520/dd21a21751e24a8f161792b66011688c.jpg 76 http://www.xiaohuar.com/d/file/20170516/6e295fe48c33245be858c40d37fb5ee6.jpg 77 http://www.xiaohuar.com/d/file/20170513/6121e3e90ff3ba4c9398121bda1dd582.jpg 78 http://www.xiaohuar.com/d/file/20170512/45fc9ed5d92c66f369b66841c58bd183.jpg 79 [root@yinzhengjie tmp]#
扩展:
我们在访问一个标签中的源数据,可能获取的路径不是完整路径,那么如何将获取的路径补充其应该对应的绝对路径呢?我们可以简单来实现一下,后期我们可以对其做一个优化。
1 /* 2 #!/usr/bin/env gorun 3 @author :yinzhengjie 4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:y1053419035@qq.com 6 */ 7 8 package main 9 10 import ( 11 "errors" 12 "fmt" 13 "github.com/PuerkitoBio/goquery" 14 "log" 15 "net/http" 16 "net/url" 17 "os" 18 "strings" 19 ) 20 21 func fetch(url string) ([]string, error) { //改函数会拿到我们想要的图片的路径。 22 var urls []string //定义一个空切片数组 23 resp, err := http.Get(url) 24 if err != nil { 25 log.Fatal(err) 26 } 27 defer resp.Body.Close() 28 if resp.StatusCode != http.StatusOK { 29 return nil, errors.New(resp.Status) //表示当出现错误是,返回空列表,并将错误状态返回。 30 } 31 doc, err := goquery.NewDocumentFromResponse(resp) 32 if err != nil { 33 log.Fatal(err) 34 } 35 doc.Find("img").Each(func(i int, s *goquery.Selection) { 36 link, ok := s.Attr("src") 37 if ok { 38 urls = append(urls, link) //将过滤出来的图片路径都追加到urls的数组中去,最终返回给用户。 39 } else { 40 fmt.Println("抱歉,没有发现该路径。") 41 } 42 43 }) 44 return urls, nil 45 } 46 47 func Clean_urls(root_path string, picture_path []string) []string { 48 var Absolute_path []string //定义一个绝对路径数组。 49 url_info, err := url.Parse(root_path) 50 if err != nil { 51 log.Fatal(err) 52 } 53 Scheme := url_info.Scheme //获取到链接的协议 54 //fmt.Println("使用的协议是:",Scheme) 55 Host := url_info.Host //获取链接的主机名 56 //fmt.Println("主机名称是:",Host) 57 Path := url_info.Path //获取到链接的相对路径 58 Path_Directory := strings.Split(Path, "/")[1] //获取到存放文件的目录的路径“Path_Directory”。 59 //fmt.Println("存放文件的目录是:",Path_Directory) 60 for _, souce_path := range picture_path { 61 if strings.HasPrefix(souce_path, "https") { //如果当前当前路径是以“https”开头说明是绝对路径,因此我们给一行空代码,表示不执行任何操作,千万别写:“continue”,空着就好。 62 63 } else if strings.HasPrefix(souce_path, "//") { //判断当前路径是否以“//”开头(说明包含主机名) 64 souce_path = Scheme + ":" + souce_path //如果是就对其进行拼接操作。以下逻辑相同。 65 } else if strings.HasPrefix(souce_path, "/") { //说明不包含主机名和协议,我们进行拼接即可。 66 souce_path = Scheme + "://" + Host + souce_path 67 } else { 68 souce_path = Scheme + "://" + Host + "/" + Path_Directory + "/" + souce_path 69 } 70 Absolute_path = append(Absolute_path, souce_path) //不管是否满足上面的条件,最终都会被追加到该数组中来。 71 } 72 return Absolute_path //最终返回处理后的每个链接的绝对路基。 73 } 74 75 func main() { 76 root_path := os.Args[1] //定义一个URl,也就是我们要爬的网站。 77 picture_path, err := fetch(root_path) //“fetch”函数会帮我们拿到picture_path的路径,但是路径可能是相对路径或是绝对路径。不同意。 78 if err != nil { 79 log.Fatal(err) 80 } 81 82 Absolute_path := Clean_urls(root_path, picture_path) //“Clean_urls”函数会帮我们把picture_path的路径做一个统一,最终都拿到了绝对路径Absolute_path数组。 83 84 for _, Picture_absolute_path := range Absolute_path { 85 fmt.Println(Picture_absolute_path) //最终我们会得到一个图片的完整路径,我们可以对这个路径进行下载,压缩,加密等等操作。 86 } 87 }