I’m working on a script which scrapes thousands of different web pages. Since these pages are usually different (has different sites), I use multithreading to speed up scraping.
EDIT: SIMPLE SHORT EXPLANATION
——-
I’m loading 300 urls (htmls) in one pool of 300 workers. Since the size of html is variable, sometimes, the sum of sizes is probably too big and python raises: internal buffer error : Memory allocation failed : growing buffer
. I want to somehow check if this can happend and if, wait until the buffer is not full.
——-
This approach works but sometimes, python starts to throw:
internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
internal buffer internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
into console. I suppose that it is because of size of html
I store in memory, which can be 300*(for example 1mb) = 300mb
EDIT:
I know that I can decrease number of workers and I will. But it’s not a solution, there would be just lower chance to get such error. I want to avoid this error at all…
I started to log html
sizes:
ram_logger.debug('SIZE: {}'.format(sys.getsizeof(html)))
And the result is (part):
2017-03-05 13:02:04,914 DEBUG SIZE: 243940
2017-03-05 13:02:05,023 DEBUG SIZE: 138384
2017-03-05 13:02:05,026 DEBUG SIZE: 1185964
2017-03-05 13:02:05,141 DEBUG SIZE: 1203715
2017-03-05 13:02:05,213 DEBUG SIZE: 291415
2017-03-05 13:02:05,213 DEBUG SIZE: 287030
2017-03-05 13:02:05,224 DEBUG SIZE: 1192165
2017-03-05 13:02:05,230 DEBUG SIZE: 1193751
2017-03-05 13:02:05,234 DEBUG SIZE: 359193
2017-03-05 13:02:05,247 DEBUG SIZE: 23703
2017-03-05 13:02:05,252 DEBUG SIZE: 24606
2017-03-05 13:02:05,275 DEBUG SIZE: 302388
2017-03-05 13:02:05,329 DEBUG SIZE: 334925
This is my simplified scraping approach:
def scrape_chunk(chunk):
pool = Pool(300)
results = pool.map(scrape_chunk_item, chunk)
pool.close()
pool.join()
return results
def scrape_chunk_item(item):
root_result = _load_root(item.get('url'))
# parse using xpath and return
And the function to load html:
def _load_root(url):
for i in xrange(settings.ENGINE_NUMBER_OF_CONNECTION_ATTEMPTS):
try:
headers = requests.utils.default_headers()
headers['User-Agent'] = ua.chrome
r = requests.get(url, timeout=(settings.ENGINE_SCRAPER_REQUEST_TIMEOUT + i, 10 + i), verify=False, )
r.raise_for_status()
except requests.Timeout as e:
if i >= settings.ENGINE_NUMBER_OF_CONNECTION_ATTEMPTS - 1:
tb = traceback.format_exc()
return {'success': False, 'root': None, 'error': 'timeout', 'traceback': tb}
except Exception:
tb = traceback.format_exc()
return {'success': False, 'root': None, 'error': 'unknown_error', 'traceback': tb}
else:
break
r.encoding = 'utf-8'
html = r.content
ram_logger.debug('SIZE: {}'.format(sys.getsizeof(html)))
try:
root = etree.fromstring(html, etree.HTMLParser())
except Exception:
tb = traceback.format_exc()
return {'success': False, 'root': None, 'error': 'root_error', 'traceback': tb}
return {'success': True, 'root': root}
Do you know how to make it safe? Something which make workers wait if there would be buffer overflow problem?
Don’t reinvent the wheel and use Scrapy
web-scraping framework:
Scrapy is an application framework for crawling web sites and
extracting structured data which can be used for a wide range of
useful applications, like data mining, information processing or
historical archival.
Think about it — the scalability/parallelizing/performance problem is solved for you — do you really want to continue diving into wonderful world of Thread
s in python, making your code smell suspiciously, hitting the CPU and memory limits, handling conflicts and, at the end, making your code impossible to debug and maintain — instead of focusing on the extracting and collecting the data? And, even with gevent
I doubt your final code would be in any ways more simple and readable as the same you would implement based on Scrapy. Why not use the tool that was tested and used by a huge amount of users proven to be the best tool ever created in the web-scraping python world?
Here is a working spider that scrapes the quotes in a similar manner:
from scrapy.spider import Spider
from scrapy.item import Item, Field
from scrapy.http import Request
class BloombergItem(Item):
ur = Field()
parameter = Field()
value = Field()
class BloombergSpider(Spider):
name = 'bloomberg'
allowed_domains = ['www.bloomberg.com']
def start_requests(self):
with open("stocks.txt") as f:
for ur in f:
yield Request("http://www.bloomberg.com/quote/%s:US" % ur)
def parse(self, response):
for parameter in response.css('table.key_stat_data tr'):
item = BloombergItem()
item['ur'] = response.xpath('//title/text()').extract()[0].split(':')[0]
item['parameter'] = parameter.xpath('th/text()').extract()[0]
item['value'] = parameter.xpath('td/text()').extract()[0]
yield item
If the contents of stocks.txt
is:
AAPL
The spider would output (for example, if you would choose to output it in JSON):
[
{
"parameter": "Current P/E Ratio (ttm)",
"value": "16.6091",
"ur": "AAPL"
},
{
"parameter": "Estimated P/E(09/2015)",
"value": "13.6668",
"ur": "AAPL"
},
{
"parameter": "Relative P/E vs.",
"value": "0.9439",
"ur": "AAPL"
},
...
]
A good place to start with Scrapy is the Scrapy Tutorial.
За последние 24 часа нас посетил 11621 программист и 1154 робота. Сейчас ищут 216 программистов …
-
- С нами с:
- 28 июл 2016
- Сообщения:
- 43
- Симпатии:
- 0
В скрипте прописано первой же строчкой:
-
ini_set(‘memory_limit’, ‘-1’);
При этом вылетает Out of memory (allocated 14680064) (tried to allocate 11423240 bytes).
Скрипт расшифровывает xml файлы, т.е. в один момент в переменной находится всё содержимое xml файла, да он бывает иногда большой(от 100мб). Но неужели сервер не выдержит такого? Или может тут есть косяк какой-то? Утечек вроде других нету, все подчищаю, просто файлы сами по себе большие. -
Команда форума
Модератор- С нами с:
- 25 июл 2013
- Сообщения:
- 12.162
- Симпатии:
- 1.770
- Адрес:
- :сердА
1) Какая версия пыха?
2) Сервер ваш?
3) Профилирование расхода памяти xdebug-ом делали таймстампом?
4) Имеют место забор/передача данных? Если да, то как? Используется ли буферизация вывода?
5) Сколько памяти на сервере? -
- С нами с:
- 28 июл 2016
- Сообщения:
- 43
- Симпатии:
- 0
1)7.0.20
2)Да, xampp
3)Нет, хз, что это, просто через функцию стандартную и вывод проверял какая переменная скок занимает.
4)Если правильно понял, то данные берутся прямиком из файла, заносятся в mysql. Вывода вообще нету, только в mysql все кладет
5)Если я правильно понимаю, то поскольку я на локальном, то этот вопрос отпадает? -
Команда форума
Модератор- С нами с:
- 25 июл 2013
- Сообщения:
- 12.162
- Симпатии:
- 1.770
- Адрес:
- :сердА
Нет, не отпадает. Нужно поглядеть, во что уперся пых.
xdebug — библиотека для отладки. Одна из ее фич — возможность профилирования работы приложения от вызова к вызову. В итоге получается текстовый файл, где в каждой строке указан вызов функции какой-либо, время, затраченное на выполнение, изменение расхода памяти, общая память, точка вызова и тд, там настраивается. Ну и время самого приложения в конкретный момент.
Помогает реально увидеть утечки, а не на предположениях. Вы думаете, что их нет, а они могут быть в самых неожиданных местах. На данный момент пыха ругается, что ей полтора гига не дали откусить. Полтора гига — это что-то запредельное. Не удивлюсь, если там сам апач перегруженный модулями, еще с пол-гига жрет, и вылет происходит из-за упирания в планку «2гб на 32-битный процесс».
-
- С нами с:
- 28 июл 2016
- Сообщения:
- 43
- Симпатии:
- 0
Вроде я нашел что-то типа утечки (а точнее оптимизировал немного), без xdebug’a, а то у меня что-то не получилось с ним(не отсылает в phpstorm ответку по переменным). Теперь другая проблема, тоже связанная с памятью, мне кажется тут может быть уже сам simpleXML такие объемы не вытягивает?
-
SimpleXMLElement::__construct(): Memory allocation failed : growing buffer in
Или это по прежнему утечка где то?
Раз у меня локальный, то апач же всю оперативку забирает или не? У меня 4гб. Или нет? А как узнать тогда, я не нагуглил что-то)
Кстати сам файл 150мб весит. Я заметил, что вылетает такая ошибка только на файлах больше ~70мб -
- С нами с:
- 28 июл 2016
- Сообщения:
- 43
- Симпатии:
- 0
Вроде разобрался с xdebug’ом, не знаю он ли эту инфу выдал, но вот:
time memory
4.2831 167594464 __construct ( ??? ) …class.php:700
Вот строчка говорит, что памяти много берет. Это конструктор класса simpleXMLElement. То есть утечек нет, тупо такие большие файлы обрабатывать памяти не хватает? Вообще это было бы довольно логично, если файл ~100мб, то объект будет намного больше
— Добавлено —
Какой выход тогда? -
Команда форума
Модератор- С нами с:
- 25 июл 2013
- Сообщения:
- 12.162
- Симпатии:
- 1.770
- Адрес:
- :сердА
Может быть ограничение памяти на процесс апача. И его нужно повысить.
Тут есть ответы на эту тему — https://stackoverflow.com/questions/4399138/upper-memory-limit-for-php-apache, мб пригодится. Под топом там как раз про апач.
— Добавлено —
Но это, разумеется, не решение проблемы, а отсрочка. Если размер файлов будет расти, все равно упретесь.
Тут нужно что-то типа lazy_load. Надо поглядеть, умеет ли simpleXML в такое. Если нет, то использовать расширение, которое умеет. Их много у пыхи, что-то да найдется.Суть приема lazy load в том, что в память мы грузим не все сразу, а только сигнатуры узлов. Сам же узел грузится в память только при обращении к нему. Причем тоже не весь, а лишь в виде сигнатур узлов и атрибутов, по которым, при обращении можно получить конечные данные или другие узлы. А по завершению работы с ним, его можно выгрузить. Таким макаром можно хоть гигабайтовые структуры ворочать и не упираться ни в какие лимиты.
-
- С нами с:
- 28 июл 2016
- Сообщения:
- 43
- Симпатии:
- 0
Добавил, как там говорилось строки:
-
#RLimitMEM 85643200 104857600 # Limit to: 80Mb / process, 100Mb total
-
RLimitMEM 42949672960 85983232000 # Limit to: 128Mb / Process, 512Mb total
Ну цифры я побольше сделал) Сейчас они тут нереальные, но я много раз реальные вводил и по итогу толку насколько я понял 0, но я заметил такую вещь: если скрипт не может распарсить один файл(слишком много весит), то сколько я не перезапускай скрипт, ничего, но если апач перезапустить, то он 2-3 распарсивает, а потом опять та же песня, и такая махинация работает вроде как. С чем это может быть связано?
— Добавлено —
Про laze load интересно, спасибо, можете посоветовать, где прочитать про это можно и чтобы сразу потом в код вклинить?
— Добавлено —
Вообще я думал о том, что тут решило бы проблему не сразу весь файл брать, а по частям, но все реализации мне виделись костыльными, да и щас я совсем ума ни приложу, как это оформить -
- С нами с:
- 28 июл 2016
- Сообщения:
- 43
- Симпатии:
- 0
Можете, пожалуйста, подсказать в направление каких методов смотреть? Или в общих чертах как делается такое, дальше я уж сам постараюсь реализовать это
-
Команда форума
Модератор- С нами с:
- 25 июл 2013
- Сообщения:
- 12.162
- Симпатии:
- 1.770
- Адрес:
- :сердА
Сервер после этого перезапускать надо, к слову.
— Добавлено —Да хоть с блокировкой файла, которая выставлялась от имени апача, а потом пых умирал и не снимал ее. Я хз что у вас там происходит, ищите…
А никак. XML по частям не прочитать, это же не потоковый формат, как обычный текст. В лоб это не решается чтением по кускам. Там хитрее надо быть.
Документация по PHP -> библиотеки для работы с XML.
-
Команда форума
Модератор- С нами с:
- 20 июн 2012
- Сообщения:
- 8.493
- Симпатии:
- 1.732
XMLReader позволяет сократить расход памяти на чтение XML, но делает это чуть более сложной задачей. Я вот это использовал: https://gist.github.com/justthefish/9302625, мне понравилось
-
neverlose
Активный пользователь- С нами с:
- 27 авг 2008
- Сообщения:
- 1.112
- Симпатии:
- 20
14680064 bytes = 14336 Kilobytes = 14 Megabytes
11423240 bytes = ~11156 Kilobytes = ~11 Megabytes -
Команда форума
Модератор- С нами с:
- 25 июл 2013
- Сообщения:
- 12.162
- Симпатии:
- 1.770
- Адрес:
- :сердА
Да, с полутора гигами я маху дал на два регистра.
-
- С нами с:
- 28 июл 2016
- Сообщения:
- 43
- Симпатии:
- 0
Тогда тем более вопрос почему, вылетает при 14 мб, когда без ограничений стоит?) Да и я щас посмотрел, конструктор берет ~150мб примерно, тоже не особо много
— Добавлено —
Вообще там структура xml файла повторяющаяся, что то типа такого:все равно не получится никаким костылем считать? может как нибудь вызывать определенные строки по очереди
-
Команда форума
Модератор- С нами с:
- 20 июн 2012
- Сообщения:
- 8.493
- Симпатии:
- 1.732
Я же дал ссылку. Хотя странно, что php ругается на память. Вариант, который я дал, не строит DOM, поэтому использует значительно меньше памяти
-
- С нами с:
- 28 июл 2016
- Сообщения:
- 43
- Симпатии:
- 0
Точно, прошу прощения, много раз метался в том, в каком направлении все таки проблему решать и забыл про эту ссылку. Спасио
Я работаю над скриптом, который сбрасывает тысячи различных веб-страниц. Поскольку эти страницы обычно разные (имеют разные сайты), я использую многопоточность, чтобы ускорить очистку.
EDIT: ПРОСТОЕ КОРОТКОЕ ПОЯСНЕНИЕ
——-
Я загружаю 300 URL-адресов (htmls) в одном пуле из 300 человек. Так как размер html является переменным, иногда сумма размеров, вероятно, слишком велика и повышает уровень python: internal buffer error: Memory allocation failed: growing buffer
. Я хочу как-то проверить, может ли это произойти, и если, подождите, пока буфер не будет заполнен.
——-
Этот подход работает, но иногда питон начинает бросать:
internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
internal buffer internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
internal buffer error : Memory allocation failed : growing buffer
в консоль. Я полагаю, что это из-за размера html
я храню в памяти, который может быть 300 * (например, 1mb) = 300mb
РЕДАКТИРОВАТЬ:
Я знаю, что могу сократить число рабочих, и я это сделаю. Но это не решение, было бы меньше шансов получить такую ошибку. Я хочу избежать этой ошибки вообще…
Я начал регистрировать размеры html
:
ram_logger.debug('SIZE: {}'.format(sys.getsizeof(html)))
И результат (часть):
2017-03-05 13:02:04,914 DEBUG SIZE: 243940
2017-03-05 13:02:05,023 DEBUG SIZE: 138384
2017-03-05 13:02:05,026 DEBUG SIZE: 1185964
2017-03-05 13:02:05,141 DEBUG SIZE: 1203715
2017-03-05 13:02:05,213 DEBUG SIZE: 291415
2017-03-05 13:02:05,213 DEBUG SIZE: 287030
2017-03-05 13:02:05,224 DEBUG SIZE: 1192165
2017-03-05 13:02:05,230 DEBUG SIZE: 1193751
2017-03-05 13:02:05,234 DEBUG SIZE: 359193
2017-03-05 13:02:05,247 DEBUG SIZE: 23703
2017-03-05 13:02:05,252 DEBUG SIZE: 24606
2017-03-05 13:02:05,275 DEBUG SIZE: 302388
2017-03-05 13:02:05,329 DEBUG SIZE: 334925
Это мой упрощенный метод скремблирования:
def scrape_chunk(chunk):
pool = Pool(300)
results = pool.map(scrape_chunk_item, chunk)
pool.close()
pool.join()
return results
def scrape_chunk_item(item):
root_result = _load_root(item.get('url'))
# parse using xpath and return
И функция загрузки html:
def _load_root(url):
for i in xrange(settings.ENGINE_NUMBER_OF_CONNECTION_ATTEMPTS):
try:
headers = requests.utils.default_headers()
headers['User-Agent'] = ua.chrome
r = requests.get(url, timeout=(settings.ENGINE_SCRAPER_REQUEST_TIMEOUT + i, 10 + i), verify=False, )
r.raise_for_status()
except requests.Timeout as e:
if i >= settings.ENGINE_NUMBER_OF_CONNECTION_ATTEMPTS - 1:
tb = traceback.format_exc()
return {'success': False, 'root': None, 'error': 'timeout', 'traceback': tb}
except Exception:
tb = traceback.format_exc()
return {'success': False, 'root': None, 'error': 'unknown_error', 'traceback': tb}
else:
break
r.encoding = 'utf-8'
html = r.content
ram_logger.debug('SIZE: {}'.format(sys.getsizeof(html)))
try:
root = etree.fromstring(html, etree.HTMLParser())
except Exception:
tb = traceback.format_exc()
return {'success': False, 'root': None, 'error': 'root_error', 'traceback': tb}
return {'success': True, 'root': root}
Вы знаете, как сделать его безопасным? Что-то, что заставляет рабочих ждать, если проблема с переполнением буфера?
Help
Odoo is the world’s easiest all-in-one management software.
It includes hundreds of business apps:
- CRM
- e-Commerce
- Accounting
- Inventory
- PoS
- Project management
- MRP
Take the tour
-
All Forums
- Topics
- People
- Tags
- Badges
- About
Hi Community,
odoo service stopped in server with following error
odoo-bin[9003]: internal buffer error : Memory allocation failed : growing buffer
odoo-bin[9003]: I/O error : buffer full
odoo.service: Main process exited, code=killed, status=11/SEGV
odoo.service: Failed with result 'signal'.
Thanks in Advance
No workers are configured
2Answers
Issue might be happening due to some of cron stuck in processing. you can check by putting logger.
Bug #77212 | Memory allocation failed : growing buffer on aws server | |||
---|---|---|---|---|
Submitted: | 2018-11-28 13:09 UTC | Modified: | 2018-11-28 15:18 UTC | |
From: | sujaljhaonly4u at gmail dot com | Assigned: | ||
Status: | Not a bug | Package: | SimpleXML related | |
PHP Version: | 5.6.38 | OS: | linux | |
Private report: | No | CVE-ID: | None |
[2018-11-28 13:09 UTC] sujaljhaonly4u at gmail dot com
Description: ------------ Hi, i am receiving this message when i am trying to parse the 1.7gb xml file for inserting on aws server. Memory allocation failed : growing buffer.. please help me out! Thank You, Sujal Jha Test script: --------------- <?php include('../product/upload_function_backup.php'); include('../../config/database.php'); include('../../objects/hooks/function.php'); $dir = '../product_feeds/tata cliq'; $file= "tata_cliq_fashion.xml"; $data = file_get_contents($dir.'/'.$file); $xml=stripslashes($data); libxml_use_internal_errors(true); $arr = simplexml_load_string((string)$xml); foreach( libxml_get_errors() as $error ) { print_r($error); } print_r($arr); ?> Expected result: ---------------- SimpleXMLElement Object ( [Product] => Array ( [0] => SimpleXMLElement Object ( [ProductID] => 1065005367 [ProductSKU] => A08160 [ProductName] => WOMEN'S TRAINING STELLASPORT WOVEN SHORTS [ProductDescription] => Stella McCartney inspired adidas SC Woven shorts for women. It comes with an Elasticated waist with two side pockets, one back zipped pocket and all-over 'Stellasport' branding. [ProductPrice] => 1000.00 [ProductPriceCurrency] => INR [WasPrice] => 2499.00 [DiscountedPrice] => 0.00 [ProductURL] => http://clk.omgt5.com/?AID=1327881&PID=17736&Type=12&r=https://shop.adidas.co.in/%23!product/A08160_scwovenshort [PID] => 17736 [MID] => 929898 [ProductImageMediumURL] => https://content.adidas.co.in/static/Product-A08160/Women_Training_Shorts_A08160_1.jpg [StockAvailability] => In stock [Brand] => SPORT PERFORMANCE [custom1] => Gender - Female [custom2] => AgeGroup - Adult [CategoryName] => SHORTS (1/4) [CategoryPathAsString] => Root|TEXTILES|SHORTS (1/4)| ) )
Patches
add-fronk-support
(last revision 2018-11-28 13:15 UTC by sujaljhaonly4u at gmail dot com)
Add a Patch
Pull Requests
Add a Pull Request
History
AllCommentsChangesGit/SVN commitsRelated reports
[2018-11-28 14:19 UTC] spam2 at rhsoft dot net
this is a bugtracker and not a support forum! contact your administrator and make sure you have *at least* twice the memory of stuff you want to proceed available and that there are no resource limits
[2018-11-28 15:18 UTC] cmb@php.net
-Status: Open
+Status: Not a bug
[2018-11-28 15:18 UTC] cmb@php.net
Sorry, but your problem does not imply a bug in PHP itself. For a list of more appropriate places to ask for help using PHP, please visit http://www.php.net/support.php as this bug system is not the appropriate forum for asking support questions. Due to the volume of reports we can not explain in detail here why your report is not a bug. The support channels will be able to provide an explanation for you. Thank you for your interest in PHP.