concurrent.futures.ThreadPoolExecutor не работает как исключение. Потоки перестают работать, даже если в очереди достаточно данных для работы

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

например:

введите здесь описание изображения

Как мы видим, веб-страница http://www.enlightedinc.com/ имеет следующие URL. Итак, один поток завершил сканирование URL http://www.enlightedinc.com/. Он выполнит поисковый робот для URL http://www.enlightedinc.com/support/. . Затем это будет сделано для следующего веб-URL и так далее...

Чтобы все это работало, я использовал Queue, Set, concurrent.futures.ThreadPoolExecutor.

1. Очередь для работы с несколькими потоками, чтобы она могла работать с каждым URL-адресом. 2. Установите, чтобы каждый URL-адрес посещался один раз. 3. concurrent.futures.ThreadPoolExecutor для работы с несколькими потоками.

Вот код.

#python web_crawler.py http://www.enlightedinc.com/
from urllib.request import Request, urlopen
import argparse
import queue
import threading
import concurrent.futures
from bs4 import BeautifulSoup
# set up queue
url_queue = queue.Queue()
lock = threading.Lock()
# created a set to store all visited links
set = set()
total_thread = 2

def web_crawler():
    while True:
        try:
            base_url = url_queue.get(True, 10).strip()
            try:
                # add new url to set and skip visited url
                lock.acquire()
                if base_url in set:
                    continue
                else:
                    set.add(base_url)
            finally:
                lock.release()
            try:
                # get all urls and put in queue
                str_url = base_url
                req = Request(base_url, headers={'User-Agent': 'Mozilla/5.0'})
                html = urlopen(req, timeout = 5).read()
                bs = BeautifulSoup(html, "html.parser")
                possible_links = bs.find_all('a')
                for link in possible_links:
                    if link.has_attr('href') and ("http" in link.attrs['href'] or "https" in link.attrs['href']) and ".pdf" not in link.attrs['href'] and ".png" not in link.attrs['href'] and ".jpg" not in link.attrs['href'] and ".jpeg" not in link.attrs['href']:
                        str_url += "\n\t" + (link.attrs['href'])
                        url_queue.put((link.attrs['href']))
                lock.acquire()
                print (str_url)
                lock.release()
            except urllib.error.HTTPError as e:
                print(e.code)
            except Exception as e:
                print ("Error: " + str(e))
        except queue.Empty:
            print("empty occure")
            break
        finally:
            url_queue.task_done()


# parse the argument
def parse_args():
    parser = argparse.ArgumentParser(description='Script for Web Crawler')
    parser.add_argument('url',help='Starting URL')
    return parser.parse_args()

def main():
    args = parse_args()
    url_queue.put(args.url)
    # Created threadPool to work with multiple threads
    with concurrent.futures.ThreadPoolExecutor() as executor:
        for i in range(total_thread):
            executor.submit(web_crawler)
    print ("size is ")
    print (url_queue.qsize())
    url_queue.join()

if __name__ == "__main__":
    main()

В методе Main я написал url_queue.join(), чтобы убедиться, что поток обработал все URL-адреса в очереди, но когда мы проверяем размер очереди, в очереди уже есть данные. Таким образом, основной поток будет ждать вечно, чтобы завершить весь процесс URL.

Но проблема в том, что в какой-то момент поток перестает работать. Я использую оператор break, если очередь пуста. Поэтому, как только все потоки перестают работать, я проверяю размер очереди в основном методе, но размер очереди не равен нулю. Тогда почему потоки выходят из цикла?

Я пробовал так много вещей, чтобы понять сценарии, но не получил никакого решения.

Буду признателен за любую помощь или подсказку. Заранее спасибо.


person Parth Patel    schedule 31.01.2018    source источник
comment
Вместо того, чтобы бороться с ThreadPools, вы можете использовать asyncio python3, который может упростить задачу. Надеюсь, это поможет вам.   -  person Naveen Honest Raj K    schedule 31.01.2018
comment
Да. Но я хочу понять, как работает поток. Потому что он должен продолжать работать, пока очередь не станет пустой. @NaveenHonestRaj   -  person Parth Patel    schedule 31.01.2018


Ответы (1)


Я думаю размер очереди не изменится. Поскольку в этом ответе говорится, что queue.task_done() не извлекает элемент из очереди, т. е. размер очереди будет только увеличить через ваш скрипт. Все ссылки будут обработаны, но последние отпечатки будут показывать количество посещенных ссылок, а не количество необработанных ссылок.

person Michael Anderson    schedule 02.02.2018