2012-05-29 7 views
4

안녕하세요! 파이썬으로 웹 크롤러를 작성하려고합니다. 나는 파이썬 다중 쓰레드를 사용하고 싶었다. 이전에 제안한 논문과 튜토리얼을 읽은 후에도 여전히 문제가 있습니다. 내 코드 (전체 소스 코드 here입니다) 여기에 있습니다 :파이썬 다중 쓰레드 크롤러

class Crawler(threading.Thread): 

    global g_URLsDict 
    varLock = threading.Lock() 
    count = 0 

    def __init__(self, queue): 
     threading.Thread.__init__(self) 
     self.queue = queue 
     self.url = self.queue.get() 

    def run(self): 
     while 1: 
      print self.getName()+" started" 
      self.page = getPage(self.url) 
      self.parsedPage = getParsedPage(self.page, fix=True) 
      self.urls = getLinksFromParsedPage(self.parsedPage) 

      for url in self.urls: 

       self.fp = hashlib.sha1(url).hexdigest() 

       #url-seen check 
       Crawler.varLock.acquire() #lock for global variable g_URLs 
       if self.fp in g_URLsDict: 
        Crawler.varLock.release() #releasing lock 
       else: 
        #print url+" does not exist" 
        Crawler.count +=1 
        print "total links: %d"%len(g_URLsDict) 
        print self.fp 
        g_URLsDict[self.fp] = url 
        Crawler.varLock.release() #releasing lock 
        self.queue.put(url) 

        print self.getName()+ " %d"%self.queue.qsize() 
        self.queue.task_done() 
      #self.queue.task_done() 
     #self.queue.task_done() 


print g_URLsDict 
queue = Queue.Queue() 
queue.put("http://www.ertir.com") 

for i in range(5): 
    t = Crawler(queue) 
    t.setDaemon(True) 
    t.start() 

queue.join() 

필요에 따라이 스레드 1 일 이후에 어떤 결과를 제공하지 않으며 다르게 시간을 실행하고있을 작동하지 않습니다이 오류 제공 :

Exception in thread Thread-2 (most likely raised during interpreter shutdown): 

어떻게 해결할 수 있습니까? 또한 이것은 for 루프보다 효과적이라고 생각하지 않습니다. 사람이 차이를 설명 할 수있는, 다른 장소에서,

def run(self): 
    while 1: 
     print self.getName()+" started" 
     self.page = getPage(self.url) 
     self.parsedPage = getParsedPage(self.page, fix=True) 
     self.urls = getLinksFromParsedPage(self.parsedPage) 

     for url in self.urls: 

      self.fp = hashlib.sha1(url).hexdigest() 

      #url-seen check 
      Crawler.varLock.acquire() #lock for global variable g_URLs 
      if self.fp in g_URLsDict: 
       Crawler.varLock.release() #releasing lock 
      else: 
       #print url+" does not exist" 
       print self.fp 
       g_URLsDict[self.fp] = url 
       Crawler.varLock.release() #releasing lock 
       self.queue.put(url) 

       print self.getName()+ " %d"%self.queue.qsize() 
       #self.queue.task_done() 
     #self.queue.task_done() 
    self.queue.task_done() 

내가 task_done() 명령을 사용하여 실험 :

나는 실행()을 해결하기 위해 노력했다?

+0

이 첫 번째 예는 어떤 들여 쓰기 누락인가요을? 반원들이 한 수준 씩 밀려나는 것처럼 보입니다. –

+0

첫 번째 예를 업데이트했습니다. – torayeff

+0

실례를 게시 할 수 있습니까? 어떤 모듈을 가져 옵니까? –

답변

3

스레드가 초기화 될 때 self.url = self.queue.get() 만 호출하면됩니다. 줄을 추가로 처리하기 위해 새 URL을 선택하려면 while 루프 내부의 대기열에서 URL을 다시 가져 와서 다시 시도해야합니다.

self.page = getPage(self.url)self.page = getPage(self.queue.get())으로 바꾸어보십시오. get 함수는 무기한 차단됩니다. 잠시 후에 타임 아웃하고 배경 스레드가 요청에 따라 정상적으로 종료되도록하는 방법을 추가하는 것이 좋습니다 (예외가 제거 된 경우).

위에서 설명한대로 get()을 사용하는 some good examples on effbot.org이 있습니다. ;

the docs for task_done()에서보세요 : 최초 의견에 답변 -

편집get() (시간 제한 없음)을 호출 할 때마다 task_done()으로 전화를 걸면 모든 대기 호출이 join()으로 차단되어 해당 대기열의 모든 항목이 처리됩니다. get()을 호출 할 때마다 대기열에 새 URL이 게시 될 때까지 대기 (잠자기)됩니다.

Edit2가 -이 대안 실행 기능 시도해보십시오

def run(self): 
    while 1: 
     print self.getName()+" started" 
     url = self.queue.get() # <-- note that we're blocking here to wait for a url from the queue 
     self.page = getPage(url) 
     self.parsedPage = getParsedPage(self.page, fix=True) 
     self.urls = getLinksFromParsedPage(self.parsedPage) 

     for url in self.urls: 

      self.fp = hashlib.sha1(url).hexdigest() 

      #url-seen check 
      Crawler.varLock.acquire() #lock for global variable g_URLs 
      if self.fp in g_URLsDict: 
       Crawler.varLock.release() #releasing lock 
      else: 
       #print url+" does not exist" 
       Crawler.count +=1 
       print "total links: %d"%len(g_URLsDict) 
       print self.fp 
       g_URLsDict[self.fp] = url 
       Crawler.varLock.release() #releasing lock 
       self.queue.put(url) 

       print self.getName()+ " %d"%self.queue.qsize() 

     self.queue.task_done() # <-- We've processed the url this thread pulled off the queue so indicate we're done with it. 
+0

및 task_done() 명령은 어떨까요? 나는 그것을 넣고 그것이 어떻게 영향을 미치는가? task_done() 명령이 호출 될 때 스레드가 잠자기 상태이고 다른 스레드에 시간이 주어 졌습니까? 그렇다면 동시성은 어디에 있습니까? 나는 혼란 스럽다. – torayeff

+0

답변을 보려면 –

+0

을 참조하십시오. task_done()을 호출하면 대기열 인 다른 스레드 만 사용할 수 있습니다. 즉, 대기열에서 url을 가져 와서 즉시 task_done()을 호출하고 url을 얻는 두 번째 방법은 페이지 처리 (페이지 처리 시간이 걸리기 때문에 다른 스레드가 Queue를 사용하게하려는 경우) task_done()을 호출합니다. 차이점은 무엇입니까? 어느 쪽이 효과적 일까 – torayeff