0

Это касается почти того же кода, о котором я только что задал другой вопрос об этом утром, поэтому, если он выглядит знакомым, это потому, что это так.Список, заполненный Scrapy, возвращается до фактического заполнения

class LbcSubtopicSpider(scrapy.Spider): 

...irrelevant/sensitive code... 

    rawTranscripts = [] 
    rawTranslations = [] 

    def parse(self, response): 
     rawTitles = [] 
     rawVideos = [] 
     for sel in response.xpath('//ul[1]'): #only scrape the first list 

      ...irrelevant code... 

      index = 0 
      for sub in sel.xpath('li/ul/li/a'): #scrape the sublist items 
       index += 1 
       if index%2!=0: #odd numbered entries are the transcripts 
        transcriptLink = sub.xpath('@href').extract() 
        #url = response.urljoin(transcriptLink[0]) 
        #yield scrapy.Request(url, callback=self.parse_transcript) 
       else: #even numbered entries are the translations 
        translationLink = sub.xpath('@href').extract() 
        url = response.urljoin(translationLink[0]) 
        yield scrapy.Request(url, callback=self.parse_translation) 

     print rawTitles 
     print rawVideos 
     print "translations:" 
     print self.rawTranslations 

    def parse_translation(self, response): 
     for sel in response.xpath('//p[not(@class)]'): 
      rawTranslation = sel.xpath('text()').extract() 
      rawTranslation = ''.join(rawTranslation) 
      #print rawTranslation 
      self.rawTranslations.append(rawTranslation) 
      #print self.rawTranslations 

Моя проблема заключается в том, что «печать self.rawTranslations» в parse(...) метод печатает ничего более "[]". Это может означать одну из двух вещей: это может быть сброс списка прямо перед печатью, или это может быть печать перед вызовами parse_translation(...), которые заполняют список из ссылок parse(...). Я склонен подозревать, что это последнее, поскольку я не вижу никакого кода, который бы сбросил список, если только "rawTranslations = []" в классе класса не запускается несколько раз.

Стоит отметить, что если я раскомментирую ту же строку в parse_translation(...), она напечатает желаемый результат, что означает, что он правильно извлекает текст, и проблема кажется уникальной для основного метода parse(...).

Мои попытки решить то, что я считаю проблемой синхронизации, были довольно бесцельными - я просто попытался использовать объект RLock на основе множества обучающих программ Google, которые я смог найти, и я на 99% уверен, что я его неправильно использовал, поскольку результат был идентичным.

+0

Я пробовал Интернет в прошлый час, пытаясь лучше понять блокировки на Python и не очень далеко. Идея, которую я имею в голову, - освободить замок после завершения последнего посещения подстраницы, но я нашел удивительно мало примеров синтаксиса. – jah

ответ

0

Так это кажется чем-то Hacky решение, тем более, что я только что узнал о приоритете запроса Scrapy в функциональность, но вот мой новый код, который дает желаемый результат:

class LbcVideosSpider(scrapy.Spider): 

    ...code omitted... 

    done = 0 #variable to keep track of subtopic iterations 
    rawTranscripts = [] 
    rawTranslations = [] 

    def parse(self, response): 
     #initialize containers for each field 
     rawTitles = [] 
     rawVideos = [] 

     ...code omitted... 

      index = 0 
      query = sel.xpath('li/ul/li/a') 
      for sub in query: #scrape the sublist items 
       index += 1 
       if index%2!=0: #odd numbered entries are the transcripts 
        transcriptLink = sub.xpath('@href').extract() 
        #url = response.urljoin(transcriptLink[0]) 
        #yield scrapy.Request(url, callback=self.parse_transcript) 
       else: #even numbered entries are the translations 
        translationLink = sub.xpath('@href').extract() 
        url = response.urljoin(translationLink[0]) 
        yield scrapy.Request(url, callback=self.parse_translation, \ 
         meta={'index': index/2, 'maxIndex': len(query)/2}) 

     print rawTitles 
     print rawVideos 

    def parse_translation(self, response): 
     #grab meta variables 
     i = response.meta['index'] 
     maxIndex = response.meta['maxIndex'] 

     #interested in p nodes without class 
     query = response.xpath('//p[not(@class)]') 
     for sel in query: 
      rawTranslation = sel.xpath('text()').extract() 
      rawTranslation = ''.join(rawTranslation) #collapse each line 
      self.rawTranslations.append(rawTranslation) 

      #increment number of translations done, check if finished 
      self.done += 1 
      print self.done 
      if self.done==maxIndex: 
       print self.rawTranslations 

в принципе, я просто следил, сколько запросов было завершено и делает код условного на адресацию запроса FINA л. Это отображает полностью заполненный список.

0

Проблема в том, что вы не понимаете, как работает scrapy.

Scrapy - это обходная структура, используемая для создания пауков веб-сайтов, а не только для выполнения запросов, это модуль requests.

Запросы Scrapy работают асинхронно, когда вы вызываете yield Request(...), вы добавляете запросы в стек запросов, которые будут выполняться в какой-то момент (у вас нет контроля над ним). Это означает, что вы не можете ожидать, что некоторая часть вашего кода после того, как yield Request(...) будет выполнена в этот момент. Фактически, ваш метод должен всегда заканчиваться, давая Request или Item.

Теперь из того, что я вижу, и в большинстве случаев путаницы с помощью scrapy, вы хотите сохранить населенный пункт, который вы создали по каким-либо методам, но требуемая информация находится на другом запросе.

В этом случае связь, как правило, осуществляется с помощью параметра meta из Request, что-то вроде этого:

... 
    yield Request(url, callback=self.second_method, meta={'item': myitem, 'moreinfo': 'moreinfo', 'foo': 'bar'}) 

def second_method(self, response): 
    previous_meta_info = response.meta 
    # I can access the previous item with `response.meta['item']` 
    ... 
+0

Я не знаю, насколько это меняет ситуацию, но элемент, который я пытаюсь заполнить, не был создан в методе, а скорее как объект в классе. – jah

+0

Не похоже, что мета-информация - это способ сделать это, или, по крайней мере, не с тем, как я все структурировал.Причина в том, что я могу дать только другой запрос из 'parse' или' parse_translation', и ни один из методов не сможет передать 'self.rawTranslations' в его полное состояние. Если бы я делал это в 'parse', он пропускал бы пустой список; если бы я это делал в 'parse_translation', он называл бы мой третий (неписанный) метод столько раз, сколько был бы списком, а не только один раз в конце. Я думаю, что это связано с тем, что контейнер находится вне метода. – jah

Смежные вопросы