返回介绍

7.2 基本设置

发布于 2024-01-30 22:48:37 字数 11930 浏览 0 评论 0 收藏 0

Scrapy包含非常多的设置,因此为其分类成为了一个迫切的需求。我们将会从图7.1中总结出的大部分基本设置开始讨论。通过它们了解重要的系统特性,并且我们还将频繁地调整它们。

图7.1 Scrapy基本设置

7.2.1 分析

使用这些设置,你可以配置Scrapy,使其通过日志、统计和Telnet工具提供性能和调试信息。

1.日志

Scrapy基于严重程度,拥有不同的日志等级:DEBUG(最低等级)、INFO、WARNING、ERROR及CRITICAL(最高等级)。除此之外,还有一个SILENT等级,使用它将不记录任何日志。通过将LOG_LEVEL设置为希望日志记录的最低级别,可以限制日志文件只接受指定等级以上的日志。我们一般将该值设为INFO,因为DEBUG级别过于详细。一个非常有用的Scrapy扩展是Log Stats扩展,该扩展会打印出每分钟抓取的item和页面的数量。日志频率使用LOGSTATS_INTERVAL进行设置,其默认值为60秒。该设置的频率过低,所以在我开发时,会将该值设置为5秒,因为大多数运行都很短暂。写入日志的文件可以通过LOG_FILE设置。除非将LOG_ENABLED的值设置为False进行显式禁用,否则日志将会输出到标准错误当中。最后,可以通过设置LOG_STDOUT为True,告知Scrapy将所有标准输出(比如:"print"消息)写入日志。

2.统计

STATS_DUMP默认是开启的,它会在爬虫结束运行时,将统计信息收集器中的值转存到日志当中。可以通过将DOWNLOADER_STATS设置为False,控制是否为下载记录统计信息。还可以通过DEPTH_STATS设置,控制是否收集站点深度的统计信息。要想了解有关深度的更多细节,可以将DEPTH_STATS_VERBOSE设为True。STATSMAILER_RCPTS是一个邮件列表(比如设置为['my@mail.com']),当爬取完成时,会向该列表中的邮箱发送邮件。无需经常调整这些设置,不过它们偶尔会在调试时帮助到你。

3.Telnet

Scrapy包含一个内置的Telnet控制台,可以为你提供正在运行中的Scrapy进程的Python shell。TELNETCONSOLE_ENABLED默认情况下是开启的,而TELNETCONSOLE_PORT决定了连接到控制台的端口。你可能需要修改该值,以防止端口冲突。

示例1——使用Telnet

在某些情况下,需要查看正在运行的Scrapy的内部状态。下面让我们看看如何使用Telnet控制台完成该操作。

本章代码位于ch07目录中。其中,本示例在ch07/properties目录中。

$ pwd
/root/book/ch07/properties
$ ls
properties scrapy.cfg

使用如下命令开始爬取。

$ scrapy crawl fast
...
[scrapy] DEBUG: Telnet console listening on 127.0.0.1:6023:6023

上面的消息意味着Telnet已经被激活,并且使用6023端口进行监听。现在,可以在另一个终端中,使用telnet命令连接它。

$ telnet localhost 6023
>>>

此时,该控制台会提供一个Scrapy内部的Python控制台。你可以查看某些组件,比如使用engine变量查看引擎,不过为了能够更快地了解状态概况,可以使用est()命令。

>>> est()
Execution engine status

time()-engine.start_time      : 5.73892092705
engine.has_capacity()        : False
len(engine.downloader.active)    : 8
...
len(engine.slot.inprogress)     : 10
...
len(engine.scraper.slot.active)   : 2

第10章将会探讨其中的一些度量标准。此时将发现你依然是在Scrapy引擎内部运行它。假设使用了如下命令:

>>> import time
>>> time.sleep(1) # Don't do this!

此时,你会发现在另一个终端中会出现短暂的暂停。显然,该控制台不是用来计算Pi值前100万位的合适地点。你可以在该控制台中操作的事情还包括暂停、继续和终止爬取。你可能会发现,在远程机器操作Scrapy会话时,这些事情和终端通常都很有用。

