IMDB Movie Scraping дает пустой CSV с использованием Scrapy - PullRequest
0 голосов
/ 17 января 2019

Я получаю бланк csv, хотя в коде ошибки не отображаются. Невозможно просканировать веб-страницу.

Это код, который я написал со ссылкой на YouTube: -

import scrapy

from Example.items import MovieItem

class ThirdSpider(scrapy.Spider):
name = "imdbtestspider"
allowed_domains = ["imdb.com"]
start_url = ('http://www.imdb.com/chart/top',)


  def parse(self,response):
    links = response.xpath('//tbody[@class="lister-list"]/tr/td[@class="titleColumn"]/a/@href').extract()
    i = 1
    for link in links:
        abs_url = response.urljoin(link)
        #
        url_next = '//*[@id="main"]/div/span/div/div/div[2]/table/tbody/tr['+str(i)+']/td[3]/strong/text()'
        rating = response.xpath(url_next).extact()
        if (i <= len(link)):
            i=i+1
            yield scrapy.Request(abs_url, callback = self.parse_indetail, meta = {'rating': rating})

  def parse_indetail(self,response):
    item = MovieItem()
    #
    item['title'] = response.xpath('//div[@class="title_wrapper"])/h1/text()').extract[0][:-1]
    item['directors'] = response.xpath('//div[@class="credit_summary_items"]/span[@itemprop="director"]/a/span/text()').extract()[0]
    item['writers'] = response.xpath('//div[@class="credit_summary_items"]/span[@itemprop="creator"]/a/span/text()').extract()
    item['stars'] = response.xpath('//div[@class="credit_summary_items"]/span[@itemprop="actors"]/a/span/text()').extract()
    item['popularity'] = response.xpath('//div[@class="titleReviewBarSubItem"]/div/span/text()').extract()[2][21:-8]

    return item

Это вывод, который я получаю при выполнении кода с

scrapy crawl imdbtestspider -o example.csv -t csv

2019-01-17 18:44:34 [scrapy.core.engine] ИНФОРМАЦИЯ: Паук открыт 2019-01-17 18:44:34 [scrapy.extensions.logstats] ИНФОРМАЦИЯ: Просканировано 0 страниц (при 0 pag эс / мин), соскоб 0 пунктов (при 0 ст / мин)

Ответы [ 3 ]

0 голосов
/ 18 января 2019

Относительно того, почему вы получаете сообщение об ошибке "0 / страниц просканировано", несмотря на то, что вы не воссоздаете ваш случай, я должен предположить, что ваш метод итерации страницы не создает правильные URL-адреса страницы.

У меня проблемы с пониманием использования для создания массива переменных всех "последующих ссылок", а затем с помощью len для отправки их в parse_indetail (), но пара вещей, на которые стоит обратить внимание.

  1. Когда вы используете «мета» для передачи элементов из одной функции в другую, хотя у вас есть правильная идея, вам не хватает некоторых экземпляров для функции, в которую вы ее передаете (вам также следует использовать стандартное соглашение об именах для простота)

Должно быть что-то вроде этого ...

def parse(self,response):
    # If you are going to capture an item at the first request, you must instantiate
    # your items class
    item = MovieItem()
    ....
    # You seem to want to pass ratings to the next function for itimization, so
    # you make sure that you have it listed in your items.py file and you set it
    item[rating] = response.xpath(PATH).extact() # Why did you ad the url_next? huh?
    ....
    # Standard convention for passing meta using call back is like this, this way
    # allows you to pass multiple itemized item gets passed
    yield scrapy.Request(abs_url, callback = self.parse_indetail, meta = {'item': item})

  def parse_indetail(self,response):
    # Then you must initialize the meta again in the function your passing it to
    item = response.meta['item']
    # Then you can continue your scraping
  1. Вы не должны усложнять логику итерации страницы. Кажется, вы понимаете, как это работает, но вам нужна помощь в настройке этого аспекта Я воссоздал ваш вариант использования и оптимизировал его.
#items.py file
import scrapy


