2016-09-01 2 views
0

Ich bin ziemlich neu zu Python und ich hoffe, dass jemand hier mir helfen kann.Python Multiprozessing Pool friert ohne Grund ein

Ich habe vor einigen Wochen angefangen, Python zu lernen, und ich habe versucht, einen Webcrawler zu bauen.

Die Idee ist folgende: Der erste Teil crawlt die Domänen von einer Website (für jeden Buchstaben). Der zweite Teil prüft, ob die Domain gültig ist (erreichbar und nicht geparkt) und hält sie in einer Datenbank.

Alles läuft gut, bis der Crawler 'r' erreicht. Nach einigen Minuten friert das Programm ohne Fehlermeldung usw. Auch die Buchstaben nach 'r' machen keine Probleme ... Die Domäne, in der das Programm einfriert, ist nicht das Gleiche.

Hier ist mein Code:

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: Nach einigen Stunden Debuggen und Testen Ich habe eine Idee. Kann es sein, dass das Request-Modul, das im Thread verwendet wird, Probleme verursacht?

+0

Ich habe bereits ein ähnliches Problem hier gefunden: [link] (http://stackoverflow.com/questions/19071529/python-multiprocessing-125-list-never-finishes) Aber das Programm stoppt im Thread Pool und erreicht nicht einmal die Linie, wo ich schließe und schließe mich dem Pool an. – mLe

Antwort

0

Nach mehreren Stunden Debugging und Tests konnte ich das Problem beheben.

Stattdessen Pool des Multiprozessing ich die ThreadPoolExecutor verwendet haben (die für Netzwerkanwendungen besser ist)

ich herausgefunden haben, dass die requests.get() in der Gewinde Funktion einige Probleme verursacht. Ich habe das Timeout auf 1 geändert.

Nach diesen Änderungen funktionierte das Programm.

Ich weiß nicht den genauen Grund, aber ich würde mich sehr dafür interessieren. Wenn jemand es weiß, würde ich mich freuen, wenn er es posten könnte.

Verwandte Themen