【问题标题】:WebScraping User Reviews using Scrapy Not Going to 'Next' page使用 Scrapy 抓取用户评论不会转到“下一页”页面
【发布时间】:2021-02-02 17:05:59
【问题描述】:

我能够刮掉烂番茄“所有观众”对这部电影的第一页评论:https://www.rottentomatoes.com/m/ghostbusters/reviews?type=user

我现在的问题是,与加载更多评论的“所有评论家”评论不同,在“所有观众”中,您单击“下一步”而不是单击“下一页”,例如添加到 URL page=2。现在我不能这样做,我需要弄清楚如何单击“下一步”并获取新链接。

我想知道是否需要使用 selenium 并制作一个 web 驱动程序来完成这项任务。

我是使用开发者工具的新手,并且无法找到正确的名称来引用“下一步”按钮。下面是我成功拉取第一页的代码(但不是想要的后续连续页面)和网站开发者端的截图供参考。任何见解或建议将不胜感激:

import scrapy

class ReviewsSpider(scrapy.Spider):
    name = 'reviews'
    allowed_domains = ['rottentomatoes.com']

    start_urls = ['https://www.rottentomatoes.com/m/ghostbusters/reviews/?type=user']

    def parse(self, response):

        #Extracting the content using css selectors
        reviews = response.css('.audience-reviews__review::text').extract()

        #Give the extracted content row wise
        for item in zip(reviews):
            #create a dictionary to store the scraped info
            scraped_info = {
                'review' : item[0],
            }

            #yield or give the scraped info to scrapy
            yield scraped_info

        next_page_url = response.xpath('//li[//*[@id="content"]/div/div/nav[3]/button[2]/span]/a/@href').extract_first()
        if next_page_url:
            yield scrapy.Request(next_page_url, callback=self.parse)

Developer Tool End Screenshot #1 Developer Tool End Screenshot #2

【问题讨论】:

    标签: python web-scraping scrapy selenium-chromedriver


    【解决方案1】:

    这里的主要内容是我们在按下“下一步按钮”后发出的请求。我们应该用 SiteID、endCursor 和 startCursor 更新它(我们也可以更新方向)。

    我们可以在页面的源代码中找到所有必要的参数。在“root.RottenTomatoes.context.movi​​eReview”下

    我们可以用正则表达式抓取代码并制作一个python字典来轻松获取所有参数。

    regex = r'root\.RottenTomatoes\.context\.movieReview = (.*?);'
    movie_review_data = re.findall(regex, tomatoes_scripts)[0]
    movie_review_data_dict = json.loads(movie_review_data)
    

    然后我们获取 SiteID、endCursor 和 endCursor

    movie_id = movie_review_data_dict.get('movieId')
    next_page = movie_review_data_dict.get('pageInfo').get('hasNextPage')
    end_cursor = movie_review_data_dict.get('pageInfo').get('endCursor')
    

    我们能够从页面中获取第一个 cmets,并使用我们使用参数构建的特殊 URL 发出下一个请求。响应是一个 JSON 对象,我们将其作为 Python 字典(其中包含我们为下一页更新的参数)。

    之后,我们循环我们的方法并从字典中获取所有必要的字段。我提供了完整的代码,但被告知它可以工作,但它是一个草稿,当然,我们必须使用最好的 Scrapy 实践,如 Items、ItemLoaders,为 generate_review_url 函数创建一个单独的文件等。代码是即时编写的,并且展示主要思想并有效

    import scrapy
    import re
    import json
    
    
    def generate_review_url(movie_id,
                            end_cursor,
                            start_cursor=''):
        return f'https://www.rottentomatoes.com/napi/movie/{movie_id}'\
            f'/reviews/user?direction=next&'\
            f'endCursor={end_cursor}&startCursor={start_cursor}'
    
    
    class ReviewsSpider(scrapy.Spider):
        name = 'reviews'
        allowed_domains = ['rottentomatoes.com']
        start_urls = [
            'https://www.rottentomatoes.com/m/ghostbusters/reviews?type=user'
        ]
    
        def parse(self, response):
            tomatoes_scripts = response.xpath(
                '//script[contains(text(), "function (root)")]/text()'
            ).get()
    
            regex = r'root\.RottenTomatoes\.context\.movieReview = (.*?);'
            movie_review_data = re.findall(regex, tomatoes_scripts)[0]
            movie_review_data_dict = json.loads(movie_review_data)
            movie_id = movie_review_data_dict.get('movieId')
            next_page = movie_review_data_dict.get('pageInfo').get('hasNextPage')
            end_cursor = movie_review_data_dict.get('pageInfo').get('endCursor')
    
            reviews = response.xpath('//ul[@class="audience-reviews"]/li')
            for review in reviews:
                yield {
                    'review': review.xpath(
                        './/p[contains(@class, "audience-reviews__review")]/text()'
                    ).get()
                }
    
            if next_page:
                yield scrapy.Request(
                    url=generate_review_url(movie_id, end_cursor),
                    callback=self.parse_special_response,
                    meta={'movie_id': movie_id}
                )
    
        def parse_special_response(self, response):
            response_dict = json.loads(response.body)
    
            reviews = response_dict.get('reviews')
            for review in reviews:
                yield {
                    'review': review.get('review')
                }
    
            movie_id = response.meta.get('movie_id')
            next_page = response_dict.get('pageInfo').get('hasNextPage')
            end_cursor = response_dict.get('pageInfo').get('endCursor')
            start_cursor = response_dict.get('pageInfo').get('startCursor')
    
            if next_page:
                yield scrapy.Request(
                    url=generate_review_url(movie_id, end_cursor, start_cursor),
                    callback=self.parse_special_response,
                    meta={'movie_id': movie_id}
                )
    

    regEx 的解决方案对我来说看起来有点“脏”,也没有任何异常控制等。欢迎改进 =)

    用户评论中似乎有 25 万多条来自用户的评论。当我收集到 11k 条评论时,我停止了脚本。我也测试了这部电影https://www.rottentomatoes.com/m/pg_psycho_goreman/reviews?type=user 并收集了 46 条所有相关的评论 =)

    【讨论】:

    • 我是个真正的天使
    猜你喜欢
    • 2018-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多