我已经开始学习Scrapy,并尝试废弃LetterBoxd我无法集成Splash和Scrapy如何刮掉前2000页?

问题描述

import scrapy
from scrapy_splash import SplashRequest
 
class Test4basicSpider(scrapy.Spider):
    name = 'test4Basic'
    allowed_domains = ['letterBoxd.com']
    start_urls = ['https://letterBoxd.com/films/popular/size/small/page/1/']
    # start_urls = ['https://letterBoxd.com/film/tales-from-the-darkside-the-movie/']
 
    script1 = '''
    function main(splash,args)
        splash.private_mode_enabled = false
        url = args.url
        assert(splash:go(args.url))
        assert(splash:wait(0.5))
        return {
            html = splash:html()
        }
    end
    '''
 
    def start_requests(self):
        yield SplashRequest(url='https://letterBoxd.com/films/popular/size/small/page/1/',callback=self.parse,endpoint="execute",args={
            'lua_source': self.script1
        })
 
    def parse(self,response):
        for movie in response.xpath("//li[@class='listitem poster-container']"):
            movie_url = movie.xpath("(//a[@class='frame'])[1]/@href").get()
            yield scrapy.Request(
                url=f'https://letterBoxd.com{movie_url}',callback=self.parse_movie,)
 
        next_page = response.xpath("//a[@class='next']/@href").get()
        if next_page:
            yield SplashRequest(
                url=f'https://letterBoxd.com{next_page}',endpoint='execute',args={
                    'lua_source': self.script1
                },callback=self.parse
            )
 
    def parse_movie(self,response):
 
        yield {
            'title': response.xpath('//section[@id="featured-film-header"]/h1/text()').get(),'year': response.xpath('//small[@class="number"]/a/text()').get(),'duration': response.xpath('(//p[@class="text-link text-footer"]/text())[1]').get(),'genre': response.xpath('//div[@class="text-sluglist capitalize"]/p/a/text()').getall(),'rating': response.xpath('//a[contains(@class,"tooltip display-rating")]/text()').get(),'language': response.xpath('((//span[contains(text(),"Language")]/parent::node()/following::node())/p/a/text())[1]').get()
        }

如果我直接从任何电影URL进行刮除,我就能成功地刮除除ratings(需要Javascript)之外的所有字段。我也尝试对分页应用一些逻辑,但是当我尝试爬网时却一无所获。该代码在哪里出错? LetterBoxd的robots.txt文件可以禁止它吗,我不知道如何。

解决方法

关于下一页的问题。听起来好像需要下一页链接的启动请求。您应该考虑如何继续请求下一页链接,直到没有链接为止。

为您提供一些帮助。无需使用飞溅来获得评分。

如果您查看浏览器在检查页面时发出的请求。您已经看到有一个AJAX请求,其中包含与该评分相对应的一些HTML,正如您所建议的那样,它是由javascript加载的。

enter image description here

我倾向于复制此请求并将其粘贴到curl.trillworks.com中。将cURL命令转换为python。然后,您可以处理请求,看看是否可以在没有任何标题的情况下抓住它……

enter image description here 实际上,您甚至不需要标题/参数/ cookie来发出请求。要获取评级信息,您可以向https://letterboxd.com/csi/film/joker-2019/rating-histogram/

发送一个简单的HTTP get请求

代码示例

start_url = ['https://letterboxd.com/csi/film/joker-2019/rating-histogram/']
def parse(self,response):
    rating = response.xpath('//a[@class="tooltip display-rating"]/text()').get()

输出

3.8

对于任何电影链接,请将joker-2019替换为指定特定电影页面链接的URL的相应​​部分。

根据评论更新

您实际上几乎已经掌握了这个。您已经为下一页正确编写了代码。我认为您每个链接的XPATH选择器都有些许错误。

更新代码

for movie in response.xpath("//li[@class='listitem poster-container']"):
            movie_url = movie.xpath(".//a[@class='frame']/@href").get()
            print(movie_url)
            yield scrapy.Request(
                url=f'https://letterboxd.com{movie_url}',callback=self.parse_movie,dont_filter=True
            )

更正

  1. 请注意,它应该是.//而不是//.//搜索每个response.xpath("//li[@class='listitem poster-container']")列表项的相对路径。简单的错误,我们都错过了。

  2. 我不太了解XPATH选择器

    '(//a[@class='frame'])[1]/@href'

    我已将其更改为有效的'//a[@class='frame']/@href'

  3. 它正在过滤所有请求,因为它具有相同的基本URL letterboxd.com,因此在scrapy.Request中,必须确保dont_filter=True处理所有请求。 / p>

更新2:将Rating纳入代码

请参阅答案的主体,但这是实现。我们创建链接的部分内容,我们需要将其提供给提供评级的直方图URL。然后,我们调用一个回调来获取该评分,然后将该变量通过rating方法传递给parse_movie方法。

def parse(self,response):
        
    for movie in response.xpath("//li[@class='listitem poster-container']"):
        movie_url = movie.xpath(".//a[@class='frame']/@href").get()
        partial = movie_url.split('/')[-2]

        yield scrapy.Request(
            url=f'https://letterboxd.com{movie_url}',dont_filter=True
            )

        rating_url = f'https://letterboxd.com/csi/film/{partial}/rating-histogram/'
        yield scrapy.Request(url=rating_url,callback=self.rating)
        
        next_page = response.xpath("//a[@class='next']/@href").get()
        if next_page:
            yield SplashRequest(
                url=f'https://letterboxd.com{next_page}',endpoint='execute',args={
                    'lua_source': self.script1
                },callback=self.parse
            )

def rating(self,response):
    self.rating = response.xpath('//a[@class="tooltip display-rating"]/text()').get()

def parse_movie(self,response):
 
    yield {
            'title': response.xpath('//section[@id="featured-film-header"]/h1/text()').get(),'year': response.xpath('//small[@class="number"]/a/text()').get(),'duration': response.xpath('(//p[@class="text-link text-footer"]/text())[1]').get(),'genre': response.xpath('//div[@class="text-sluglist capitalize"]/p/a/text()').getall(),'rating': self.rating,'language': response.xpath('((//span[contains(text(),"Language")]/parent::node()/following::node())/p/a/text())[1]').get()
        }

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...