如何在Python2中下载大型文件

如何在Python2中下载大型文件,python,download,mechanize,Python,Download,Mechanize,我正试图用mechanize模块下载大文件(大约1GB),但我没有成功。我一直在搜索类似的线程,但我只找到了那些文件可以公开访问且无需登录即可获取文件的线程。但这不是我的情况,因为文件位于私有部分,我需要在下载之前登录。这是我到目前为止所做的 import mechanize g_form_id = "" def is_form_found(form1): return "id" in form1.attrs and form1.attrs['id'] == g_form_id d

我正试图用mechanize模块下载大文件(大约1GB),但我没有成功。我一直在搜索类似的线程,但我只找到了那些文件可以公开访问且无需登录即可获取文件的线程。但这不是我的情况,因为文件位于私有部分,我需要在下载之前登录。这是我到目前为止所做的

import mechanize

g_form_id = ""

def is_form_found(form1):
    return "id" in form1.attrs and form1.attrs['id'] == g_form_id

def select_form_with_id_using_br(br1, id1):
    global g_form_id
    g_form_id = id1
    try:
        br1.select_form(predicate=is_form_found)
    except mechanize.FormNotFoundError:
        print "form not found, id: " + g_form_id
        exit()

url_to_login = "https://example.com/"
url_to_file = "https://example.com/download/files/filename=fname.exe"
local_filename = "fname.exe"

br = mechanize.Browser()
br.set_handle_robots(False)   # ignore robots
br.set_handle_refresh(False)  # can sometimes hang without this
br.addheaders =  [('User-agent', 'Firefox')]

response = br.open(url_to_login)
# Find login form
select_form_with_id_using_br(br, 'login-form')
# Fill in data
br.form['email'] = 'email@domain.com'
br.form['password'] = 'password'
br.set_all_readonly(False)    # allow everything to be written to
br.submit()

# Try to download file
br.retrieve(url_to_file, local_filename)
但我在下载512MB时遇到一个错误:

Traceback (most recent call last):
  File "dl.py", line 34, in <module>
    br.retrieve(br.retrieve(url_to_file, local_filename)
  File "C:\Python27\lib\site-packages\mechanize\_opener.py", line 277, in retrieve
    block = fp.read(bs)
  File "C:\Python27\lib\site-packages\mechanize\_response.py", line 199, in read
    self.__cache.write(data)
MemoryError: out of memory
回溯(最近一次呼叫最后一次):
文件“dl.py”,第34行,在
br.retrieve(br.retrieve(url\u到\u文件,本地\u文件名)
文件“C:\Python27\lib\site packages\mechanize\\u opener.py”,第277行,检索
block=fp.read(bs)
文件“C:\Python27\lib\site packages\mechanize\\u response.py”,第199行,已读
自缓存写入(数据)
内存错误:内存不足
你有什么办法解决这个问题吗?
谢谢

试着按块下载/编写。文件似乎占用了你所有的内存

若服务器支持,则应为请求指定范围标头


试着按块下载/写入。文件似乎占用了你所有的内存

若服务器支持,则应为请求指定范围标头

您可以使用和登录,然后写入流式内容。需要几个表单字段,其中包括一个绝对必要的
\u令牌
字段:

from bs4 import BeautifulSoup
import requests
from urlparse import urljoin

data = {'email': 'email@domain.com', 'password': 'password'}
base = "https://support.codasip.com"

with requests.Session() as s:
    # update headers
    s.headers.update({'User-agent': 'Firefox'})

    # use bs4 to parse the from fields
    soup = BeautifulSoup(s.get(base).content)
    form = soup.select_one("#frm-loginForm")
    # works as it is a relative path. Not always the case.
    action = form["action"]

    # Get rest of the fields, ignore password and email.
    for inp in form.find_all("input", {"name":True,"value":True}):
        name, value = inp["name"], inp["value"]
        if name not in data:
            data[name] = value
    # login
    s.post(urljoin(base, action), data=data)
    # get protected url
    with open(local_filename, "wb") as f:
        for chk in s.get(url_to_file, stream=True).iter_content(1024):
            f.write(chk)
您可以使用和登录,然后写入流式内容。需要几个表单字段,包括
\u令牌
字段,这是绝对必要的:

from bs4 import BeautifulSoup
import requests
from urlparse import urljoin

data = {'email': 'email@domain.com', 'password': 'password'}
base = "https://support.codasip.com"

with requests.Session() as s:
    # update headers
    s.headers.update({'User-agent': 'Firefox'})

    # use bs4 to parse the from fields
    soup = BeautifulSoup(s.get(base).content)
    form = soup.select_one("#frm-loginForm")
    # works as it is a relative path. Not always the case.
    action = form["action"]

    # Get rest of the fields, ignore password and email.
    for inp in form.find_all("input", {"name":True,"value":True}):
        name, value = inp["name"], inp["value"]
        if name not in data:
            data[name] = value
    # login
    s.post(urljoin(base, action), data=data)
    # get protected url
    with open(local_filename, "wb") as f:
        for chk in s.get(url_to_file, stream=True).iter_content(1024):
            f.write(chk)


也许可以通过
请求尝试
。你必须使用mechanize吗?不,文件下载后我不关心它的方式。但是日志部分有一个问题。如果有其他模块可以做到这一点,我对它持开放态度。你可以通过bs4和几行代码中的请求来实现这一点,你可以共享url吗?是的,但仅限于此对于日志页面(这应该足够了):可能通过
请求尝试
。你必须使用mechanize吗?不,文件下载后我不关心它的方式。但是日志部分有问题。如果有其他模块可以这样做,我愿意接受。你可以使用bs4和几行代码中的请求来实现这一点,你可以共享url吗?是的,但仅限于此对于登录页面(这应该足够了):谢谢你的回答,但似乎登录不起作用,可能是因为找不到正确的表单条目。我会设法解决这个问题。@MilanSkála,实际上我们需要一个令牌,我会在一分钟内编辑嗯,奇怪,呼叫soup。选择_one()方法引发TypeError:“非类型”对象不可调用。@MilanSkála,我运行了代码进行验证,它执行了它应该执行的操作,您是否像上面那样传递基本url?是的,我使用了您的代码1:1。这可能是由bs4模块的不同版本引起的吗?我使用的是4.3.2。顺便说一句,方法“选择”可以工作,但返回列表,第一项在列表中是表单的html(作为字符串)。谢谢您的回答,但似乎登录不起作用,可能是因为找不到正确的表单条目。我会设法解决这个问题。@MilanSkála,实际上我们需要一个令牌,我会在一分钟内编辑嗯,奇怪,调用soup。选择_one()方法引发TypeError:“非类型”对象不可调用。@MilanSkála,我运行了代码进行验证,它执行了它应该执行的操作,您是否像上面那样传递基本url?是的,我使用了您的代码1:1。这可能是由bs4模块的不同版本引起的吗?我使用的是4.3.2。顺便说一句,方法“选择”可以工作,但返回列表,第一项在列表中是表单的html(作为字符串)。