内容简介:前段时间写了个小爬虫,从国外某网站上下载视频,初期使用的是单线下载,后面发现访问服务端的资源数过多,会被反爬机制限制,还有一个问题就是单线下载境外网站内容,效率比较低,下载速度很慢,后面修修补补改了改,改为多线访问同个资源,顺利解决反爬机制,也提升了下载效率.`最近写了个小爬虫,从国外某网站上下载视频,初期使用的是单线下载,后面发现访问服务端的资源数过多,会被反爬机制限制,还有一个问题就是单线下载境外网站内容性能比较差,下载速度很慢,后面修修补补改了改,改为多线访问同个资源,顺利解决反爬机制,也提升了下载效
前段时间写了个小爬虫,从国外某网站上下载视频,初期使用的是单线下载,后面发现访问服务端的资源数过多,会被反爬机制限制,还有一个问题就是单线下载境外网站内容,效率比较低,下载速度很慢,后面修修补补改了改,改为多线访问同个资源,顺利解决反爬机制,也提升了下载效率.
多线程下载必须服务端支持
1.判断服务端是否支持多线下载:
使用 HEAD 方法请求资源,然后查看服务端返回数据
image.png
2.查看返回数据头部是否存在 `Accept-Ranges →bytes`
如果有,那么就支持多线程下载,没有的话基本上可以洗洗睡了.
Golang 实现环节
`
最近写了个小爬虫,从国外某网站上下载视频,初期使用的是单线下载,后面发现访问服务端的资源数过多,会被反爬机制限制,还有一个问题就是单线下载境外网站内容性能比较差,下载速度很慢,后面修修补补改了改,改为多线访问同个资源,顺利解决反爬机制,也提升了下载效率.
多线程下载必须服务端支持
1.判断服务端是否支持多线下载:
使用 HEAD 方法请求资源,然后查看服务端返回数据
image.png
2.查看返回数据头部是否存在 `Accept-Ranges →bytes`
如果有,那么就支持多线程下载,没有的话基本上可以洗洗睡了.
Golang 实现环节
判断是否支持多线下载
image.png
多线下载任务分配
image.png
执行下载
image.png
完整代码
package download
import (
"github.com/labstack/gommon/log"
"io/ioutil"
"net/http"
"os"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
)
var client = http.Client{Timeout: time.Second * 180}
var threadGroup = sync.WaitGroup{}
var packageSize int64
func init() {
//每个线程下载文件的大小
packageSize = 1048576 * 4
}
func Download(url, cachePath string, scheduleCallback func(schedule float64)) string {
var localFileSize int64
var file *os.File
if info, e := os.Stat(cachePath); e != nil {
if os.IsNotExist(e) {
if createFile, err := os.Create(cachePath); err == nil {
file = createFile
} else {
panic(err)
}
} else {
panic(e)
}
} else {
localFileSize = info.Size()
}
//HEAD 方法请求服务端是否支持多线程下载,并获取文件大小
if request, e := http.NewRequest("HEAD", url, nil); e == nil {
if response, i := client.Do(request); i == nil {
defer response.Body.Close()
//得到文件大小
ContentLength := response.ContentLength
if localFileSize == ContentLength {
log.Warn("file exist~")
return cachePath
} else {
//判断是否支持多线下载
if strings.Compare(response.Header.Get("Accept-Ranges"), "bytes") == 0 {
//支持 走下载流程
if dispSliceDownload(file, ContentLength, url, scheduleCallback) == 0 {
return cachePath
} else {
return ""
}
} else {
panic("nonsupport ~")
}
}
} else {
panic(i)
}
} else {
panic(e)
}
return ""
}
func dispSliceDownload(file *os.File, ContentLength int64, url string, scheduleCallback func(schedule float64)) int {
defer file.Close()
//文件总大小除以 每个线程下载的大小
i := ContentLength / packageSize
//保证文件下载完整
if ContentLength%packageSize > 0 {
i += 1
}
//下载总进度
var schedule int64
//分配下载线程
for count := 0; count < int(i); count++ {
//计算每个线程下载的区间,起始位置
var start int64
var end int64
start = int64(int64(count) * packageSize)
end = start + packageSize
if int64(end) > ContentLength {
end = end - (end - ContentLength)
}
//构建请求
if req, e := http.NewRequest("GET", url, nil); e == nil {
req.Header.Set(
"Range",
"bytes="+strconv.FormatInt(start, 10)+"-"+strconv.FormatInt(end, 10))
//
threadGroup.Add(1)
go sliceDownload(req, file, &schedule, &ContentLength, scheduleCallback, start)
} else {
panic(e)
}
}
//等待所有线程完成下载
threadGroup.Wait()
return 0
}
func sliceDownload(request *http.Request, file *os.File, schedule *int64, ContentLength *int64, scheduleCallback func(schedule float64),
start int64) {
defer threadGroup.Done()
if response, e := client.Do(request); e == nil && response.StatusCode == 206 {
defer response.Body.Close()
if bytes, i := ioutil.ReadAll(response.Body); i == nil {
i2 := len(bytes)
//从我们计算好的起点写入文件
file.WriteAt(bytes, start)
atomic.AddInt64(schedule, int64(i2))
val := atomic.LoadInt64(schedule)
num := float64(val*1.0) / float64(*ContentLength) * 100
scheduleCallback(float64(num))
} else {
panic(e)
}
} else {
panic(e)
}
}
因为硬盘空间有限,爬取到180GB的时候,就结束了爬取.
image.png
个人联系方式: 作者QQ:853151446 作者邮箱:853151446@qq.com 有问题或者可以一起探讨的,请联系我,或者留言.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- linux线程实现
- 在Java中怎样实现多线程?Java线程的四种状态
- 线程切换函数schedule的实现
- 多线程的四种实现方式
- Java线程池ThreadPoolExecutor实现原理
- 线程池的简单实现(Rust)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Art of Computer Programming, Volumes 1-3 Boxed Set
Donald E. Knuth / Addison-Wesley Professional / 1998-10-15 / USD 199.99
This multivolume work is widely recognized as the definitive description of classical computer science. The first three volumes have for decades been an invaluable resource in programming theory and p......一起来看看 《The Art of Computer Programming, Volumes 1-3 Boxed Set》 这本书的介绍吧!