如何用Python Scrapy跟踪链接

1,456 阅读4分钟

How To Follow Links With Python Scrapy

在使用Python Scrapy进行数据提取时跟踪链接是非常直接的。我们需要做的第一件事是找到页面上的导航链接。很多时候,这是一个包含文本 "下一步 "的链接,但它不一定是。然后,我们需要构建一个XPath或CSS选择器查询,以获得我们需要的锚元素的href属性中包含的值。一旦完成,我们就可以使用Scrapy的response.follow()方法来自动导航到网站的其他页面。


查找下一个按钮

这个例子使用的是books.tscrape.com,我们可以看到,在主页上有一个 "下一步 "按钮,可以链接到下一个页面。这一直持续到所有50个页面被显示出来。

next button for responsefollow scrapy

在Scrapy Shell中的测试显示,**response.css('.next a').attrib['href']**给了我们需要的URL值。


实现 response.follow()

现在,为了让我们的Spider能够导航到下一页,我们可以构建下面的代码。第一步是使用*response.css('.next a').attrib['href']*选择器从页面中提取要访问的URL,并将该结果存储在next_page变量中。

一旦完成,我们使用if语句来确保next_page是一个有效的URL。如果它是有效的,那么我们就会产生一个对response.follow()的调用,像这样。

response.follow(next_page, callback=self.parse)

请注意,在这个Spider类中,有一个回调函数是指向parse()方法的。这告诉Scrapy继续搜刮当前页面,当你完成后--点击链接访问下一个页面,然后再次运行parse()方法来搜刮新的页面。这个过程一直持续到不再有一个从当前页面提取的有效URL为止。换句话说,最后一个页面不会有一个文本为 "Next "的锚标签指向一个新的页面。此时,*response.css('.next a').attrib['href']*实际上将是空的,或者说是无,因此response.follow()方法将不会被调用,Spider将停止。

import scrapy


class BooksSpider(scrapy.Spider):
    name = 'books'
    allowed_domains = ['books.toscrape.com']
    start_urls = ['http://books.toscrape.com/']

    def parse(self, response):
        for book in response.xpath('//article'):
            yield {
                'booktitle': book.xpath('.//a/text()').get(),
                'bookrating': book.xpath('.//p').attrib['class'],
                'bookprice': book.xpath('.//div[2]/p/text()').get(),
                'bookavailability': book.xpath('.//div[2]/p[2]/i/following-sibling::text()').get().strip()
            }

        next_page = response.css('.next a').attrib['href']
        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)

运行Spider

对我们的Scrapy项目所做的这个小改动,现在已经有了一个递归跟踪链接的方法,直到所有的页面都被抓取。我们可以运行蜘蛛,并将其输出到一个JSON文件。

bookstoscrape $scrapy crawl books -o books.json 

在蜘蛛的输出中,我们现在可以看到一些令人印象深刻的统计数字。蜘蛛显示,现在有1000个项目在大约12秒内被搜刮完毕。这就是整个网站,而我们只添加了几行代码

{'downloader/request_bytes': 15059,
 'downloader/request_count': 51,
 'downloader/request_method_count/GET': 51,
 'downloader/response_bytes': 291875,
 'downloader/response_count': 51,
 'downloader/response_status_count/200': 50,
 'downloader/response_status_count/404': 1,
'elapsed_time_seconds': 12.535962,
 'finish_reason': 'finished',
'item_scraped_count': 1000,
 'log_count/DEBUG': 1051,
 'log_count/ERROR': 1,
 'log_count/INFO': 11,
 'request_depth_max': 49,
 'response_received_count': 51,
 'robotstxt/request_count': 1,
 'robotstxt/response_count': 1,
 'robotstxt/response_status_count/404': 1,
 'scheduler/dequeued': 50,
 'scheduler/dequeued/memory': 50,
 'scheduler/enqueued': 50,
 'scheduler/enqueued/memory': 50,
 'spider_exceptions/KeyError': 1,
}

我们可以检查Scrapy项目中生成的books.json文件,当然,它现在有1000个对象,每个对象都有一个标题、评级、价格和可用性属性。令人印象深刻!

链接扩展器

Scrapy还提供了所谓的链接提取器。这是一个可以从响应中自动提取链接的对象。它们通常用于Crawl Spiders,尽管它们也可以用于普通的Spiders,比如本文介绍的那个。语法不同,但可以达到同样的效果。上面的链接跟踪代码是用链接提取器改写的,结果是一样的。

import scrapy
from scrapy.linkextractors import LinkExtractor


class BooksSpider(scrapy.Spider):
    name = 'books'
    allowed_domains = ['books.toscrape.com']
    start_urls = ['http://books.toscrape.com/']

    def parse(self, response):
        for book in response.xpath('//article'):
            yield {
                'booktitle': book.xpath('.//a/text()').get(),
                'bookrating': book.xpath('.//p').attrib['class'],
                'bookprice': book.xpath('.//div[2]/p/text()').get(),
                'bookavailability': book.xpath('.//div[2]/p[2]/i/following-sibling::text()').get().strip()
            }

        next_page = LinkExtractor(restrict_css='.next a').extract_links(response)[0]
        if next_page.url is not None:
            yield response.follow(next_page, callback=self.parse)

如何限制被跟踪链接的数量

当这种类型的递归程序运行时,它将一直运行下去,直到满足停止条件。你可能不希望在一个非常大的网站上出现这种情况。在这种情况下,你需要一种方法来阻止蜘蛛抓取新的链接,有几种方法可以做到这一点。

CLOSESPIDER_PAGECOUNT
一种方法是在settings.py中添加一个配置值,将CLOSESPIDER_PAGECOUNT设置为25。

# Scrapy settings for bookstoscrape project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
#     https://docs.scrapy.org/en/latest/topics/settings.html
#     https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
#     https://docs.scrapy.org/en/latest/topics/spider-middleware.html

BOT_NAME = 'bookstoscrape'

SPIDER_MODULES = ['bookstoscrape.spiders']
NEWSPIDER_MODULE = 'bookstoscrape.spiders'

CLOSESPIDER_PAGECOUNT = 25

现在,当我们运行蜘蛛时,它在搜刮了25个页面后就会停止运行。你也可以通过设置要搜刮的项目数量来做同样的事情。例如,如果你设置CLOSESPIDER_ITEMCOUNT = 100,那么在检索完100个项目后,爬行会自动停止。在处理大型数据集时,请记住settings.py文件中的这两个配置值。

如何用Python Scrapy跟踪链接摘要

在Python Scrapy中还有几种跟踪链接的方法,但response.follow()方法可能是最容易使用的,特别是在第一次使用Scrapy时。跟踪链接的其他选择是urljoin()方法和LinkExtractor对象。