【问题标题】:IMDB scrapy get all movie dataIMDB scrapy 获取所有电影数据
【发布时间】:2016-06-19 13:36:08
【问题描述】:

我正在做一个课堂项目,并试图获取截至 2016 年的所有 IMDB 电影数据(标题、预算等)。我采用了来自 https://github.com/alexwhb/IMDB-spider/blob/master/tutorial/spiders/spider.py 的代码。

我的想法是:从 i in range(1874,2016) (因为 1874 是 http://www.imdb.com/year/ 上显示的最早年份),将程序定向到相应年份的网站,并从该 url 获取数据。

但问题是,每年每个页面只显示 50 部电影,所以在爬取了 50 部电影之后,我如何才能转到下一页呢?每年爬完之后,我如何才能进入下一年?到目前为止,这是我解析 url 部分的代码,但它只能抓取特定年份的 50 部电影。

class tutorialSpider(scrapy.Spider):
    name = "tutorial"
    allowed_domains = ["imdb.com"]
    start_urls = ["http://www.imdb.com/search/title?year=2014,2014&title_type=feature&sort=moviemeter,asc"] 

    def parse(self, response):
            for sel in response.xpath("//*[@class='results']/tr/td[3]"):
                item = MovieItem()
                item['Title'] = sel.xpath('a/text()').extract()[0]
                item['MianPageUrl']= "http://imdb.com"+sel.xpath('a/@href').extract()[0]
                request = scrapy.Request(item['MianPageUrl'], callback=self.parseMovieDetails)
                request.meta['item'] = item
                yield request

【问题讨论】:

  • div class="see-more -> "/search/title?year=1930,1930&title_type=feature&sort=moviemeter,asc 然后,如果您查看该页面,则会发现另一条线索,span class="pagination" -> href="/search/title?sort=moviemeter,asc&start=51&title_type=feature&year=1930,1930"

标签: python python-2.7 scrapy scrapy-spider


【解决方案1】:

我想出了一个非常愚蠢的方法来解决这个问题。我将所有链接都放在 start_urls 中。更好的解决方案将不胜感激!

class tutorialSpider(scrapy.Spider):
    name = "tutorial"
    allowed_domains = ["imdb.com"]
    start_urls = []
    for i in xrange(1874, 2017):
        for j in xrange(1, 11501, 50): 
        # since the largest number of movies for a year to have is 11,400 (2016)
        start_url = "http://www.imdb.com/search/title?sort=moviemeter,asc&start=" + str(j) + "&title_type=feature&year=" + str(i) + "," + str(i)
        start_urls.append(start_url)

    def parse(self, response):
        for sel in response.xpath("//*[@class='results']/tr/td[3]"):
            item = MovieItem()
            item['Title'] = sel.xpath('a/text()').extract()[0]
            item['MianPageUrl']= "http://imdb.com"+sel.xpath('a/@href').extract()[0]
            request = scrapy.Request(item['MianPageUrl'], callback=self.parseMovieDetails)
            request.meta['item'] = item
            yield request

【讨论】:

  • 硬编码值不是一个好主意,你看我留下的评论了吗?您可以解析页面本身的所有链接以观看更多电影。
  • @PadraicCunningham 刚刚看到。谢谢!
【解决方案2】:

您可以使用CrawlSpiders 来简化您的任务。正如您将在下面看到的,start_requests 动态生成 URL 列表,而 parse_page 仅提取要抓取的电影。通过rules 属性查找并点击“下一步”链接。

我同意@Padraic Cunningham 的观点,即硬编码值不是一个好主意。我添加了蜘蛛参数,以便您可以调用: scrapy crawl imdb -a start=1950 -a end=1980(如果没有任何参数,scraper 将默认为 1874-2016)。

import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

from imdbyear.items import MovieItem

class IMDBSpider(CrawlSpider):
    name = 'imdb'
    rules = (
        # extract links at the bottom of the page. note that there are 'Prev' and 'Next'
        # links, so a bit of additional filtering is needed
        Rule(LinkExtractor(restrict_xpaths=('//*[@id="right"]/span/a')),
            process_links=lambda links: filter(lambda l: 'Next' in l.text, links),
            callback='parse_page',
            follow=True),
    )

    def __init__(self, start=None, end=None, *args, **kwargs):
      super(IMDBSpider, self).__init__(*args, **kwargs)
      self.start_year = int(start) if start else 1874
      self.end_year = int(end) if end else 2016

    # generate start_urls dynamically
    def start_requests(self):
        for year in range(self.start_year, self.end_year+1):
            yield scrapy.Request('http://www.imdb.com/search/title?year=%d,%d&title_type=feature&sort=moviemeter,asc' % (year, year))

    def parse_page(self, response):
        for sel in response.xpath("//*[@class='results']/tr/td[3]"):
            item = MovieItem()
            item['Title'] = sel.xpath('a/text()').extract()[0]
            # note -- you had 'MianPageUrl' as your scrapy field name. I would recommend fixing this typo
            # (you will need to change it in items.py as well)
            item['MainPageUrl']= "http://imdb.com"+sel.xpath('a/@href').extract()[0]
            request = scrapy.Request(item['MainPageUrl'], callback=self.parseMovieDetails)
            request.meta['item'] = item
            yield request
    # make sure that the dynamically generated start_urls are parsed as well
    parse_start_url = parse_page

    # do your magic
    def parseMovieDetails(self, response):
        pass

【讨论】:

  • 我懒得写出来+1 :)
  • 谢谢!但实际上当我运行“scrapy crawl imdb -a start=1950 -a end=1980”时,它会显示“NameError: name 'start' is not defined”。我错过了什么吗?
  • @Chiefscreation 嗯......如果你在没有任何参数的情况下运行它会发生什么,scrapy crawl imdb?它是从 1874 年开始的吗?
  • @Chiefscreation,为了确保我们没有遗漏任何内容,您使用的是最新版本的 Scrapy 吗?
  • @GregSadetsky 如果我运行“scrapy crawl imdb”,它会说“self”未定义。我两周前下载了 Scrapy,所以我认为它是最新的......
【解决方案3】:
您可以使用下面的代码来关注下一页
#'a.lister-page-next.next-page::attr(href)' 是获取下一页链接的选择器

next_page = response.css('a.lister-page-next.nextpage::attr(href)').extract_first() # joins current and next page url
if next_page is not None:
           next_page = response.urljoin(next_page)
           yield scrapy.Request(next_page, callback=self.parse) # calls parse function again when crawled to next page

【讨论】:

    【解决方案4】:

    @Greg Sadetsky 提供的代码需要一些小的改动。那么只有一个变化是在 parse_page 方法的第一行。

        Just change xpath in the for loop from:
        response.xpath("//*[@class='results']/tr/td[3]"):
        to
        response.xpath("//*[contains(@class,'lister-item-content')]/h3"):
    

    这对我来说就像一个魅力!

    【讨论】:

      猜你喜欢
      • 2015-02-10
      • 2013-04-12
      • 2021-07-29
      • 1970-01-01
      • 2012-11-22
      • 2017-01-01
      • 2019-05-21
      • 2022-08-14
      • 2015-08-13
      相关资源
      最近更新 更多