数学研发论坛

 找回密码
 欢迎注册
查看: 639|回复: 5

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

[复制链接]
发表于 2021-12-3 11:07:51 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?欢迎注册

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

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


毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2021-12-3 12:30:13 | 显示全部楼层
1) 既然是内存泄漏了. 那么urllib.request.urlopen(req) 之后 好像还应该close掉这个句柄.
2) with open 之后不需要再close.
3) 试试python3的requests. 替代urllib.

  1. def get_file(url, path):
  2.     try:
  3.         req = urllib.request.Request(url, headers=headers)
  4.         with urllib.request.urlopen(req, data=login_data.encode('utf-8')) as u:
  5.             data = u.read()  
  6.             with open(path, 'wb') as f:
  7.                 f.write(data)
  8.     except Exception as e:
  9.         print(e)
  10.         print('获取文件失败')
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 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')这个参数,应该不会是这个问题吧?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 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(),但是这个好像不能下载文件
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2021-12-3 21:09:28 | 显示全部楼层
试了下 requests下载文件, 支持 进度条更新 和 断点续传.
参考文章, https://www.justdopython.com/2020/11/16/python-downloadFile/

  1. import os,re
  2. import requests
  3. import tqdm

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

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

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


  13. def tqdm_download(url, file_name):

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

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

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

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

  24.     # Range 加入请求头
  25.     header = {"Range": f"bytes={first_byte}-{file_size}",
  26.               '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'}
  27.     # 加了一个 initial 参数
  28.     with tqdm.tqdm(total=file_size, unit='B', initial=first_byte, unit_scale=True, unit_divisor=1024, ascii=True, desc=file_name) as bar:
  29.         # 加 headers 参数
  30.         with requests.get(url + file_name, headers=header, stream=True) as r:
  31.             with open(file_name, 'ab') as fp:
  32.                 for chunk in r.iter_content(chunk_size=512):
  33.                     if chunk:
  34.                         fp.write(chunk)
  35.                         bar.update(len(chunk))


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

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

复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2021-12-3 21:41:05 | 显示全部楼层
lsr314 发表于 2021-12-3 18:18
按这个办法运行了一下,python.exe内存占用还是持续在增加。
headers里已经包括cookies信息了,所以在ur ...

你是怎么确定内存一直在增加.  我用上面的代码测试 下载了10分钟左右, pycharm内存占用很稳定. 有时增加有时候减少.
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2022-5-21 23:29 , Processed in 0.072788 second(s), 16 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表