2016-09-01 3 views
0

Я довольно новичок в python, и я надеюсь, что кто-то здесь может мне помочь.Пул многопроцессорности Python замерзает без причины

Я начал изучать python несколько недель назад, и я попытался создать webcrawler.

Идея такова: первая часть обходит домены с сайта (для каждой буквы). Вторая часть проверяет, действителен ли домен (доступен и не припаркован), и сохраняется в базе данных.

Все идет хорошо, пока гусеничный ход не достигнет «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

я уже нашел подобную проблему здесь: [ссылка] (http://stackoverflow.com/questions/19071529/python-multiprocessing-125-list-never-finishes) Но программа останавливается в потоке пул и даже не доходит до линии, где я закрываю и присоединяюсь к пулу. – mLe

ответ

0

После нескольких часов отладки и тестирования я мог бы исправить эту проблему.

Вместо многопроцессорной бассейна я использовал ThreadPoolExecutor (что лучше для сетевых приложений)

Я понял, что requests.get() в функции резьбовым вызвало некоторые проблемы. Я изменил таймаут на 1.

После этих изменений программа работала.

Я не знаю точно, но я был бы очень заинтересован в этом. Если кто-то это знает, я был бы признателен, если бы он/она мог опубликовать его.