使用Python requests模块下载速度极慢

3

问题:

我一直在尝试使用Python的request模块制作一个简单的动画下载器。我正在使用progressbar2模块跟踪进度。在尝试下载时,我得到了0.x B/s的速度。我认为问题是基于这个问题选择chunk_size。但是无论块大小如何,我都得到了相同微不足道的速度。

规格和信息:

  1. 我使用的是Windows 10,Python 3.5,最新的requests模块(2.18.4),并且拥有40Mbps的良好互联网速度。
  2. 我可以通过浏览器(Chrome)和Free Download Manager在约1分钟内从链接下载文件。
  3. 链接完全正常工作,我没有防火墙冲突。

代码:

import os
import requests
import progressbar
from progressbar import *

os.chdir('D:\\anime\\ongoing')

widgets = ['Downloading: ', Percentage(), ' ', Bar(marker='#',left='[',right=']'),
           ' ', ETA(), FileTransferSpeed()]

url = 'https://lh3.googleusercontent.com/AtkUe87GbrINzTJS_Fj4W08CGqlOg9anwEF7n5-eKXcyS1RsaB8LdzRVaXloiJwiaX2IX1xqUiA=m22?title=(720P%20-%20mp4)Net-juu%20no%20Susume%20Episode%207'
r = requests.get(url,stream=True)
remotesize = r.headers['content-length']

print("Downloading {}.mp4!\n\n".format(url.split('title=')[1]))
pbar = ProgressBar(max_value=int(remotesize),widgets=widgets).start()
i = 0
with open('./tempy/tempy_file.mp4', 'wb') as f:
   for chunk in r.iter_content(chunk_size=5*1024*1024): 
      if chunk:
         i = i + len(chunk)
         f.write(chunk)
         pbar.update(int(i/int(remotesize) * 100))
pbar.finish()         
print("Successfully downloaded!\n\n")

截图:

速度简直太快了。

期望解决方案:

不确定这个Github Issue是否已经解决。

  1. 最好在requests模块内找到解决方案,但我愿意接受任何在Python范围内能够帮助我提高下载速度的答案。
  2. 我想要分块下载,因为我想通过进度条查看进度。所以shutil.copyfileobj(r.raw)不符合我的要求。
  3. 我尝试过使用多线程,但只是让事情变得更加复杂,并没有帮助解决问题。我认为问题出在将块写入缓冲区本身上,将这个任务分别交给不同的线程并不能帮助解决问题。

编辑:

根据建议,我尝试通过包含随机用户代理来解决问题,如下所示:

desktop_agents = ['Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36',
                 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36',
                 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36',
                 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/602.2.14 (KHTML, like Gecko) Version/10.0.1 Safari/602.2.14',
                 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36',
                 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
                 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
                 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36',
                 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36',
                 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0']

def random_headers():
    return {'User-Agent': choice(desktop_agents),'Accept':'text/html,video/mp4,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'}

并且使用以下头部信息发送请求:r = requests.get(url,stream=True,headers=random_headers())

然而,这没有任何区别。 :(

第二次编辑:

尝试使用来自“http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_5mb.mp4”的示例视频。问题仍然存在。 :/


你确定这不是谷歌在这里进行限制吗?实际上,是远程端以缓慢的速率提供数据。 - Martijn Pieters
关于 Github 的问题,确实已更改默认大小。您设置了一个不错的块大小,因此那个问题根本不适用 - Martijn Pieters
可能吧。我会像Matt提到的那样添加用户代理并尝试。 - Harshith Thota
不确定是否相关,但我编写的一个爬虫成功地获取了相同的链接。因此,我认为在这种情况下谷歌并没有真正阻止机器人。 - Harshith Thota
1
UAs只是一个头部信息。Google很可能使用更复杂的启发式算法来确定某个请求是否来自机器人。你尝试过在本地已知不会限制速度的Web服务器上运行相同的代码吗?如果那也很慢,那么我们可能可以归咎于requests库。否则,您需要对头部信息进行更多的实验和调整。 - Martijn Pieters
显示剩余2条评论
3个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
1

就像其他人建议的那样,谷歌限制了速度。为了克服这个问题,我使用Selenium webdriver下载链接:

from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
prefs = {'download.default_directory' : dir_name}
            chrome_options.add_experimental_option('prefs', prefs)
            driver = webdriver.Chrome(chrome_options=chrome_options)
driver.get(li)

好的,至少我能够完全自动化下载,并以Google Chrome下载器可能的速度进行下载。

因此,如果有人可以帮助我解决这个问题,请在评论中回复,如果有用,我会给他们点赞:

  1. 找出一种在Python中像Free Download Manager一样为每个文件使用多个连接的方法。

这里是完整脚本的链接。


0

这个问题之前已经被问过了,但我认为 OP 观察到的问题不在于下载,而是在于报告。进度条被填充到最大值,该值等于 remotesize 的值:

pbar = ProgressBar(max_value=int(remotesize),widgets=widgets).start()

然而,在事件循环内,通过获取已下载块的大小i并除以remotesize再乘以100来更新进度条:

pbar.update(int(i/int(remotesize) * 100))

本质上,第一行设置了进度条期望的绝对值范围为0到文件总大小,而第二行则期望将进度条设置为百分比形式,范围从0%到100%。因此,在任何时刻,进度条实际上是以百分比/位(例如9%/321053151位)的单位显示,这就是为什么进度条认为进度极其缓慢的原因。

因此,要么将第一行更改为:

pbar = ProgressBar(max_value=100,widgets=widgets).start()

或者,将第二行改为:

pbar.update(i)

0

你尝试过在请求头中填写你的用户代理和其他 Google 可能需要的头信息,以避免被标记为机器人并限制下载速度吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,