Очистка форума Scrapy, стратегии синхронизации между конвейером статей и обработчиками запросов
Отказ от ответственности На этот вопрос сложно ответить напрямую, и вам нужно иметь хорошее понимание scrapy и последовательности программ, чтобы ответить на него. Мне трудно свернуть вопрос в нечто более простое, чтобы ответить прямо.
AFAIK нельзя вернуть запросы от обработчиков конвейера элементов. Я пытаюсь разобрать все сообщения в определенной категории с форума. Моя стратегия обхода форума следующая:
- Создайте список всех страниц в категории и отправьте их загрузчику для загрузки.
- Получить все темы на каждой странице и отправить их в конвейер.
- Подождите, пока все элементы страницы будут обработаны (вставлены в реляционную базу данных), а затем начните обход каждой темы.
У меня возникают проблемы с выяснением порядка последовательности шагов 3. Я использую следующие два объекта (перечислены в конце), чтобы помочь в логике секвенирования. category::process_page
это обработчик запросов, используемый при обходе тематических страниц.
В классе категории:
Конец фазы 1 представляет все тематические страницы, которые были получены. Конец фазы 2 означает, что конвейер предмета прошел основную работу по всем темам.
Класс тем, который представляет все темы на конкретной странице списка тем, конец фазы 1 означает, что все темы на странице были отправлены в базу данных. Как только каждая тема на странице была добавлена в базу данных, страница удаляется из категории - и как только все страницы сделаны, сканер должен перейти к загрузке всех тем.
Итак, как мне заблокировать загрузчик, чтобы он мог ждать завершения фазы 2 категории, используя логику, которая запускается в конвейере элементов? Есть ли в скрапе какой-то механизм для этого? возможно я могу перезапустить логику загрузчика из конвейера элементов?
Вероятно, существует множество способов сделать это, но я новичок в Python и системный программист C++ / C.
Примечание. Мой первоначальный дизайн должен был быть сделан из 3-4 различных пауков. Один возвращает заголовок форума, второй - все темы, третий - все сообщения, а четвертый - темы, которые необходимо обновить. Но, безусловно, должно быть более естественное решение этой проблемы, я хотел бы сложить последние 3 паука в один.
Я бы принял ответ, что ложка питает логику для запуска пауков, не прибегая к bash (было бы неплохо иметь возможность изгонять пауков из графического интерфейса), тогда я мог бы создать программу драйвера и придерживаться своего первоначального дизайна.
###############################################################################
class TopicPageItemBundle:
def __init__(self,topic_page_url,category_item_bundle):
self.url = topic_page_url
self.topics = set()
self.topics_phase1 = set()
self.category_item_bundle = category_item_bundle
def add_topic(self, topic_url):
self.topics.add(topic_url)
self.topics_phase1.add(topic_url)
def topic_phase1_done(self, topic_url):
self.topics.remove(topic_url)
if len(self.topics_phase1) == 0:
return true
else:
return false
###############################################################################
class CategoryItemBundle:
def __init__(self,forum_id):
self.topic_pages = {}
self.topic_pages_phase1 = set()
self.forum_id = forum_id
def add_topic_page(self,topic_page_url):
tpib = TopicPageItemBundle(topic_page_url,self)
self.topic_pages[topic_page_url] = tpib
self.topic_pages_phase1.add(topic_page_url)
self.topic_pages_phase2.add(topic_page_url)
def process_page(self, response):
return_items = []
tp = TopicPage(response,self)
pagenav = tp.nav()
log.msg("received " + pagenav.make_nav_info(), log.INFO)
page_bundle = self.topic_pages[response.url]
posts = tp.extract_posts(self.forum_id)
for post in posts:
if post != None:
page_bundle.add_topic(post["url"])
post["page_topic_bundle"] = page_bundle
return return_items
# phase 1 represents finishing the retrieval of all topic pages in a forum
def topic_page_phase1_done(self, topic_page_url):
self.topic_pages_phase1.remove(topic_page_url)
if len(self.topic_pages_phase1) == 0:
return true
else:
return false
def topic_page_phase2_done(self,topic_page_url)
self.topic_pages_phase2.remove(topic_page_url)
if len(self.topic_pages_phase2) == 0:
return true
else:
return true
###############################################################################
2 ответа
Есть ли причина, по которой вы хотите начать очищать каждую тему только после того, как получите список всех из них и сохраните их в БД?
Потому что мой блокнотический поток обычно таков: получить страницу со списком тем; найти ссылки для каждой темы и получить запрос для каждой с обратным вызовом для очистки темы; найти ссылку на следующую страницу списка и получить обратный вызов для того же обратного вызова; и так далее.
AFAIK, если из обратного вызова вы сначала получите элемент темы, а затем запрос, ваш конвейер будет немедленно выполнен с данным элементом, поскольку в scrapy все происходит синхронно, и только ресурсы загружаются асинхронно с использованием витой.
Одним из подходов к решению проблемы является объединение кода в конвейере элементов для обработки темы в обработчике запросов. По сути, избавление от разрыва между конвейером элементов и загрузчиком, и таким образом у вас есть только одна фаза, фаза, которая означает, что все темы были вставлены в базу данных без синхронизации.
Это, однако, кажется немного неестественным, так как вы обходите "то, как все должно быть сделано" в скрапе. Вы можете продолжить использовать конвейер элементов, когда начнете очищать тему для сообщений, поскольку это не требует синхронизации.