Слишком много памяти используется при работе с BeautifulSoup4 в Python 3 - PullRequest
1 голос
/ 14 апреля 2020

Я написал скрипт, который извлекает содержимое страницы HTML и анализирует его. Запустив этот код в al oop, где я дал несколько URL-адресов, я заметил, что использование памяти росло слишком быстро и слишком быстро. Профилируя и отлаживая код несколькими инструментами, я замечаю, что проблема связана с битом кода, который использует BeautifulSoup4, по крайней мере, я так думаю.

Line    Mem usage    Increment     Line Contents                                                                                                                                        
59     40.5 MiB     40.5 MiB       @profile                           
60                                 def crawl(self):                                                                                     
70     40.6 MiB      0.0 MiB           self.add_url_to_crawl(self.base_url)
71                             
72    291.8 MiB      0.0 MiB           for url in self.page_queue:           
74    267.4 MiB      0.0 MiB               if url in self.crawled_urls:   
75                                             continue
76                                                                                                                                                                                         
77    267.4 MiB      0.0 MiB               page = Page(url=url, base_domain=self.base_url, log=self.log)
78                             
79    267.4 MiB      0.0 MiB               if page.parsed_url.netloc != page.base_domain.netloc:
80                                             continue                 
81                                                                                         
82    291.8 MiB     40.1 MiB               page.analyze()                                                                                                                                  
83                             
84    291.8 MiB      0.0 MiB               self.content_hashes[page.content_hash].add(page.url)   
94                                                                                         
95                                         # Add crawled page links into the queue                                                                                                         
96    291.8 MiB      0.0 MiB               for url in page.links:
97    291.8 MiB      0.0 MiB                   self.add_url_to_crawl(url)
98                                         
100    291.8 MiB      0.0 MiB               self.crawled_pages.append(page.getData())
101    291.8 MiB      0.0 MiB               self.crawled_urls.add(page.url)
102                                         
103    291.8 MiB      0.0 MiB               mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
104    291.8 MiB      0.0 MiB               print('Memory usage is: {0} KB'.format(mem))

Вот какая строка 104 печатает каждый прогон:

Memory usage is: 69216 KB       
Memory usage is: 92092 KB       
Memory usage is: 105796 KB                                                                  
Memory usage is: 134704 KB                                                                  
Memory usage is: 158604 KB                                                                                                                                                                  
Memory usage is: 184068 KB                                                                  
Memory usage is: 225324 KB                                                                  
Memory usage is: 248708 KB                                                                  
Memory usage is: 273780 KB                                                                                                                                                                  
Memory usage is: 298768 KB

Используя tracemalloc в главном файле, который вызывает все модули и используя метод crawl, описанный выше, я получил следующий список из tracemalloc.snapshot():

/usr/lib/python3.8/site-packages/bs4/element.py:744: size=23.3 MiB, count=210391, average=116 B
/usr/lib/python3.8/site-packages/bs4/builder/__init__.py:215: size=17.3 MiB, count=335036, average=54 B
/usr/lib/python3.8/site-packages/bs4/element.py:628: size=9028 KiB, count=132476, average=70 B
/usr/lib/python3.8/html/parser.py:327: size=7804 KiB, count=147140, average=54 B
/usr/lib/python3.8/site-packages/bs4/element.py:121: size=6727 KiB, count=132476, average=52 B
/usr/lib/python3.8/site-packages/bs4/element.py:117: size=6702 KiB, count=40848, average=168 B
/usr/lib/python3.8/html/parser.py:324: size=6285 KiB, count=85986, average=75 B
/usr/lib/python3.8/site-packages/bs4/element.py:772: size=5754 KiB, count=105215, average=56 B
/usr/lib/python3.8/html/parser.py:314: size=5334 KiB, count=105196, average=52 B
/usr/lib/python3.8/site-packages/bs4/__init__.py:587: size=4932 KiB, count=105197, average=48 B

Most перечисленные выше файлы находятся в папке / bs4 / . Теперь, с того момента, как переменная page (строка 82) нигде не хранится, page.getData() возвращает словарь и page.url строку, почему у BeautifulSoup так много места в памяти?

В строке 72 вы можете увидеть, как использование памяти изменилось с ~ 40 МБ до ~ 291 МБ (, учитывая, что oop обработало 10 URL ), это большое изменение, учитывая, что данные, которые я на самом деле сохраняю, небольшой словарь и строка.

У меня проблема с сборщиком мусора или я что-то не так написал?

Я не очень практичен с Python, поэтому надеюсь, что суть Я сделал с профилированием и отладка верна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...