【问题标题】:Q: Scrapy: Next pages not crawled but crawler seems to be following links问:Scrapy:没有抓取下一页,但爬虫似乎正在跟踪链接
【发布时间】:2016-02-04 13:05:00
【问题描述】:

我正在尝试学习 python 和 scrapy,但我在使用 CrawlSpider 时遇到了问题。 下面的代码对我有用。它获取起始 url 中与 xpath 匹配的所有链接 - //div[@class="info"]/h3/a/@href 然后将这些链接传递给函数 parse_dir_contents

我现在需要的是让爬虫移动到下一页。我尝试使用规则和链接提取器,但似乎无法使其正常工作。我还尝试使用//a/@href 作为 parse 函数的 xpath,但它不会将链接传递给 parse_dir_contents 函数。我想我错过了一些非常简单的东西。有什么想法吗?

class ypSpider(CrawlSpider):
name = "ypTest"
download_delay = 2
allowed_domains = ["yellowpages.com"]
start_urls = ["http://www.yellowpages.com/new-york-ny/restaurants?page=1"]

rules = [
    Rule(LinkExtractor(allow=['restaurants?page=[1-2]']), callback="parse")
]

def parse(self, response):
    for href in response.xpath('//div[@class="info"]/h3/a/@href'):
        url = response.urljoin(href.extract())
        if 'mip' in url:
            yield scrapy.Request(url, callback=self.parse_dir_contents)


def parse_dir_contents(self, response):
    for sel in response.xpath('//div[@id="mip"]'):
        item = ypItem()
        item['url'] = response.url
        item['business'] = sel.xpath('//div/div/h1/text()').extract()
        ---extra items here---
        yield item

编辑: 这是具有三个功能的更新代码,能够抓取 150 个项目。我认为这是我的规则有问题,但我尝试了我认为可行的方法,但输出仍然相同。

class ypSpider(CrawlSpider):
name = "ypTest"
download_delay = 2
allowed_domains = ["yellowpages.com"]
start_urls = ["http://www.yellowpages.com/new-york-ny/restaurants?page=1"]

rules = [
    Rule(LinkExtractor(allow=[r'restaurants\?page\=[1-2]']), callback='parse')
]

def parse(self, response):
    for href in response.xpath('//a/@href'):
        url = response.urljoin(href.extract())
        if 'restaurants?page=' in url:
            yield scrapy.Request(url, callback=self.parse_links)


def parse_links(self, response):
    for href in response.xpath('//div[@class="info"]/h3/a/@href'):
        url = response.urljoin(href.extract())
        if 'mip' in url:
            yield scrapy.Request(url, callback=self.parse_page)


def parse_page(self, response):
    for sel in response.xpath('//div[@id="mip"]'):
        item = ypItem()
        item['url'] = response.url
        item['business'] = sel.xpath('//div/div/h1/text()').extract()
        item['phone'] = sel.xpath('//div/div/section/div/div[2]/p[3]/text()').extract()
        item['street'] = sel.xpath('//div/div/section/div/div[2]/p[1]/text()').re(r'(.+)\,')
        item['city'] = sel.xpath('//div/div/section/div/div[2]/p[2]/text()').re(r'(.+)\,')
        item['state'] = sel.xpath('//div/div/section/div/div[2]/p[2]/text()').re(r'\,\s(.+)\s\d')
        item['zip'] = sel.xpath('//div/div/section/div/div[2]/p[2]/text()').re(r'(\d+)')
        item['category'] = sel.xpath('//dd[@class="categories"]/span/a/text()').extract()
        yield item

【问题讨论】:

    标签: python xpath scrapy web-crawler


    【解决方案1】:

    CrawlSpider 将解析例程用于自己的目的,将您的 parse() 重命名为其他名称,将 rules[] 中的回调更改为匹配并重试。

    【讨论】:

    • 那行不通。但它给了我一个想法,即创建另一个 parse() 函数,该函数将首先获取页面上的所有链接,然后将其传递给原始 parse(),我将其重命名为 parse_links(),然后将其传递给 parse_dir_contents()。希望有效。
    • 好吧,看来它现在正在抓取 150 个项目,而不是大约 30 个。但即使我增加 allow=['restaurants?page=[1-2]'] 以允许更多页面,它不起作用。我也尝试增加深度限制,但输出相同。
    • 至少有进步。你能发布你最新的代码吗?
    • 来自doc.scrapy.org/en/latest/topics/spiders.html#crawling-rules的scrapy文档。你真的不应该有一个 parse() 方法,因为 CrawlSpider 使用它。 When writing crawl spider rules, avoid using parse as callback, since the CrawlSpider uses the parse method itself to implement its logic. So if you override the parse method, the crawl spider will no longer work.
    • @JignoAlfredVenezuela,你说得对,它只抓取 150 个项目,每页 30 个项目。这是因为LinkExtractor 规则根本不起作用。
    【解决方案2】:

    我知道回答这个问题已经很晚了,但我设法解决了它,我发布了我的答案,因为它可能对像我这样对如何使用scrapy RuleLinkExtractor 感到困惑的人有所帮助首先。

    这是我的工作代码:

    # -*- coding: utf-8 -*-
    import scrapy
    from scrapy.spiders import CrawlSpider, Rule
    from scrapy.linkextractors import LinkExtractor
    
    
    class ypSpider(CrawlSpider):
        name = "ypTest"
        allowed_domains = ["yellowpages.com"]
        start_urls = ['http://www.yellowpages.com/new-york-ny/restaurants'
                 ]
        rules = (
            Rule(LinkExtractor(allow=[r'restaurants\?page=\d+']), follow=True), # Scrapes all the pagination links 
            Rule(LinkExtractor(restrict_xpaths="//div[@class='scrollable-pane']//a[@class='business-name']"), callback='parse_item'), # Scrapes all the restaurant detail links and use `parse_item` as a callback method
        )
    
        def parse_item(self, response):
            yield {
                'url' : response.url
            }
    

    所以,我设法了解了 RuleLinkExtractor 在这种情况下的工作原理。

    第一个Rule 条目用于抓取所有分页链接,LinkExtractor 函数中的allow 参数基本上使用regex 仅传递与regex 匹配的链接。在这种情况下,根据regex,只有包含restaurants\?page=\d+ 这样的模式的链接,其中\d+ 表示一个或多个数字。此外,它使用默认的parse 方法作为回调。 (在这种情况下,我可以使用restrict_xpath 参数仅选择那些位于HTML 中特定区域下的链接,而不是allow 参数,但我使用它来了解它如何与regex 一起使用)

    第二个Rule 用于获取所有餐厅详细信息链接并使用parse_item 方法解析这些链接。在这个Rule 中,我们使用restrict_xpaths 参数,它定义了响应中应该从中提取链接的区域。在这里,我们只获取div 下的内容,类为scrollable-pane,并且只获取那些类为business-name 的链接,就像你检查HTML 一样,你会发现不止一个指向同一个餐厅的链接同一div 中的不同查询参数。最后,我们传递了我们的回调方法parse_item

    现在,当我运行这个蜘蛛时,它会获取所有餐厅(纽约州纽约的餐厅)的详细信息,在这种情况下,总共有 3030 个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-30
      • 1970-01-01
      • 2012-01-22
      • 2021-10-09
      • 2011-06-26
      • 1970-01-01
      • 2013-02-07
      相关资源
      最近更新 更多