Мне нужно почистить сайт обмена фильмами, где каждый фильм может иметь несколько эпизодов.Паук по-прежнему работает нормально, но есть некоторые недостатки с возвращенными элементами.
Когда паук получает доступ к странице индекса, он извлекает ссылки для просмотра фильма (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": "..."}}
Я думаю, мне нужно передать данные обратно к предыдущемуобратный вызов в скрапе, но я не понимаю, как это сделать. Пожалуйста, помогите мне. Я действительно ценю это. Спасибо.