>>> engine.pause()
>>> engine.unpause()
>>> engine.stop()
Connection closed by foreign host.

7.2.2 性能

第10章将会详细介绍关于性能的设置,这里仅作为一个小结。性能设置可以让我们根据特定的工作负载调整Scrapy的性能特性。CONCURRENT_REQUESTS用于设置同时执行的最大请求数。大多数情况下,该设置用于防止在爬取不同网站(域名/IP)时超出服务器出站容量。除此之外,还可以找到更加严格的CONCURRENT_REQUESTS_PER_DOMAIN以及CONCURRENT_REQUESTS_PER_IP。这两个设置分别通过限制同时对每个域名或 IP地址发出的请求数,达到保护远程服务器的效果。当CONCURRENT_REQUESTS_PER_IP为非零值时,CONCURRENT_REQUESTS_PER_DOMAIN就会被忽略。这些设置不是以秒为单位的。如果CONCURRENT_REQUESTS = 16,而请求平均花费1/4秒的话,你的限制就是每秒16/0.25 = 64个请求。CONCURRENT_ITEMS用于设置对每个响应同时处理的最大item数量。你可能会发现该设置并没有它看起来那么实用,因为很多情况下,每个页面或请求中只有一个Item。并且,其默认值100也比较随意。如果减小该值,比如减小到10或者1,你甚至可能会看到性能提升,这取决于每个请求的Item数量,以及管道的复杂程度。还需要注意的是,由于该值是每个请求时的数量,如果限制了CONCURRENT_REQUESTS = 16、CONCURRENT_ITEMS = 100,那么可能意味着会有1600个item同时在尝试写入数据库。一般来说,建议将该值设置得更保守一些。

对于下载,DOWNLOAD_TIMEOUT决定了下载器在取消一个请求之前需要等待的时间,其默认值为180秒,这似乎有些偏高(当并发请求数为16时,这意味着站点下载的速度大约为5页/分钟)。建议降低该值,比如当存在超时问题时,将其降低为10秒。默认情况下,Scrapy将两次下载间的延迟设置为0,以最大化抓取速度。可以使用DOWNLOAD_DELAY设置将其修改为更加保守的下载速度。有些网站会将请求频率作为“机器人”行为的测量指标。通过设置DOWNLOAD_DELAY,还会在下载延迟中启用一个±50%的随机偏移量。可以通过将RANDOMIZE_DOWNLOAD_DELAY设置为False来禁用该功能。

最后,为了更快的DNS查找,Scrapy默认使用了DNSCACHE_ENABLED设置,启用了内存中的DNS缓存。

7.2.3 提前终止爬取

Scrapy的CloseSpider扩展可以在达成某个条件时,自动终止爬虫爬取。可以分别使用CLOSESPIDER_TIMEOUT(以秒计)、CLOSESPIDER_ITEMCOUNT、CLOSESPIDER_PAGECOUNT以及CLOSESPIDER_ERRORCOUNT这些设置,配置在一段时间后、抓取一定数量item后、接收到一定数量响应后或是遇到一定数量错误后,关闭爬虫。通常情况下,你会在运行爬虫时使用命令行的方式设置这些内容,我们已经在前面的几章中做过几次此类操作。

$ scrapy crawl fast -s CLOSESPIDER_ITEMCOUNT=10
$ scrapy crawl fast -s CLOSESPIDER_PAGECOUNT=10
$ scrapy crawl fast -s CLOSESPIDER_TIMEOUT=10

7.2.4 HTTP缓存和离线运行

Scrapy的HttpCacheMiddleware组件(默认未激活)为HTTP请求和响应提供了一个低级的缓存。当启用该组件时,缓存会存储每个请求及其对应的响应。通过将HTTPCACHE_POLICY设置为scrapy.contrib.httpcache.RFC2616Policy,可以启用一个遵从RFC2616的更复杂的缓存策略。为了启用该缓存,还需要将HTTPCACHE_ENABLED设置为True,并将HTTPCACHE_DIR设置为文件系统中的一个目录(使用相对路径将会在项目的数据文件夹下创建一个目录)。

