Я пишу сканер для своего приложения SPA. Поскольку это SPA, я не могу использовать wget / curl или любое другое решение, не основанное на браузере, для сканирования, потому что мне нужен браузер для запуска javascript в моем SPA.
Я закодировал это, используя питон и селен. Он начнется на главной странице, отсканирует все элементы href
, сохранит их в формате set
, отменит те, которые я уже посетил (visited
, как в opened with selenium and collected all the href elements
), и возьмет следующий URL из набора. и посетить его. Затем он будет повторять процесс снова и снова, пока не посетит все ссылки.
Код выглядит так:
def main():
...
# Here we will be saving all the links that we can find in the DOM of
# each visited URL
collected = set()
collected.add(crawler.start_url)
# Here we will be saving all the URLs that we have already visited
visited = set()
base_netloc = urlparse(crawler.start_url).netloc
while len(collected):
url = collected.pop()
urls = self.collect_urls(url)
urls = [x for x in urls if x not in visited and urlparse(x).netloc == base_netloc]
collected = collected.union(urls)
visited.add(url)
crawler.links = list(visited)
crawler.save()
def collect_urls(self, url):
browser = Browser()
browser.fetch(url)
urls = set()
elements = browser.get_xpath_elements("//a[@href]")
for element in elements:
link = browser.get_element_attribute(element, "href")
if link != url:
urls.add(link)
browser.stop()
return urls
Я хочу сделать каждый вызов collect_urls
задачей Celery, чтобы он мог повторить попытку в случае сбоя, а также сделать все это быстрее (используя несколько рабочих). Проблема в том, что collect_urls
вызывается изнутри while
, который зависит от набора collected
, который заполняется результатами collect_urls
.
Я знаю, что могу вызвать задачу Celery с помощью delay()
и ждать результата с помощью get()
, поэтому мой код будет выглядеть следующим образом:
while len(collected):
url = collected.pop()
task = self.collect_urls.delay(url)
urls = task.get(timeout=30)
Это преобразует мои вызовы в collect_urls
в задачи Celery, и это позволит мне повторить попытку в случае сбоя, но я все равно не смогу использовать более одного работника, так как мне нужно ждать результата delay()
.
Как я могу реорганизовать свой код таким образом, чтобы он позволял мне использовать несколько рабочих для collect_urls
?