网友 ***an.net 说:
- package main
- import (
- &*uot;fmt&*uot;
- &*uot;io/ioutil&*uot;
- &*uot;net/http&*uot;
- &*uot;os&*uot;
- &*uot;regexp&*uot;
- &*uot;strconv&*uot;
- &*uot;st**ngs&*uot;
- &*uot;sync&*uot;
- &*uot;time&*uot;
- )
- var (
- reImg = `https?://[^&*uot;]+?(\.((jpg)|(png)|(jpeg)|(gif)|(bmp)))`
- taskChan chan st**ng // 记录任务完成的通道
- imgChan chan st**ng // 图片通道
- waitG**up sync.WaitG**up // 协程会涉及到并发,这个的作用具体的可百度
- pageStart int = 1 // 从第几页开始
- pageSize int = 30 // 扫描页数
- DownLoadPath st**ng = &*uot;D:/HBuilderX/p**ject/GolangP**ject/爬虫小案例/img/&*uot; // 此处是图片下载的地址,需要修改为你们自己的地址
- )
- func main() {
- fmt.P**ntln(&*uot;从第几页开始&*uot;)
- fmt.Scanln(&pageStart)
- fmt.P**ntln(&*uot;扫描页数&*uot;)
- fmt.Scanln(&pageSize)
- taskChan = make(chan st**ng, pageSize) // 给管道缓冲值
- imgChan = make(chan st**ng, 100000) // 给管道缓冲值
- for i := pageStart; i < pageStart+pageSize; i++ {
- waitG**up.Add(1)
- go getWebBody(i) // 获取地址的body
- }
- waitG**up.Add(1)
- go handleImg() // 处理img
- waitG**up.Add(1)
- go checkOk()
- waitG**up.Wait()
- fmt.P**ntln(&*uot;执行完毕,回车退出&*uot;)
- var input st**ng
- fmt.Scanln(&input)
- }
- func getWebBody(i int) {
- **l := &*uot;https://www.bizhizu.cn/shouji/tag-%E5%8F%AF%E7%88%B1/&*uot; + strconv.Itoa(i) + &*uot;.html&*uot;
- resp, err := http.Get(**l)
- if err != nil {
- fmt.P**ntln(err)
- }
- defer resp.Body.Close() // 此处不可少,否则会造成内存泄露或者溢出问题
- body, _ := ioutil.ReadAll(resp.Body)
- re := regexp.MustCompile(reImg) // 正则匹配图片地址
- result := re.FindAllSt**ngSubmatch(st**ng(body), -1)
- p**ntln(&*uot;第&*uot; + strconv.Itoa(i) + &*uot;页找到数据&*uot; + strconv.Itoa(len(result)) + &*uot;条&*uot;)
- for _, v := range result {
- imgChan <- v[0] // 把得到的数据写到 管道 里
- }
- taskChan <- **l
- waitG**up.Done()
- }
- // 处理图片方法
- func handleImg() {
- for **l := range imgChan {
- fileName := GetFilenameF**mUrl(**l)
- result := DownloadFile(**l, fileName)
- if result {
- fmt.P**ntf(&*uot;已下载完毕 %v \n&*uot;, **l)
- } else {
- fmt.P**ntf(&*uot;下载失败 %v \n&*uot;, **l)
- }
- }
- waitG**up.Done()
- }
- // **管道任务是否完成
- func checkOk() {
- count := 0
- for {
- **l := <-taskChan
- fmt.P**ntf(&*uot;完成爬取:%v \n&*uot;, **l)
- count++
- if count == pageSize {
- close(imgChan)
- close(taskChan)
- break
- }
- }
- waitG**up.Done()
- }
- // 截取**l名字
- func GetFilenameF**mUrl(**l st**ng) (filename st**ng) {
- // 返回最后一个/的位置
- lastIndex := st**ngs.LastIndex(**l, &*uot;/&*uot;)
- // 切出来
- filename = **l[lastIndex+1:]
- // 时间*解决重名
- timePrefix := strconv.Itoa(int(time.Now().UnixNano()))
- filename = timePrefix + &*uot;_&*uot; + filename
- ret**n
- }
- // 下载文件方法
- func DownloadFile(**l st**ng, filename st**ng) bool {
- var err er**r
- resp, err := http.Get(**l)
- if err != nil {
- fmt.P**ntln(err)
- }
- defer resp.Body.Close()
- bytes, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- fmt.P**ntln(err)
- }
- if _, err := os.Stat(DownLoadPath); os.IsNotExist(err) {
- // 必须分成两步
- // 先创建文件夹
- os.Mkdir(DownLoadPath, 0777)
- // 再修改权限
- os.Chmod(DownLoadPath, 0666)
- }
- filename = DownLoadPath + filename
- err = ioutil.W**teFile(filename, bytes, 0666)
- if err != nil {
- ret**n false
- }
- ret**n true
- }
网友 Twice 说:
人生苦短,我用PYTHON
网友 Mr.Bean 说:
支持看到了if err 舒服了
未经允许不得转载:爱主机 » Golang协程并发爬取图片源码,仅供学习
爱主机