Я работаю над поисковым роботом, используя 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, если очередь пуста. Поэтому, как только все потоки перестают работать, я проверяю размер очереди в основном методе, но размер очереди не равен нулю. Тогда почему потоки выходят из цикла?
Я пробовал так много вещей, чтобы понять сценарии, но не получил никакого решения.
Буду признателен за любую помощь или подсказку. Заранее спасибо.