Передача данных к предыдущему обратному вызову с помощью Scrapy - PullRequest
1 голос
/ 18 апреля 2019

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

Когда паук получает доступ к странице индекса, он извлекает ссылки для просмотра фильма (http://tamnhinso.info/phim/phim-bo/),, затем он выдаст запросполучить страницу показа для фильмов (у которых есть много эпизодов), оттуда он будет анализировать ссылку для каждого эпизода, затем попытаться выдать запрос GET для каждого URL эпизода. После этого паук проанализирует ответ HTML, чтобы получить видеоссылка для каждого эпизода.

def start_requests(self):
      for url in self.start_urls:
        yield Request(url=url, callback=self.parse_list_movie)

    def parse_list_movie(self, response):
      movie_urls = LinkExtractor(restrict_xpaths="//div[@class='col-md-2 col-xs-6 movie-item']").extract_links(response)
      for item in movie_urls:
        yield Request(url=item.url, callback=self.parse_movie_info)

      next_page = response.meta.get('next_page')
      num_next_page = 2 if next_page is None else next_page
      next_page_link = "phim/phim-bo/viewbycategory?page="

      if num_next_page <= 40:
        yield response.follow(next_page_link + str(num_next_page), 
                      callback=self.parse_list_movie, meta = {'next_page' : num_next_page + 1})

    def parse_movie_info(self, response):
      l = ItemLoader(item=PhimBoItem(), response=response)
      #some code to retrieve information from that film

      link_film_url = response.xpath("//div[@class='movie-detail']//div[@class='mt-10']/a/@href").extract_first()
      yield scrapy.Request(url=response.urljoin(link_film_url), callback=self.parse_list_episode, meta={"item": l})


    def parse_list_episode(self, response):
        loader = response.meta.get('item')
        script = """
                function main(splash)
                    splash.html5_media_enabled = true
                    splash.private_mode_enabled = false
                    assert(splash:go(splash.args.url))
                    assert(splash:wait(3))
                    return splash:html()
                end
            """
        for episode in LinkExtractor(restrict_xpaths="//div[@class='col-md-6 mt-20 watch-chap']").extract_links(response):
            yield SplashRequest(url=response.urljoin(episode.url), callback=self.parse_link_episode, meta={'item': loader}, endpoint='execute',
                                    args={'lua_source': script,'wait': 5, 'timeout': 3600})

    def parse_link_episode(self, response):
      loader = response.meta.get('item')
      loader.replace_value('episode', self.get_episode(response))
      return loader.load_item()

    def get_episode(self, response):
        l = ItemLoader(item=Episode(), response=response)
        l.add_value('ep_num', response.url, re = r'\-(\d+)')
        l.add_value('link', self.get_link(response))
        return dict(l.load_item())


    def get_link(self, response):
      l = ItemLoader(item=Link(), response=response)
      l.add_xpath('link_360', "//source[@label='360']/@src")
      l.add_xpath('link_720', "//source[@label='720']/@src")
      l.add_xpath('link_1080',  "//source[@label='1080']/@src")

      return dict(l.load_item())

Возвращенный элемент будет пропущен через конвейеры элементов и сохранен в формате строки json. Поскольку у каждого фильма есть много эпизодов, результат, который я получаю, выглядит следующим образом:

{"id":1, ..., "episode": {"ep_num": "1", "link": "..."}}
{"id":1, ..., "episode": {"ep_num": "2", "link": "..."}}
{"id":2, ..., "episode": {"ep_num": "1", "link": "..."}}

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

{"id":1, ..., "episode": [{"ep_num": "1", "link": "..."}, 
                           {"ep_num": "2", "link": "..."}, ...]}
{"id":2, ..., "episode": {"ep_num": "1", "link": "..."}}

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

1 Ответ

1 голос
/ 20 апреля 2019

Насколько мне известно, по крайней мере, не существует простого способа собрать эти ответы в вашем методе синтаксического анализа.

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

Если вы не можете ждать так долго, вы можете передать список запрошенных URL-адресов в виде метаданных с каждым запросом.В вашем конвейере товаров вы можете попытаться дождаться всех этих ответов, пока не выполните дальнейшую обработку.В этом случае вы должны убедиться, что действительно все запросы производят элемент (даже те, которые не были выполнены или отброшены).

РЕДАКТИРОВАТЬ: Я только что наткнулся на эту библиотеку.Это может помочь вам: https://github.com/rmax/scrapy-inline-requests

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...