1

私は数千もの異なるWebページをスクラップするスクリプトを作成しています。これらのページは通常異なるので(サイトが異なる)、マルチスレッドを使用してスクレイピングを高速化します。メモリの割り当てに失敗しました:バッファの増加 - Python

EDIT:SIMPLE短い説明

-------

私は300人の労働者の1つのプールに300件のURL(HTMLS)をロードしています。 htmlのサイズは可変であるため、サイズの合計が大きすぎる可能性があり、Pythonは次のようになります。internal buffer error : Memory allocation failed : growing buffer。私は何とかこのことが起こる可能性があるかどうかをチェックし、バッファがいっぱいになるまで待ってください。

-------

このアプローチは動作しますが、時々、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 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 

。私はそれがために300にすることができ、私はメモリに格納htmlのサイズ、であると仮定する* = 300メガバイト(たとえば1メガバイトなど)

EDIT:

私は労働者の数を減らすことができることを知っていますします。しかし、それは解決策ではありません、そのようなエラーを取得するためにちょうど低いチャンスがあります。私はすべてではこのエラーを回避したい...

は私が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} 

あなたはそれを安全にする方法をご存知ですか?バッファオーバーフローの問題がある場合、作業者を待機させる何か?

答えて

1

あなたが何であるかを推測する必要はありませんので、total_memも自動計算できる が

lock = threading.Lock() 
total_mem= 1024 * 1024 * 500 #500MB spare memory 
@contextlib.contextmanager 
def ensure_memory(size): 
    global total_mem 
    while 1: 
     with lock: 
      if total_mem > size: 
       total_mem-= size 
       break 
     time.sleep(1) #or something else... 
    yield 
    with lock: 
     total_mem += size 

def _load_root(url): 
    ... 
    r = requests.get(url, timeout=(settings.ENGINE_SCRAPER_REQUEST_TIMEOUT + i, 10 + i), verify=False, stream=True) #add the stream=True to make request wait on on loading the entire request 
    ... 
    with ensure_memory(r.headers['content-length']): 
     #now do stuff here :) 
     html = r.content 
     ... 
     return {'success': True, 'root': root} 

テストされていません...利用できるXメモリがある場合にのみ起動する各ワーカーを制限することができます各マシンの正しい値...

関連する問題