lsr314 发表于 2021-12-3 11:07:51

Python爬虫占用内存不断增大,如何释放?

本帖最后由 lsr314 于 2021-12-3 11:38 编辑

最近在写一个爬虫,从网站上下载上市公司年报和公告,并保存到本地,用到了requests.get()和urllib.request.Request()、urllib.request.urlopen()这几个函数。
程序可以正确执行,但是每下载一个文件,python.exe进程占用的内存就会增加,每次增加的大小大约就是1-2个下载的文件的大小。不久系统内存就满了。
通过debug,发现主要是在执行urllib.request.urlopen().read()的时候,内存会增加。
想问有什么办法可以在程序运行的过程中释放内存,或者让它自己停止,并且释放内存后重新启动,接着上次的进度继续运行下去?
下面是程序的核心部分,后面还有对公司代码的for循环,这里就不贴了:
def get_file(url, path):   
    try:
         req = urllib.request.Request(url, headers=headers)
         data = urllib.request.urlopen(req).read()# 这一步持续增加占用内存      
         with open(path, 'wb') as f:
               f.write(data)
               f.close()
    except Exception as e:
         print(e)
         print('获取文件失败')

wayne 发表于 2021-12-3 12:30:13

1) 既然是内存泄漏了. 那么urllib.request.urlopen(req) 之后 好像还应该close掉这个句柄.
2) with open 之后不需要再close.
3) 试试python3的requests. 替代urllib.

def get_file(url, path):
    try:
      req = urllib.request.Request(url, headers=headers)
      with urllib.request.urlopen(req, data=login_data.encode('utf-8')) as u:
            data = u.read()
            with open(path, 'wb') as f:
                f.write(data)
    except Exception as e:
      print(e)
      print('获取文件失败')

lsr314 发表于 2021-12-3 18:18:40

wayne 发表于 2021-12-3 12:30
1) 既然是内存泄漏了. 那么urllib.request.urlopen(req) 之后 好像还应该close掉这个句柄.
2) with open...

按这个办法运行了一下,python.exe内存占用还是持续在增加。
headers里已经包括cookies信息了,所以在urllib.request.urlopen()没有加data=login_data.encode('utf-8')这个参数,应该不会是这个问题吧?

lsr314 发表于 2021-12-3 18:20:35

wayne 发表于 2021-12-3 12:30
1) 既然是内存泄漏了. 那么urllib.request.urlopen(req) 之后 好像还应该close掉这个句柄.
2) with open...

我也不喜欢用urllib,不过用requests是怎么替代的?一般网页我会直接用requests.get(),但是这个好像不能下载文件

wayne 发表于 2021-12-3 21:09:28

试了下 requests下载文件, 支持 进度条更新 和 断点续传.
参考文章, https://www.justdopython.com/2020/11/16/python-downloadFile/

import os,re
import requests
import tqdm

def download_file(url, file):
    resp = requests.get(url+file, stream=True)

    file_size = int(resp.headers['content-length'])
    print('{0} ,filesize: = {1:.3f} MB'.format(file, file_size/1024./1024.))

    with requests.get(url+file, stream=True) as r:
      with open(file, 'wb') as fp:
            for chunk in r.iter_content(chunk_size=1024):
                if chunk:
                  fp.write(chunk)


def tqdm_download(url, file_name):

    r = requests.get(url + file_name, stream=True)

    # 获取文件大小
    file_size = int(r.headers['content-length'])

    # 如果文件存在获取文件大小,否在从 0 开始下载,
    first_byte = 0
    if os.path.exists(file_name):
      first_byte = os.path.getsize(file_name)

    # 判断是否已经下载完成
    if first_byte >= file_size:
      return

    # Range 加入请求头
    header = {"Range": f"bytes={first_byte}-{file_size}",
            'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.3538.77 Safari/537.36'}
    # 加了一个 initial 参数
    with tqdm.tqdm(total=file_size, unit='B', initial=first_byte, unit_scale=True, unit_divisor=1024, ascii=True, desc=file_name) as bar:
      # 加 headers 参数
      with requests.get(url + file_name, headers=header, stream=True) as r:
            with open(file_name, 'ab') as fp:
                for chunk in r.iter_content(chunk_size=512):
                  if chunk:
                        fp.write(chunk)
                        bar.update(len(chunk))


u='https://mirrors.cloud.tencent.com/qt/official_releases/qt/6.2/6.2.2/submodules/'

r = requests.get(u)
res = re.findall(r'([\w+\-\.]+xz)</a>', r.text)
for file in res:
    # download_file(u, file)
    tqdm_download(u, file)

wayne 发表于 2021-12-3 21:41:05

lsr314 发表于 2021-12-3 18:18
按这个办法运行了一下,python.exe内存占用还是持续在增加。
headers里已经包括cookies信息了,所以在ur ...

你是怎么确定内存一直在增加.我用上面的代码测试 下载了10分钟左右, pycharm内存占用很稳定. 有时增加有时候减少.
页: [1]
查看完整版本: Python爬虫占用内存不断增大,如何释放?