还可以选择通过设置存储后端类HTTPCACHE_STORAGE为scrapy.contrib.httpcache.DbmCacheStorage,为缓存文件指定数据库后端,并且还可以选择调整HTTPCACHE_DBM_MODULE设置(默认为任意数据库管理系统)。还有一些设置可以用于缓存行为调优,不过默认值已经能够为你很好地服务了。

示例2——使用缓存的离线运行

假设你运行了如下代码:

$ scrapy crawl fast -s LOG_LEVEL=INFO -s CLOSESPIDER_ITEMCOUNT=5000

你会发现大约一分钟后运行可以完成。如果此时无法访问Web服务器,可能就无法爬取任何数据。假设你现在使用如下代码,再次运行爬虫。

$ scrapy crawl fast -s LOG_LEVEL=INFO -s CLOSESPIDER_ITEMCOUNT=5000 -s 
HTTPCACHE_ENABLED=1
...
INFO: Enabled downloader middlewares:...*HttpCacheMiddleware*

你会注意到此时启用了HttpCacheMiddleware,当查看当前目录下的隐藏目录时,将会发现一个新的.scrapy目录,目录结构如下所示。

$ tree .scrapy | head
.scrapy
└── httpcache
   └── easy
      ├── 00
      │  ├── 002054968919f13763a7292c1907caf06d5a4810
      │  │  ├── meta
      │  │  ├── pickled_meta
      │  │  ├── request_body
      │  │  ├── request_headers
      │  │  ├── response_body
...

现在,如果重新运行爬虫,获取略少于前面数量的item时,就会发现即使在无法访问Web服务器的情况下,也能完成得更加迅速。

$ scrapy crawl fast -s LOG_LEVEL=INFO -s CLOSESPIDER_ITEMCOUNT=4500 -s 
HTTPCACHE_ENABLED=1

我们使用了略少于前面数量的item作为限制,是因为当使用CLOSESPIDER_ITEMCOUNT结束时,一般会在爬虫完全结束前读取更多的页面,但我们不希望命中的页面不在缓存范围内。要想清理缓存,只需删除缓存目录即可。

$ rm -rf .scrapy

7.2.5 爬取风格

Scrapy允许我们调整选择优先爬取页面的方式。可以在DEPTH_LIMIT设置中设定最大深度,该值为0时表示不限制。通过DEPTH_PRIORITY设置,可以基于请求的深度指定优先级。最值得注意的是,可以将该值设置为正数,以执行广度优先爬取,并将任务队列由LIFO(后入先出)转为FIFO(先入先出):

DEPTH_PRIORITY = 1
SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.FifoMemoryQueue'

在爬取时进行这些设置非常有用,比如,在一个新闻门户网站中,最近的新闻更应该接近首页,并且每个新闻页都有到其他相关新闻的链接。Scrapy的默认行为是对首页的前几个新闻报道进行尽可能深地爬取,之后才会继续爬取接下来的头版新闻。而广度优先的顺序则是首先爬取最顶层的新闻,之后才会进一步深入,当结合DEPTH_LIMIT设置时,比如设为3,可以让你快速浏览门户网站中最近的新闻。

网站在其根目录下使用Web标准的robots.txt文件,声明它们允许的爬取策略,以及不希望被访问的网站结构。如果将ROBOTSTXT_OBEY设置为True,Scrapy将会遵守该约定。如果启用了该设置,请在调试时记住该点,以防发现任何意外的行为。

