2016-09-01 4 views
0

私はPythonにはかなり新しく、ここの誰かが私を助けてくれることを願っています。Pythonマルチプロセッシングプールが理由なしにフリーズする

私は数週間前にパイソンを学び始めました。私はウェブクローラーを構築しようとしました。

アイデアは次のとおりです。最初の部分はウェブサイトからドメインをクロールします(各レター用)。 2番目の部分は、ドメインが有効である(到達可能であり、駐車されていない)かどうかをチェックし、それをデータベースに保持します。

クローラが「r」に達するまですべてうまくいっています。数分後、プログラムはエラーメッセージなしでフリーズします。 'r'の後の文字も問題ありません...プログラムがフリーズするドメインは同じではありません。

import requests 
import re 
import logging 
import time 

from bs4 import BeautifulSoup 

from multiprocessing.pool import Pool 

""" Extract only the plain text of element 
""" 
def visible(element): 
    if element.parent.name in ['style', 'script', '[document]', 'head', 'title']: 
     return False 
    elif re.match('.*<!--.*-->.*', str(element), re.DOTALL): 
     return False 
    elif re.fullmatch(r"[\s\r\n]", str(element)): 
     return False 
    return True 


logging.basicConfig(format='%(asctime)s %(name)s - %(levelname)s: %(message)s', level=logging.ERROR) 
logger = logging.getLogger('crawler') 
hdlr = logging.FileHandler('crawler.log') 
formatter = logging.Formatter('%(asctime)s %(name)s - %(levelname)s: %(message)s') 
hdlr.setFormatter(formatter) 
logger.addHandler(hdlr) 
logger.setLevel(logging.DEBUG) 

""" Checks if a domain is parked. 
    Returns true if a domain is not parked, otherwise false 
    """ 
def check_if_valid(website): 
    try: 
     resp = requests.get("http://www." + website, timeout=10, verify=False) 

     soup = BeautifulSoup(resp.text, 'html.parser') 

     if len(soup.find_all('script')) == 0: 
      # check for very small web pages 
      if len(resp.text) < 700: 
       return None 
      # check for 'park' pattern 
      text = filter(visible, soup.find_all(text=True)) 
      for elem in text: 
       if 'park' in elem: 
        return None 

     return "http://www." + website + "/" 

    except requests.exceptions.RequestException as e: 
     # no logging -> too many exceptions 
     return None 
    except Exception as ex: 
     logger.exception("Error during domain validation") 


def persist_domains(nonParkedDomains): 
    logger.info("Inserting domains into database") 
    dbConn = mysqlDB.connect() 

    for d in nonParkedDomains: 
     mysqlDB.insert_company_domain(dbConn, d) 

    mysqlDB.close_connection(dbConn) 


if __name__ =="__main__": 
    dryrun = True 

    if dryrun: 
     logger.warning("Testrun! Data does not get persisted!") 

    url = "http://www.safedomain.at/" 

# chars = ['0-9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't','u', 'v', 'w', 'x', 'y', 'z'] 
    chars = ['r','s', 't','u', 'v', 'w', 'x', 'y', 'z'] 
    payload = {'sub': 'domains', 'char': '', 'page': '1'} 

    domains = list() 
    cntValidDomains = 0 


    logger.info("Start collecting domains from \"http://www.safedomain.at\"....") 
    try: 
     for c in chars: 
      payload['char'] = c 
      payload['page'] = '1' 

      response = requests.get(url, params=payload, verify=False) 
      soup = BeautifulSoup(response.text, 'html.parser') 

      while not soup.find_all('a', {'data-pagenumber': True}): 
       time.sleep(5) 
       response = requests.get(url, params=payload, verify=False) 
       soup = BeautifulSoup(response.text, 'html.parser') 

      maxPage = int(soup.find_all('a', {'data-pagenumber': True})[-1].getText()) 

      domains = list() 
      for page in range(1, maxPage + 1): 
       payload['page'] = page 

       logger.debug("Start crawling with following payload: char=%s page=%s", payload['char'], payload['page']) 

       response = requests.get(url, params=payload) 
       soup = BeautifulSoup(response.text, 'html.parser') 

       for elem in soup.find_all('ul', {'class': 'arrow-list'}): 
        for link in elem.find_all('a'): 
         domains.append(link.getText()) 

      logger.info("Finished! Collected domains for %s: %s",c, len(domains)) 
      logger.info("Checking if domains are valid...") 

      with Pool(48) as p: 
       nonParkedDomains = p.map(check_if_valid, domains) 

      p.close() 
      p.join() 

      nonParkedDomains = list(filter(None.__ne__, nonParkedDomains)) 

      cntTemp = cntTemp + len(nonParkedDomains) 

      # check if domains should get persisted 

      if dryrun: 
       logger.info("Valid domains for %s in domains", c) 
       for elem in nonParkedDomains: 
        logger.info(elem) 
      else: 
       persist_domains(nonParkedDomains) 

      logger.info("Finished domain validation for %s!", c) 
      cntValidDomains = cntTemp + cntValidDomains 

     logger.info("Valid domains: %s", cntTemp) 
     logger.info("Program finished!") 

    except Exception as e: 
     logger.exception("Domain collection stopped unexpectedly") 

EDIT:

は、ここに私のコードでいくつかの時間のデバッグとテストの後、私はアイデアを持っています。スレッドで使用されているリクエストモジュールが問題を引き起こす可能性はありますか?

+0

私は既にここで同様の問題を発見しました:[link](http://stackoverflow.com/questions/19071529/python-multiprocessing-125-list-never-finishes) しかし、プログラムはスレッドで停止します私がプールを閉めてプールに入るラインまで届かない。 – mLe

答えて

0

数時間のデバッグとテストの後、私は問題を解決できました。

代わりに、私は(ネットワークアプリケーションのためのより良いです)ThreadPoolExecutor

を使用しましたマルチプロセッシング・プールのIは、ねじの機能でrequests.get()はいくつかのトラブルを引き起こしたことを考え出しました。タイムアウトを1に変更しました。

これらの変更の後、プログラムが機能しました。

正確な理由はわかりませんが、私は非常に興味があります。もし誰かがそれを知っていれば、私は彼がそれを投稿できるかどうか分かります。

関連する問題