scrapy 2.3 数据抓取实例

2021-06-02 11:18 更新

既然您知道了如何从页面中提取数据,那么让我们看看如何从页面中跟踪链接。

第一件事是提取到我们要跟踪的页面的链接。检查我们的页面,我们可以看到有一个链接指向下一个带有以下标记的页面:

<ul class="pager">
    <li class="next">
        <a href="/page/2/">Next <span aria-hidden="true">&rarr;</span></a>
    </li>
</ul>

我们可以尝试在外壳中提取:

>>> response.css('li.next a').get()
'<a href="/page/2/">Next <span aria-hidden="true">→</span></a>'

这将获取anchor元素,但我们需要该属性 ​href​ . 为此,Scrapy支持CSS扩展,允许您选择属性内容,如下所示:

>>> response.css('li.next a::attr(href)').get()
'/page/2/'

还有一个 ​attrib​ 可用属性(请参见 选择元素属性 更多信息):

>>> response.css('li.next a').attrib['href']
'/page/2/'

现在让我们看看我们的spider被修改为递归地跟踪下一页的链接,从中提取数据:

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('small.author::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.parse)

现在,在提取数据之后, ​parse()​ 方法查找到下一页的链接,并使用 ​urljoin()​ 方法(因为链接可以是相对的),并生成对下一页的新请求,将自身注册为回调,以处理下一页的数据提取,并保持爬行在所有页中进行。

这里您看到的是scrapy的以下链接机制:当您在回调方法中生成一个请求时,scrapy将计划发送该请求,并注册一个回调方法,以便在该请求完成时执行。

使用它,您可以构建复杂的爬虫程序,这些爬虫程序根据您定义的规则跟踪链接,并根据所访问的页面提取不同类型的数据。

在我们的示例中,它创建了一种循环,跟踪到下一页的所有链接,直到找不到一个为止——这对于爬行博客、论坛和其他带有分页的站点很方便。

创建请求的快捷方式

作为创建请求对象的快捷方式,您可以使用 ​response.follow​ ::

import scrapy


class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').get(),
                'author': quote.css('span small::text').get(),
                'tags': quote.css('div.tags a.tag::text').getall(),
            }

        next_page = response.css('li.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)

不像Scrapy.Request, ​response.follow​ 直接支持相对URL-无需调用URLJOIN。注意 ​response.follow​ 只返回一个请求实例;您仍然需要生成这个请求。

也可以将选择器传递给 ​response.follow​ 而不是字符串;此选择器应提取必要的属性:

for href in response.css('ul.pager a::attr(href)'):
    yield response.follow(href, callback=self.parse)

为了 ​<a>​ 元素有一个快捷方式: ​response.follow​ 自动使用其href属性。因此代码可以进一步缩短:

for a in response.css('ul.pager a'):
    yield response.follow(a, callback=self.parse)

要从iterable创建多个请求,可以使用 ​response.follow_all​ 取而代之的是:

anchors = response.css('ul.pager a')
yield from response.follow_all(anchors, callback=self.parse)

或者,进一步缩短:

yield from response.follow_all(css='ul.pager a', callback=self.parse)

更多示例和模式

下面是另一个spider,它演示回调和以下链接,这次是为了抓取作者信息:

import scrapy


class AuthorSpider(scrapy.Spider):
    name = 'author'

    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response):
        author_page_links = response.css('.author + a')
        yield from response.follow_all(author_page_links, self.parse_author)

        pagination_links = response.css('li.next a')
        yield from response.follow_all(pagination_links, self.parse)

    def parse_author(self, response):
        def extract_with_css(query):
            return response.css(query).get(default='').strip()

        yield {
            'name': extract_with_css('h3.author-title::text'),
            'birthdate': extract_with_css('.author-born-date::text'),
            'bio': extract_with_css('.author-description::text'),
        }

这个蜘蛛将从主页开始,它将跟踪所有指向作者页面的链接,调用 ​parse_author​ 它们的回调,以及与 ​parse​ 像我们以前看到的那样回拨。

这里,我们把回电传递给 ​response.follow_all​ 作为使代码更短的位置参数;它也适用于 ​Request​ .

这个 ​parse_author​ 回调定义了一个助手函数,用于从CSS查询中提取和清理数据,并用作者数据生成python dict。

这个蜘蛛展示的另一个有趣的事情是,即使同一作者引用了很多话,我们也不需要担心多次访问同一作者页面。默认情况下,scrappy过滤掉对已经访问过的URL的重复请求,避免了由于编程错误而太多地访问服务器的问题。这可以通过设置进行配置 ​DUPEFILTER_CLASS​ .

希望到目前为止,您已经很好地了解了如何使用scrappy跟踪链接和回调的机制。

作为另一个利用以下链接机制的蜘蛛示例,请查看 ​CrawlSpider​ 类,该类用于实现一个小规则引擎,您可以使用该引擎在上面编写爬虫程序。

另外,一个常见的模式是使用:ref:`trick将其他数据传递给回调<topics-request-response-ref-request-callback-arguments>`来构建包含来自多个页面的数据的项目。


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号