CookiesMiddleware显然包含了和cookie相关的所有操作,其中包括会话跟踪、准许登录等。如果你想拥有更“私密”的爬取,可以通过将COOKIES_ENABLED设置False以禁用。禁用cookie还会轻微降低你使用的带宽,并且可能会对你的爬取操作有一点提速,当然它会依赖于你爬取的网站。与CookiesMiddleware类似,REFERER_ENABLED的默认设置是True,即启用了用于填充Referer头的RefererMiddleware。可以使用DEFAULT_REQUEST_HEADERS自定义头部。你可能会发现该设置对于某些奇怪的网站很有用,在这些网站中只有包含了特定请求头的请求才不会被禁止。最后,自动生成的settings.py文件推荐我们设置USER_AGENT。该设置的默认值是Scrapy的版本,而我们需要将其修改为能够让网站拥有者联系到我们的信息。

7.2.6 feed

feed可以让你将Scrapy抓取得到的数据输出到本地文件系统或远程服务器当中。FEED_URI.FEED_URI决定了feed的位置,该设置中可能会包含命名参数。比如,scrapy fast -o "%(name)s_%(time)s.jl"将会自动以当前时间和爬虫名称(fast)填充输出文件名。如果需要使用一个自定义参数,比如%(foo)s,那么feed输出器需要你在爬虫中提供foo属性。此外,feed的存储,如S3、FTP或本地文件系统,也定义在URI中。例如,FEED_URI='s3://mybucket/file.json'将使用你的Amazon凭证(AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY)上传文件到Amazon的S3当中。Feed的格式(JSON、JSON Line、CSV及XML)可以使用FEED_FORMAT确定。如果没有设定该设置,Scrapy将会根据FEED_URI的扩展名猜测格式。通过将FEED_STORE_EMPTY设置为True,可以选择输出空的feed。此外,还可以使用FEED_EXPORT_FIELDS设置,选择只输出指定的几个字段。该设置对于具有固定标题列的.csv文件尤其有用。最后,FEED_URI_PARAMS用于定义对FEED_URI中任意参数进行后置处理的函数。

7.2.7 媒体下载

Scrapy可以使用图像管道下载媒体内容,此外还可以将图像转换为不同的格式、生成缩略图以及基于大小过滤图像。

IMAGES_STORE设置用于设定图像存储的目录(使用相对路径时,将会在项目根目录下创建目录)。每个Item的图像URL应该在image_urls字段中设定(可以被IMAGES_URLS_FIELD设置覆写),而下载图像的文件名则是在一个新的images字段中设定(可以被IMAGES_RESULT_FIELD设置覆写)。可以使用IMAGES_MIN_WIDTH和IMAGES_MIN_HEIGHT设置过滤过小的图像。IMAGES_EXPIRES决定了图像在过期前保留在缓存中的天数。对于缩略图的生成,可以使用IMAGES_THUMBS设置,它可以让你按照一种或多种尺寸生成缩略图。比如,可以让Scrapy生成一种图标大小的缩略图以及一种用于每次图像下载时的中等大小缩略图。

1.其他媒体

可以使用文件管道下载其他媒体文件。与图像类似,FILES_STORE设置用于确定已下载文件的存放位置,而FILES_EXPIRES设置用于确定文件保留的天数。FILES_URLS_FIELD以及FILES_RESULT_FIELD设置都和对应的IMAGES_*设置的功能相似。文件管道和图像管道可以同时激活,不会产生冲突。

示例3——下载图像

为了能够使用图像功能,必须使用sudo pip install image安装图像包。在我们的开发机中,已经为大家安装好该三方包了。想要启用图像管道,只需要编辑项目的settings.py文件,添加少量设置。首先,需要在ITEM_PIPELINES中包含scrapy.pipelines.images.ImagesPipeline。然后,设置IMAGES_STORE为相对路径"images",此外还可以选择通过IMAGES_THUMBS设置一些缩略图的描述,相关代码如下所示。

ITEM_PIPELINES = {
...
  'scrapy.pipelines.images.ImagesPipeline': 1,
}
IMAGES_STORE = 'images'
IMAGES_THUMBS = { 'small': (30, 30) }

我们在Item中已经包含了合适的image_urls字段,所以现在可以参照如下命令执行爬虫了。