class TestimbdItem(scrapy.Item):
    title = scrapy.Field()
    directors = scrapy.Field()
    writers = scrapy.Field()
    stars = scrapy.Field()
    popularity = scrapy.Field()
    rating = scrapy.Field()
# The spider file
import scrapy
from testimbd.items import TestimbdItem

class ImbdsdpyderSpider(scrapy.Spider):
    name = 'imbdsdpyder'
    allowed_domains = ['imdb.com']
    start_urls = ['http://www.imdb.com/chart/top']

    def parse(self, response):
        for href in response.css("td.titleColumn a::attr(href)").extract():
            yield scrapy.Request(response.urljoin(href),
                                 callback=self.parse_movie)

    def parse_movie(self, response):
        item = TestimbdItem()
        item['title'] = [ x.replace('\xa0', '')  for x in response.css(".title_wrapper h1::text").extract()][0]
        item['directors'] = response.xpath('//div[@class="credit_summary_item"]/h4[contains(., "Director")]/following-sibling::a/text()').extract()
        item['writers'] = response.xpath('//div[@class="credit_summary_item"]/h4[contains(., "Writers")]/following-sibling::a/text()').extract()
        item['stars'] = response.xpath('//div[@class="credit_summary_item"]/h4[contains(., "Stars")]/following-sibling::a/text()').extract()
        item['popularity'] = response.css(".titleReviewBarSubItem span.subText::text")[2].re('([0-9]+)')
        item['rating'] = response.css(".ratingValue span::text").extract_first()

        yield item

Обратите внимание на две вещи: Идентификатор функции parse (). Все, что я здесь делаю, - это использую цикл for для ссылок, каждый экземпляр в цикле ссылается на href и передает urljoined href в функцию парсера. Приведите пример использования, этого более чем достаточно. В ситуации, когда у вас есть следующая страница, она просто каким-то образом создает переменную для «следующей» страницы и вызывает обратный вызов для анализа, она будет продолжать это делать, пока не сможет отфильтровать «следующую» страницу.

Во-вторых, используйте xpath только тогда, когда элементы HTML имеют одинаковый тег с разным содержимым. Это скорее личное мнение, но я говорю людям, что селекторы xpath - это как скальпель, а селекторы css - как нож мясника. Вы можете быть чертовски точными с помощью скальпеля, но это занимает больше времени, и во многих случаях может быть проще использовать CSS-селектор, чтобы получить тот же результат.

0 голосов
/ 18 января 2019

Это еще один способ попробовать.Я использовал css selector вместо xpath, чтобы сделать скрипт менее подробным.

import scrapy

class ImbdsdpyderSpider(scrapy.Spider):
    name = 'imbdspider'
    start_urls = ['http://www.imdb.com/chart/top']

    def parse(self, response):
        for link in response.css(".titleColumn a[href^='/title/']::attr(href)").extract():
            yield scrapy.Request(response.urljoin(link),callback=self.get_info)

    def get_info(self, response):
        item = {}
        title = response.css(".title_wrapper h1::text").extract_first()
        item['title'] = ' '.join(title.split()) if title else None
        item['directors'] = response.css(".credit_summary_item h4:contains('Director') ~ a::text").extract()
        item['writers'] = response.css(".credit_summary_item h4:contains('Writer') ~ a::text").extract()
        item['stars'] = response.css(".credit_summary_item h4:contains('Stars') ~ a::text").extract()
        popularity = response.css(".titleReviewBarSubItem:contains('Popularity') .subText::text").extract_first()
        item['popularity'] = ' '.join(popularity.split()).strip("(") if popularity else None
        item['rating'] = response.css(".ratingValue span::text").extract_first()
        yield item
0 голосов
/ 17 января 2019

Я проверил вас с учетом xpaths Я не знаю, что они ошибаются или на самом деле ошибаются.

например,

xpath = //*="main"]/div/span/div/div/div[2]/table/tbody/tr['+str(i)+']/td[3]/strong/text()

#There is not table when you reach at div[2]

//div[@class="title_wrapper"])/h1/text()    #here there is and error after `]` ) is bad syntax

Кроме того, ваши xpaths не дают никаких результатов.

...