python多线程下载器_请教关于 Python 多线程下载器问题

刚学完 python 不久,想做个小爬虫练练手,于是整了个小爬虫在 vps 持续爬取某个小视频网站的发布的小视频,小视频的大小为 1-200M,小爬虫负责下载视频的部分很简单,直接 r = requests.get(url),然后把 r.content 写入文件。

后来觉得下载效率好像不行,于是上网搜了一下多线程下载器,便开始重写下载视频部分的代码了,成品如下,在我的电脑上能正常运行,但在 vps 上持续运行的话,有不少问题,不仅内存占用大(占用 200 多 M 的内存),而且时不时出现Max retries exceeded with url的错误。

from threading import Thread

import requests

class Download:

def __init__(self, url):

self.url = url

self.ua = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0'}

r = requests.head(self.url, headers=self.ua)

# 循环寻址

while r.status_code == 301 or r.status_code == 302:

self.url = r.headers['Location']

r = requests.head(self.url, headers=self.ua)

self.name = self.url.split('?')[0].split('/')[-1]

self.size = int(r.headers['Content-Length'])

# 创建等大空文件

f = open(self.name, "wb")

f.truncate(self.size)

f.close()

# 根据文件大小分配线程

if self.size < 5 * 1024 * 1024:

self.thread_num = 1

elif self.size < 10 * 1024 * 1024:

self.thread_num = 2

elif self.size < 20 * 1024 * 1024:

self.thread_num = 4

elif self.size < 40 * 1024 * 1024:

self.thread_num = 8

else:

self.thread_num = 16

# 确定文件块大小

self.part = self.size // self.thread_num

def dl(self, start, end):

header = {'Range': 'bytes={}-{}'.format(start, end)}

header.update(self.ua)

with requests.get(self.url, headers=header, stream=True) as r:

with open(self.name, 'rb+') as f:

f.seek(start)

f.write(r.content)

@staticmethod

def unit_conversion(byte):

byte = int(byte)

if byte > 1024:

res = byte / 1024

if res < 1024:

res = float('%.2f' % res)

return str(res) + 'KB'

elif res < 1024 * 1024:

res = res / 1024

res = float('%.2f' % res)

return str(res) + 'MB'

else:

res = res / (1024 * 1024)

res = float('%.2f' % res)

return str(res) + 'GB'

else:

return str(byte) + 'B'

def run(self):

thread_list = []

for i in range(self.thread_num - 1):

start = i * self.part

end = (i + 1) * self.part

t = Thread(target=self.dl, args=(start, end))

thread_list.append(t)

# 最后一部分

start = (self.thread_num - 1) * self.part

end = self.size

t = Thread(target=self.dl, args=(start, end))

thread_list.append(t)

# 启动所有子线程

for t in thread_list:

t.start()

# 子进程合并到主线程

for t in thread_list:

t.join()

print(f'{Download.unit_conversion(self.size)} {self.name}下载完成!')

return self.name, self.size

if __name__ == '__main__':

t = Download('http://www.baidu.com').run()

print(t)

请教大家几个问题:

1 、多线程下载的时候,多个线程读取同一个文件,不同的线程在文件的不同位置写入内容,需要加入线程锁吗?我感觉它们写入的部分不同,好像没有冲突啊

2 、我在网上查到Max retries exceeded with url的错误是由于 http 连接过多引起的,网上给出的方法有用 with 语句打开 requests.get(url)来确保连接会被关闭,还有的是建议直接加 response.close()关闭,还有的用with closing(requests.get(img_url, stream=True)) as r:,哪种方法比较靠谱呢?

3 、俺还有啥可以优化改进的地方?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值