$ scrapy crawl fast -s CLOSESPIDER_ITEMCOUNT=90
...
DEBUG: Scraped from <200 http://http://web:9312/.../index_00003.html/
property_000001.html>{
  'image_urls': [u'http://web:9312/images/i02.jpg'],
  'images': [{'checksum': 'c5b29f4b223218e5b5beece79fe31510',
        'path': 'full/705a3112e67...a1f.jpg',
        'url': 'http://web:9312/images/i02.jpg'}],
...
$ tree images
images
├── full
│  ├── 0abf072604df23b3be3ac51c9509999fa92ea311.jpg
│  ├── 1520131b5cc5f656bc683ddf5eab9b63e12c45b2.jpg
...
└── thumbs
   └── small
      ├── 0abf072604df23b3be3ac51c9509999fa92ea311.jpg
      ├── 1520131b5cc5f656bc683ddf5eab9b63e12c45b2.jpg
...

可以看到图像成功下载,并且创建了缩略图。主文件的JPG名称按照预期存储在了images字段当中,因此很容易推测缩略图的路径。如果想要清空图像,我们可以使用rm -rf images。

7.2.8 Amazon Web服务

Scrapy对访问Amazon Web服务有内置支持。你可以在AWSACCESS KEY_ID设置中存储AWS访问密钥,在AWS_SECRET_ACCESS_KEY设置中存储私密密钥。默认情况下,这些设置均为空。可以在如下场景中使用:

· 当下载以s3://开头的URL时(而不是https://等);

· 当通过媒体管道使用s3://路径存储文件或缩略图时;

· 当在s3://目录中存储Item的输出Feed时。

不要将这些设置存储在settings.py文件当中,以防未来某天由于任何原因造成代码公开时被泄露。

7.2.9 使用代理和爬虫

Scrapy的HttpProxyMiddleware组件允许你使用代理设置,根据UNIX约定,这些设置是通过http_proxy、https_proxy以及no_proxy这几个环境变量定义的。该组件默认是启用状态的。

示例4——使用代理和Crawlera的智能代理

DynDNS(或任何类似的服务)提供了一个免费的在线工具,用于查看当前的IP地址。使用Scrapy shell,我们向checkip.dyndns.org发送请求,查看响应,获取当前的IP地址。

$ scrapy shell http://checkip.dyndns.org
>>> response.body
'<html><head><title>Current IP Check</title></head><body>Current IP 
Address: xxx.xxx.xxx.xxx</body></html>\r\n'
>>> exit( )

想要开始代理请求,需要退出shell,并使用export命令设置新的代理。可以通过搜索HMA的公开代理列表测试免费代理(http://proxylist. hidemyass.com)。比如,我们从该列表中选择了一个IP为10.10.1.1、端口为80的代理(非真实存在的代理,请将其替换为你自己的代理地址),可以按照如下操作。

$ # First check if you already use a proxy
$ env | grep http_proxy
$ # We should have nothing. Now let's set a proxy
$ export http_proxy=http://10.10.1.1:80

按照刚才的步骤重新运行scrapy shell,可以看到执行的请求使用了不同的IP。此外,你还会发现这些代理通常速度都很慢,而且在一些情况下无法成功,如果遇到这类情况,可以尝试更换为其他的代理。如果想要禁用代理,则需要退出Scrapy shell,并执行unset http_proxy(或恢复为之前的值)。

Crawlera是Scrapinghub的一项服务,可以为Scrapy的开发者提供一个非常智能的代理。除了在后台使用很大的IP池路由你的请求外,该代理还会调整延迟和失败重试,让你在保持尽可能快的情况下,获得尽可能多且稳定的成功响应流。它基本上可以使爬虫开发者的梦想成真,并且只需像之前那样,设置http_proxy环境变量,就可以使用。

$ export http_proxy=myusername:mypassword@proxy.crawlera.com:8010

除了HTTP代理外,Crawlera还可以通过Scrapy的中间件组件方式使用。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文