2016-08-09 16 views
2

Ich versuche einen Webcrawler zu schreiben, aber ich stecke fest, weil ich irgendwo in meinem Code keine Endlosschleife sehen kann.Endlosschleife kann ich nicht sehen

class Crawler(object): 
    def __init__(self, url, query, dir = os.path.dirname(__file__)): 
     self.start_url = url 
     self.start_parsed = urllib3.util.parse_url(url) 
     self.query = re.compile(query, re.IGNORECASE) 
     self.dir = dir 
     self.__horizon = set() 
     self.log = [] 

     self.__horizon.add(url) 
     self.log.append(url) 
     print("initializing crawler....") 
     print(locals()) 

    def start(self, depth= 5, url = '/'): 
     print(url, depth) 
     self.log.append(url) 
     if depth > 0: 
      pool = urllib3.PoolManager() 
      data = pool.request("GET", self.start_url if url == '/' else url).data.decode('utf-8') 

      valid_list = [] 
      self.add_horizon(parser_soup.get_links(data), valid_list) 

      if re.search(self.query, parser_soup.get_text(data)): 
       self.output(data) 

      for u in valid_list: 
       self.start(depth = (depth-1), url = u) 

    def output(self, data): 
     with open(os.path.join(self.dir, get_top_domain(self.start_parsed.host) + '.' + str(time.time()) + '.html'), 'w+') as f: 
      f.write(data) 

    def add_horizon(self, url_list, valid_list = []): 
     for url in url_list: 
      if get_top_domain(url) == get_top_domain(self.start_parsed.host) \ 
        and (not str(url) in self.log or not str(url) in self.__horizon): 
       valid_list.append(str(url)) 

     self.__horizon.update(valid_list) 

Es läuft für immer. Wie soll ich sicherstellen, dass ich doppelte Links eliminiere?

+0

was meinst du "kann endlosschleife nicht sehen?" –

+0

@ uoɥʇʎPʎzɐɹC Er versteht nicht, warum sein Code in eine Endlosschleife läuft. –

+0

Nicht verwandt mit Ihrer Frage, aber ein Vorschlag: Machen Sie den PoolManager in '__init__' und verwenden Sie ihn überall, um den größten Nutzen daraus zu ziehen. – shazow

Antwort

2

von Giogian Code Angepasst:

class Crawler(object): 
    def __init__(self, url, query, dir=os.path.dirname(__file__)): 
     self.visited = set() 
     # Rest of code... 

    def start(self, depth=5, url='/'): 
     if url in self.visited: 
      return True 
     self.visited.add(url) 

defaultdict ist ein Wörterbuch, das eine Standard hat, die, wenn der Index existiert nicht verwendet wird. Dies ist jedoch die falsche Lösung. Ein Set wäre speicherfreundlicher und eleganter, wie in meinem Code gezeigt.

Ein Satz verwendet O (1) Zeit - genau so schnell wie @ Giorgians Antwort.

Verwenden Sie Ctrl-C, um Ihr Programm zu unterbrechen, wenn es sich in einer Endlosschleife befindet. Dadurch wird eine Ablaufverfolgung mit dem Befehl angezeigt, der ausgeführt wurde, als das Programm unterbrochen wurde. Tun Sie das ein paar Mal und Sie sollten eine gute Vorstellung davon bekommen, wo es passiert. Alternativ können Sie einen Debugger verwenden und anhalten, wenn er sich in der Endlosschleife befindet, und die Funktion "Schritt" verwenden, um zur nächsten Ausführungszeile zu wechseln, damit Sie die Ausführung des Programms verfolgen können. PyCharm ist ein großartiger Editor mit einem Debugger. Es hat eine gute Autovervollständigung und ist einfach rundum gut. Es ist kostenlos, schau es dir an.

+0

Warum der Downvote? –

+0

defaultdict ist die falsche Lösung! Überprüfen, ob ein Wert in einer Liste ist, dauert O (n) Zeit, während die Verwendung eines Standarddikts nur O (1) Zeit benötigt! –

+0

@ GiorgianBorca-Tasciuc Befestigung ... –

2

Fügen Sie innerhalb Ihres Crawlers eine visited-Eigenschaft hinzu.

from collections import defaultdict 
class Crawler: 
    def __init__(self, url, query, dir = os.path.dirname(__file__)): 
     self.visited = defaultdict(bool) 
     # Rest of code... 

    def start(self, depth= 5, url = '/'): 
     if self.visited[url]: 
      return True 
     self.visited[url] = True 
     # Rest of code... 

Um ehrlich zu sein, kann ich auch nicht die Endlosschleife sehen. Es würde helfen, wenn Sie etwas ausgeben würden.

EDIT: Beachten Sie, dass in der obigen Antwort schrieb ich, dass mit einer defaultdict ist die falsche Lösung. Ich wollte damit sagen, dass die Verwendung einer Liste die falsche Lösung ist!

EDIT 2: @Jona Christopher Sahnwald hat einen Punkt mehr gültig als meins (siehe seinen Kommentar unter der Frage des OP). Es könnte produktiver sein, eine max_visit und current_visit Eigenschaft in Ihrer Klasse hinzuzufügen (auf etwa 1000 gesetzt). Beginnen Sie mit current_visit bei 0, und erhöhen Sie bei jedem Besuch einer Website current_visit. Wenn current_visit größer als max_visit ist, brechen Sie den Crawl ab. Beachten Sie, dass es möglicherweise besser ist, eine Art von Stapel zu implementieren, anstatt die Rekursion zu verwenden, um über besuchte Websites zu rekursiv zu gehen, sodass Sie die Crawlersuche anhalten/fortsetzen können, anstatt sie abzubrechen. Wie so:

from collections import defaultdict 

class Crawler: 
    def __init__(self, url, query, dir = os.path.dirname(__file__)): 
     self.visited = defaultdict(bool) 
     self.current_visit = 0 
     self.max_visit = 1000 
     self.to_visit = [] 
     # Rest of code... 

    def start(self, depth=5, url = '/'): 
     self.to_visit.append((url, 1)) 
     while len(self.to_visit) > 0: 
      url, current_depth = self.to_visit.pop() 
      if current_depth > depth: 
       continue 
      elif visited[url]: 
       continue 
      elif self.current_visited > self.max_visited: 
       break 

      self.current_visited += 1 
      visited[url] = True 

      # Code that does something for each page (like download it, etc) 

      # Code that finds links on page... 

      for link in links_on_page: 
       self.to_visit.append((link, current_depth + 1)) 

Auf diese Weise können Sie die Crawling-Pause einmal current_visit überschreitet max_visit, so dass Sie in Chargen von max_visit kriechen.

+0

Ihr Code läuft nicht einmal –

+0

@ uoɥʇʎPʎzɐɹC Nun, es ist natürlich nicht vollständig!Es soll nur zu OP führen. –

+0

sehe meine Antwort, eine Liste ist viel besser –

Verwandte Themen