【问题标题】:How to paginate once number of pages has been scraped? (Scrapy)刮掉页数后如何分页? (刮擦)
【发布时间】:2018-05-22 22:10:39
【问题描述】:

我正在尝试通过没有超链接分页按钮的评论网站进行分页。我已经编写了逻辑来对每个链接的页数进行分页和硬编码。但是,我想知道是否可以将我抓取的信息用作start_requests 中给定链接的页数。

此处的蜘蛛代码(带有 2 个分页链接):

class TareviewsSpider(scrapy.Spider):
    name = 'tareviews'
    allowed_domains = ['tripadvisor.com']
    # start_urls = []

    def start_requests(self):
        for page in range(0,395,5):
            yield self.make_requests_from_url('https://www.tripadvisor.com/Hotel_Review-g60795-d102542-Reviews-or{}-Courtyard_Philadelphia_Airport-Philadelphia_Pennsylvania.html'.format(page))
        for page in range(0,1645,5):
            yield self.make_requests_from_url('https://www.tripadvisor.com/Hotel_Review-g60795-d122332-Reviews-or{}-The_Ritz_Carlton_Philadelphia-Philadelphia_Pennsylvania.html'.format(page))

    def parse(self, response):
        for idx,review in enumerate(response.css('div.review-container')):
            item = {
                'num_reviews': response.css('span.reviews_header_count::text')[0].re(r'\d{0,3}\,?\d{1,3}'),
                'hotel_name': response.css('h1.heading_title::text').extract_first(),
                'review_title': review.css('span.noQuotes::text').extract_first(),
                'review_body': review.css('p.partial_entry::text').extract_first(),
                'review_date': review.xpath('//*[@class="ratingDate relativeDate"]/@title')[idx].extract(),
                'num_reviews_reviewer': review.css('span.badgetext::text').extract_first(),
                'reviewer_name': review.css('span.scrname::text').extract(),
                'bubble_rating': review.xpath("//div[contains(@class, 'reviewItemInline')]//span[contains(@class, 'ui_bubble_rating')]/@class")[idx].re(r'(?<=ui_bubble_rating bubble_).+?(?=0)')
            }
            yield item

'num_reviews' 是每个链接的最后一页编号的值。在for loopstart_requests 中是3951645

这可能吗?如果可能的话,我想避免使用无头浏览器。谢谢!

【问题讨论】:

  • parse() 中,您可以使用yield Request() 和新网址将其添加到列表中。
  • 解析,在本例中为num_reviews,返回最后一页的编号。我不认为yield Request() 在这种情况下会起作用,因为一旦知道总页数,就需要一个循环来执行分页。
  • 如果你知道页数,那么你可以在循环中使用yield Request( url=...)

标签: python web-scraping pagination scrapy


【解决方案1】:

我编写了这段代码

我使用普通网址 - 没有 -or{} - 来获取页面并查找评论数量。
接下来,我将-or{} 添加到 url - 它可以在任何地方 - 生成带有评论的页面的 url。
然后我使用for 循环和Request() 来获取带有评论的页面。
评论通过不同的方法解析 - parse_reviews()

在代码中,我使用scrapy.crawler.CrawlerProcess() 在没有完整项目的情况下运行它,
这样每个人都可以轻松运行和测试它。

它将数据保存在output.csv

import scrapy

class TareviewsSpider(scrapy.Spider):

    name = 'tareviews'
    allowed_domains = ['tripadvisor.com']

    start_urls = [ # without `-or{}`
        'https://www.tripadvisor.com/Hotel_Review-g60795-d102542-Reviews-Courtyard_Philadelphia_Airport-Philadelphia_Pennsylvania.html',
        'https://www.tripadvisor.com/Hotel_Review-g60795-d122332-Reviews-The_Ritz_Carlton_Philadelphia-Philadelphia_Pennsylvania.html',
    ]

    def parse(self, response):
        # get number of reviews
        num_reviews = response.css('span.reviews_header_count::text').extract_first()
        num_reviews = num_reviews[1:-1] # remove `( )`
        num_reviews = num_reviews.replace(',', '') # remove `,`
        num_reviews = int(num_reviews) # convert to integer
        print('num_reviews:', num_reviews, type(num_reviews))

        # create template to generate urls to pages with reviews
        url = response.url.replace('.html', '-or{}.html')
        print('template:', url)

        # add requests to list
        for offset in range(0, num_reviews, 5):
            print('url:', url.format(offset))
            yield scrapy.Request(url=url.format(offset), callback=self.parse_reviews)

    def parse_reviews(self, response):
        print('reviews')
        for idx,review in enumerate(response.css('div.review-container')):
            item = {
                'num_reviews': response.css('span.reviews_header_count::text')[0].re(r'\d{0,3}\,?\d{1,3}'),
                'hotel_name': response.css('h1.heading_title::text').extract_first(),
                'review_title': review.css('span.noQuotes::text').extract_first(),
                'review_body': review.css('p.partial_entry::text').extract_first(),
                'review_date': review.xpath('//*[@class="ratingDate relativeDate"]/@title')[idx].extract(),
                'num_reviews_reviewer': review.css('span.badgetext::text').extract_first(),
                'reviewer_name': review.css('span.scrname::text').extract(),
                'bubble_rating': review.xpath("//div[contains(@class, 'reviewItemInline')]//span[contains(@class, 'ui_bubble_rating')]/@class")[idx].re(r'(?<=ui_bubble_rating bubble_).+?(?=0)')
            }
            yield item


# --- run without project ---

import scrapy.crawler

c = scrapy.crawler.CrawlerProcess({
    "FEED_FORMAT": 'csv',
    "FEED_URI": 'output.csv',
})
c.crawl(TareviewsSpider)
c.start())

顺便说一句: 获取您需要的页面 url

 https://www.tripadvisor.com/g60795-d102542
 https://www.tripadvisor.com/g60795-d102542-or0
 https://www.tripadvisor.com/g60795-d102542-or5

url 中的其他词仅用于SEO - 以在 Google 搜索结果中获得更好的位置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 2014-04-02
    • 2018-04-18
    • 1970-01-01
    • 1970-01-01
    • 2017-08-31
    相关资源
    最近更新 更多