Scrapy - 快速指南


Scrapy - 概述

Scrapy是一个用Python编写的快速、开源的网络爬虫框架,用于借助基于XPath的选择器从网页中提取数据。

Scrapy 于 2008 年 6 月 26 日首次发布,并在 BSD 下获得许可,里程碑 1.0 于 2015 年 6 月发布。

为什么使用 Scrapy?

  • 构建和扩展大型爬行项目更加容易。

  • 它有一个称为选择器的内置机制,用于从网站中提取数据。

  • 它异步处理请求并且速度很快。

  • 它利用自动节流机制自动调节爬行速度。

  • 确保开发人员的可访问性。

Scrapy的特点

  • Scrapy 是一个开源且免费使用的网络爬虫框架。

  • Scrapy 生成 JSON、CSV 和 XML 等格式的 feed 导出。

  • Scrapy 内置支持通过 XPath 或 CSS 表达式从源中选择和提取数据。

  • Scrapy基于爬虫,可以自动从网页中提取数据。

优点

  • Scrapy 易于扩展、快速且功能强大。

  • 它是一个跨平台的应用程序框架(Windows、Linux、Mac OS 和 BSD)。

  • Scrapy 请求是异步调度和处理的。

  • Scrapy 附带了名为Scrapyd 的内置服务,它允许使用 JSON Web 服务上传项目并控制蜘蛛。

  • 废弃任何网站都是可能的,尽管该网站没有用于访问原始数据的 API。

缺点

  • Scrapy 仅适用于 Python 2.7。+

  • 不同操作系统的安装有所不同。

Scrapy - 环境

在本章中,我们将讨论如何安装和设置 Scrapy。Scrapy 必须与 Python 一起安装。

Scrapy 可以使用pip安装。要安装,请运行以下命令 -

pip install Scrapy

Windows

注意- Windows 操作系统不支持 Python 3。

步骤 1 - 从Python安装 Python 2.7

通过将以下路径添加到 PATH 来设置环境变量 -

C:\Python27\;C:\Python27\Scripts\; 

您可以使用以下命令检查 Python 版本 -

python --version

步骤 2 - 安装 OpenSSL

在环境变量中添加 C:\OpenSSL-Win32\bin。

- OpenSSL 预装在除 Windows 之外的所有操作系统中。

步骤 3 - 安装Visual C++ 2008可再发行组件。

步骤 4 - 安装pywin32

步骤 5 -为 2.7.9 之前的 Python 版本安装pip 。

您可以使用以下命令检查 pip 版本 -

pip --version

步骤 6 - 要安装 scrapy,请运行以下命令 -

pip install Scrapy

蟒蛇

如果您的计算机上安装了anacondaminiconda,请运行以下命令使用 conda 安装 Scrapy -

conda install -c scrapinghub scrapy 

Scrapinghub公司支持 Linux、Windows 和 OS X 的官方 conda 软件包。

注意- 如果您在通过 pip 安装时遇到问题,建议使用上述命令安装 Scrapy。

Ubuntu 9.10 或更高版本

Ubuntu 操作系统上预装了最新版本的 Python。使用 Scrapinghub 提供的 Ubuntu 软件包 aptgettable。使用包 -

步骤 1 - 您需要将用于签署 Scrapy 包的 GPG 密钥导入到 APT 密钥环中 -

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 627220E7

步骤 2 - 接下来,使用以下命令创建 /etc/apt/sources.list.d/scrapy.list 文件 -

echo 'deb http://archive.scrapy.org/ubuntu scrapy main' | sudo tee 
/etc/apt/sources.list.d/scrapy.list

步骤 3 - 更新包列表并安装 scrapy -

sudo apt-get update && sudo apt-get install scrapy

ArchLinux

您可以使用以下命令从 AUR Scrapy 包安装 Scrapy -

yaourt -S scrapy

Mac OS X

使用以下命令安装 Xcode 命令行工具 -

xcode-select --install 

不要使用系统 Python,而是安装一个不会与系统其他部分冲突的新更新版本。

步骤 1 - 安装自制程序

步骤 2 - 设置环境 PATH 变量以指定应在系统包之前使用自制程序包 -

echo "export PATH = /usr/local/bin:/usr/local/sbin:$PATH" >> ~/.bashrc

步骤 3 - 要确保更改完成,请使用以下命令重新加载.bashrc -

source ~/.bashrc 

步骤 4 - 接下来,使用以下命令安装 Python -

brew install python

步骤 5 - 使用以下命令安装 Scrapy -

pip install Scrapy

Scrapy - 命令行工具

描述

Scrapy命令行工具用于控制Scrapy,通常被称为“Scrapy工具”。它包括带有一组参数和选项的各种对象的命令。

配置设置

Scrapy 将在scrapy.cfg文件中找到配置设置。以下是一些地点 -

  • 系统中的C:\scrapy(项目文件夹)\scrapy.cfg

  • ~/.config/scrapy.cfg ($XDG_CONFIG_HOME) 和 ~/.scrapy.cfg ($HOME) 用于全局设置

  • 您可以在项目的根目录中找到 scrapy.cfg。

Scrapy 还可以使用以下环境变量进行配置 -

  • SCRAPY_SETTINGS_MODULE
  • SCRAPY_PROJECT
  • SCRAPY_PYTHON_SHELL

Scrapy项目的默认结构

以下结构显示了Scrapy项目的默认文件结构。

scrapy.cfg                - Deploy the configuration file
project_name/             - Name of the project
   _init_.py
   items.py               - It is project's items file
   pipelines.py           - It is project's pipelines file
   settings.py            - It is project's settings file
   spiders                - It is the spiders directory
      _init_.py
      spider_name.py
      . . .

scrapy.cfg文件是项目根目录,其中包含项目名称和项目设置。例如 -

[settings] 
default = [name of the project].settings  

[deploy] 
#url = http://localhost:6800/ 
project = [name of the project] 

使用Scrapy工具

Scrapy 工具提供了一些用法和可用命令,如下所示 -

Scrapy X.Y  - no active project 
Usage: 
   scrapy  [options] [arguments] 
Available commands: 
   crawl      It puts spider (handle the URL) to work for crawling data 
   fetch      It fetches the response from the given URL

创建项目

您可以使用以下命令在 Scrapy 中创建项目 -

scrapy startproject project_name

这将创建名为project_name的项目目录。接下来,使用以下命令转到新创建的项目 -

cd  project_name

控制项目

您可以使用 Scrapy 工具控制项目并管理它们,还可以使用以下命令创建新的蜘蛛 -

scrapy genspider mydomain mydomain.com

爬虫等命令必须在Scrapy项目内部使用。在接下来的部分中,您将了解哪些命令必须在 Scrapy 项目中运行。

Scrapy 包含一些内置命令,可用于您的项目。要查看可用命令的列表,请使用以下命令 -

scrapy -h

当您运行以下命令时,Scrapy 将显示可用命令的列表:

  • fetch - 它使用 Scrapy 下载器获取 URL。

  • runspider - 它用于运行独立的蜘蛛而不创建项目。

  • settings - 它指定项目设置值。

  • shell - 它是给定 URL 的交互式抓取模块。

  • startproject - 它创建一个新的 Scrapy 项目。

  • version - 显示 Scrapy 版本。

  • view - 它使用 Scrapy 下载器获取 URL 并在浏览器中显示内容。

您可以拥有一些与项目相关的命令,如下所示 -

  • crawl - 用于使用蜘蛛抓取数据。

  • check - 它检查爬网命令返回的项目。

  • list - 它显示项目中存在的可用蜘蛛的列表。

  • edit - 您可以使用编辑器编辑蜘蛛。

  • parse - 它使用蜘蛛解析给定的 URL。

  • bench - 用于运行快速基准测试(Benchmark 告诉 Scrapy 每分钟可以抓取多少页面)。

自定义项目命令

您可以在 Scrapy 项目中使用COMMANDS_MODULE设置构建自定义项目命令。它在设置中包含一个默认的空字符串。您可以添加以下自定义命令 -

COMMANDS_MODULE = 'mycmd.commands'

可以使用 setup.py 文件中的 scrapy.commands 部分添加 Scrapy 命令,如下所示 -

from setuptools import setup, find_packages  

setup(name = 'scrapy-module_demo', 
   entry_points = { 
      'scrapy.commands': [ 
         'cmd_demo = my_module.commands:CmdDemo', 
      ], 
   }, 
)

上面的代码在setup.py文件中添加了cmd_demo命令。

Scrapy - 蜘蛛

描述

Spider 是一个负责定义如何跟踪网站链接并从页面中提取信息的类。

Scrapy 的默认蜘蛛如下 -

scrapy.Spider

它是所有其他蜘蛛都必须继承的蜘蛛。它有以下类别 -

class scrapy.spiders.Spider

下表显示了 scrapy.Spider 类的字段 -

先生编号 字段和描述
1

姓名

这是你的蜘蛛的名字。

2

允许的域

它是蜘蛛爬行的域列表。

3

起始网址

它是一个 URL 列表,它将成为以后爬行的根,蜘蛛将从这里开始爬行。

4

自定义设置

这些设置在运行蜘蛛时将被项目范围的配置覆盖。

5

爬行器

它是链接到蜘蛛实例所绑定的 Crawler 对象的属性。

6

设置

这些是运行蜘蛛的设置。

7

记录器

它是一个用于发送日志消息的Python记录器。

8

from_crawler(爬虫,*args,**kwargs)

它是一个类方法,用于创建蜘蛛。参数是 -

  • crawler - 蜘蛛实例将绑定到的爬虫。

  • args(list) - 这些参数被传递给方法_init_()

  • kwargs(dict) - 这些关键字参数传递给方法_init_()

9

开始请求()

当没有指定特定的 URL 并且打开蜘蛛进行抓取时,Scrapy 会调用start_requests()方法。

10

make_requests_from_url(url)

它是一种用于将 url 转换为请求的方法。

11

解析(响应)

此方法处理响应并返回更多 URL 后的废弃数据。

12

日志(消息[,级别,组件])

它是一种通过蜘蛛记录器发送日志消息的方法。

13

关闭(原因)

当蜘蛛关闭时调用此方法。

蜘蛛争论

Spider 参数用于指定起始 URL,并使用带有-a选项的爬网命令传递,如下所示 -

scrapy crawl first_scrapy -a group = accessories

以下代码演示了蜘蛛如何接收参数 -

import scrapy 

class FirstSpider(scrapy.Spider): 
   name = "first" 
   
   def __init__(self, group = None, *args, **kwargs): 
      super(FirstSpider, self).__init__(*args, **kwargs) 
      self.start_urls = ["http://www.example.com/group/%s" % group]

通用蜘蛛

您可以使用通用蜘蛛来对您的蜘蛛进行子类化。他们的目标是根据一定的规则跟踪网站上的所有链接,从所有页面中提取数据。

对于以下蜘蛛中使用的示例,假设我们有一个包含以下字段的项目 -

import scrapy 
from scrapy.item import Item, Field 
  
class First_scrapyItem(scrapy.Item): 
   product_title = Field() 
   product_link = Field() 
   product_description = Field() 

爬行蜘蛛

CrawlSpider 定义了一组规则来跟踪链接并废弃多个页面。它有以下类别 -

class scrapy.spiders.CrawlSpider

以下是 CrawlSpider 类的属性 -

规则

它是一个规则对象列表,定义爬网程序如何跟踪链接。

下表显示了 CrawlSpider 类的规则 -

先生编号 规则及说明
1

链接提取器

它指定蜘蛛如何跟踪链接并提取数据。

2

打回来

将在抓取每个页面后调用它。

3

跟随

它指定是否继续跟踪链接。

parse_start_url(响应)

它通过允许解析初始响应来返回项目或请求对象。

注意- 确保在编写规则时重命名解析函数而不是解析函数,因为解析函数被 CrawlSpider 使用来实现其逻辑。

让我们看一下下面的示例,其中蜘蛛开始爬行 demoexample.com 的主页,收集所有页面、链接并使用parse_items方法进行解析 -

import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class DemoSpider(CrawlSpider):
   name = "demo"
   allowed_domains = ["www.demoexample.com"]
   start_urls = ["http://www.demoexample.com"]
      
   rules = ( 
      Rule(LinkExtractor(allow =(), restrict_xpaths = ("//div[@class = 'next']",)),
         callback = "parse_item", follow = True),
   )
   
   def parse_item(self, response):
      item = DemoItem()
      item["product_title"] = response.xpath("a/text()").extract()
      item["product_link"] = response.xpath("a/@href").extract()
      item["product_description"] = response.xpath("div[@class = 'desc']/text()").extract()
      return items

XMLFeedSpider

它是从 XML 提要中抓取并迭代节点的蜘蛛程序的基类。它有以下类别 -

class scrapy.spiders.XMLFeedSpider

下表显示了用于设置迭代器和标签名称的类属性 -

先生编号 属性及描述
1

迭代器

它定义要使用的迭代器。它可以是iternodes、htmlxml。默认是iternodes

2

迭代标签

它是一个带有要迭代的节点名称的字符串。

3

命名空间

它由 (prefix, uri) 元组列表定义,使用register_namespace()方法自动注册命名空间。

4

适应响应(响应)

它接收响应并在蜘蛛开始解析响应之前从蜘蛛中间件到达响应主体并对其进行修改。

5

parse_node(响应,选择器)

当为每个与提供的标签名称匹配的节点调用时,它会接收响应和选择器。

注意- 如果您不重写此方法,您的蜘蛛将无法工作。

6

process_results(响应,结果)

它返回蜘蛛返回的结果和响应的列表。

CSVFeedSpider

它迭代每一行,接收 CSV 文件作为响应,并调用parse_row()方法。它有以下类别 -

class scrapy.spiders.CSVFeedSpider

下表显示了可以设置的有关 CSV 文件的选项 -

先生编号 选项和说明
1

分隔符

它是一个字符串,每个字段都包含逗号(',')分隔符。

2

引用字符

它是一个字符串,每个字段都包含引号('"')。

3

标头

它是可以从中提取字段的语句列表。

4

parse_row(响应,行)

它接收响应和每一行以及标题的键。

CSVFeedSpider 示例

from scrapy.spiders import CSVFeedSpider
from demoproject.items import DemoItem  

class DemoSpider(CSVFeedSpider): 
   name = "demo" 
   allowed_domains = ["www.demoexample.com"] 
   start_urls = ["http://www.demoexample.com/feed.csv"] 
   delimiter = ";" 
   quotechar = "'" 
   headers = ["product_title", "product_link", "product_description"]  
   
   def parse_row(self, response, row): 
      self.logger.info("This is row: %r", row)  
      item = DemoItem() 
      item["product_title"] = row["product_title"] 
      item["product_link"] = row["product_link"] 
      item["product_description"] = row["product_description"] 
      return item

网站地图蜘蛛

SitemapSpider 在Sitemaps的帮助下通过从 robots.txt 中定位 URL 来抓取网站。它有以下类别 -

class scrapy.spiders.SitemapSpider

下表显示了 SitemapSpider 的字段 -

先生编号 字段和描述
1

站点地图网址

您要抓取的指向站点地图的 URL 列表。

2

站点地图规则

它是一个元组(regex、callback)的列表,其中regex是正则表达式,callback用于处理与正则表达式匹配的URL。

3

站点地图关注

它是要遵循的站点地图正则表达式的列表。

4

站点地图_备用_链接

指定单个 URL 要遵循的备用链接。

站点地图Spider 示例

以下 SitemapSpider 处理所有 URL -

from scrapy.spiders import SitemapSpider  

class DemoSpider(SitemapSpider): 
   urls = ["http://www.demoexample.com/sitemap.xml"]  
   
   def parse(self, response): 
      # You can scrap items here

以下 SitemapSpider 使用回调处理一些 URL -

from scrapy.spiders import SitemapSpider  

class DemoSpider(SitemapSpider): 
   urls = ["http://www.demoexample.com/sitemap.xml"] 
   
   rules = [ 
      ("/item/", "parse_item"), 
      ("/group/", "parse_group"), 
   ]  
   
   def parse_item(self, response): 
      # you can scrap item here  
   
   def parse_group(self, response): 
      # you can scrap group here 

以下代码显示 robots.txt 中 url 包含/sitemap_company的站点地图-

from scrapy.spiders import SitemapSpider

class DemoSpider(SitemapSpider): 
   urls = ["http://www.demoexample.com/robots.txt"] 
   rules = [ 
      ("/company/", "parse_company"), 
   ] 
   sitemap_follow = ["/sitemap_company"]  
   
   def parse_company(self, response): 
      # you can scrap company here 

您甚至可以将 SitemapSpider 与其他 URL 结合起来,如以下命令所示。

from scrapy.spiders import SitemapSpider  

class DemoSpider(SitemapSpider): 
   urls = ["http://www.demoexample.com/robots.txt"] 
   rules = [ 
      ("/company/", "parse_company"), 
   ]  
   
   other_urls = ["http://www.demoexample.com/contact-us"] 
   def start_requests(self): 
      requests = list(super(DemoSpider, self).start_requests()) 
      requests += [scrapy.Request(x, self.parse_other) for x in self.other_urls] 
      return requests 

   def parse_company(self, response): 
      # you can scrap company here... 

   def parse_other(self, response): 
      # you can scrap other here... 

Scrapy - 选择器

描述

当您抓取网页时,您需要使用称为选择器的机制提取 HTML 源的特定部分,该机制通过使用 XPath 或 CSS 表达式来实现。选择器基于lxml库构建,该库以 Python 语言处理 XML 和 HTML。

使用以下代码片段来定义选择器的不同概念 -

<html>
   <head>
      <title>My Website</title>
   </head>
   
   <body>
      <span>Hello world!!!</span>
      <div class = 'links'>
         <a href = 'one.html'>Link 1<img src = 'image1.jpg'/></a>
         <a href = 'two.html'>Link 2<img src = 'image2.jpg'/></a>
         <a href = 'three.html'>Link 3<img src = 'image3.jpg'/></a>
      </div>
   </body>
</html>

构造选择器

您可以通过传递文本TextResponse对象来构造选择器类实例。根据提供的输入类型,选择器选择以下规则 -

from scrapy.selector import Selector 
from scrapy.http import HtmlResponse

使用上面的代码,您可以将文本构造为 -

Selector(text = body).xpath('//span/text()').extract() 

它将显示结果为 -

[u'Hello world!!!'] 

您可以根据响应构建 -

response = HtmlResponse(url = 'http://mysite.com', body = body) 
Selector(response = response).xpath('//span/text()').extract()

它将显示结果为 -

[u'Hello world!!!']

使用选择器

使用上面的简单代码片段,您可以构建用于选择标题标签中定义的文本的 XPath,如下所示 -

>>response.selector.xpath('//title/text()')

现在,您可以使用.extract()方法提取文本数据,如下所示 -

>>response.xpath('//title/text()').extract()

它将产生如下结果:

[u'My Website']

您可以显示所有元素的名称,如下所示 -

>>response.xpath('//div[@class = "links"]/a/text()').extract() 

它将把元素显示为 -

Link 1
Link 2
Link 3

如果要提取第一个元素,请使用方法.extract_first(),如下所示 -

>>response.xpath('//div[@class = "links"]/a/text()').extract_first()

它将把元素显示为 -

Link 1

嵌套选择器

使用上面的代码,您可以使用.xpath()方法嵌套选择器以显示页面链接和图像源,如下所示 -

links = response.xpath('//a[contains(@href, "image")]') 

for index, link in enumerate(links): 
   args = (index, link.xpath('@href').extract(), link.xpath('img/@src').extract()) 
   print 'The link %d pointing to url %s and image %s' % args 

它将显示结果为 -

Link 1 pointing to url [u'one.html'] and image [u'image1.jpg']
Link 2 pointing to url [u'two.html'] and image [u'image2.jpg']
Link 3 pointing to url [u'three.html'] and image [u'image3.jpg']

使用正则表达式的选择器

Scrapy 允许使用正则表达式提取数据,它使用.re()方法。从上面的 HTML 代码中,我们将提取图像名称,如下所示 -

>>response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')

上面的行将图像名称显示为 -

[u'Link 1', 
u'Link 2', 
u'Link 3'] 

使用相对 XPath

当您使用以/开头的 XPath 时,嵌套选择器和 XPath 与文档的绝对路径相关,而不是选择器的相对路径。

如果你想提取<p>元素,那么首先获取所有 div 元素 -

>>mydiv = response.xpath('//div')

接下来,您可以通过在 XPath 前面添加一个点作为.//p来提取其中的所有“p”元素,如下所示 -

>>for p in mydiv.xpath('.//p').extract() 

使用 EXSLT 扩展

EXSLT 是一个发布 XSLT(可扩展样式表语言转换)扩展的社区,该扩展可将 XML 文档转换为 XHTML 文档。您可以将 EXSLT 扩展与 XPath 表达式中注册的命名空间一起使用,如下表所示 -

先生编号 前缀和用法 命名空间
1

关于

常用表达

http://exslt.org/regexp/index.html

2

设置操作

http://exslt.org/set/index.html

您可以查看上一节中使用正则表达式提取数据的简单代码格式。

有一些 XPath 提示,在将 XPath 与 Scrapy 选择器一起使用时非常有用。欲了解更多信息,请点击此链接

Scrapy - 项目

描述

Scrapy 过程可用于使用蜘蛛从网页等源中提取数据。Scrapy 使用Item类来生成输出,其对象用于收集抓取的数据。

申报物品

您可以使用类定义语法以及字段对象来声明项目,如下所示 -

import scrapy 
class MyProducts(scrapy.Item): 
   productName = Field() 
   productLink = Field() 
   imageURL = Field() 
   price = Field() 
   size = Field() 

项目字段

项目字段用于显示每个字段的元数据。由于字段对象的值没有限制,因此可访问的元数据键不包含任何元数据的引用列表。字段对象用于指定所有字段元数据,您可以根据项目中的要求指定任何其他字段键。可以使用 Item.fields 属性访问字段对象。

使用项目

当您使用这些项目时,可以定义一些常用功能。欲了解更多信息,请点击此链接

扩展项目

可以通过声明原始项目的子类来扩展这些项目。例如 -

class MyProductDetails(Product): 
   original_rate = scrapy.Field(serializer = str) 
   discount_rate = scrapy.Field()

您可以使用现有字段元数据通过添加更多值或更改现有值来扩展字段元数据,如以下代码所示 -

class MyProductPackage(Product): 
   name = scrapy.Field(Product.fields['name'], serializer = serializer_demo)

项目对象

可以使用以下类指定项目对象,该类从给定参数提供新的初始化项目 -

class scrapy.item.Item([arg])

Item 提供构造函数的副本,并提供由字段中的项目给出的额外属性。

字段对象

可以使用以下类指定字段对象,其中 Field 类不发出附加过程或属性 -

class scrapy.item.Field([arg])

Scrapy - 物品加载器

描述

项目加载器提供了一种便捷的方法来填充从网站上抓取的项目。

声明项目加载器

Item Loaders 的声明就像 Items 一样。

例如 -

from scrapy.loader import ItemLoader 
from scrapy.loader.processors import TakeFirst, MapCompose, Join  

class DemoLoader(ItemLoader):  
   default_output_processor = TakeFirst()  
   title_in = MapCompose(unicode.title) 
   title_out = Join()  
   size_in = MapCompose(unicode.strip)  
   # you can continue scraping here

在上面的代码中,您可以看到输入处理器是使用_in后缀声明的,输出处理器是使用_out后缀声明的。

ItemLoader.default_input_processor和ItemLoader.default_output_processor属性用于声明默认输入/输出处理器

使用项目加载器填充项目

要使用 Item Loader,首先使用类似 dict 的对象进行实例化,或者在项目使用ItemLoader.default_item_class属性中指定的 Item 类的情况下不使用该对象进行实例化。

  • 您可以使用选择器将值收集到项目加载器中。

  • 您可以在同一项目字段中添加更多值,项目加载器将使用适当的处理程序来添加这些值。

以下代码演示了如何使用项目加载器填充项目 -

from scrapy.loader import ItemLoader 
from demoproject.items import Demo  

def parse(self, response): 
   l = ItemLoader(item = Product(), response = response)
   l.add_xpath("title", "//div[@class = 'product_title']")
   l.add_xpath("title", "//div[@class = 'product_name']")
   l.add_xpath("desc", "//div[@class = 'desc']")
   l.add_css("size", "div#size]")
   l.add_value("last_updated", "yesterday")
   return l.load_item()

如上所示,有两个不同的 XPath,使用add_xpath()方法从中提取标题字段-

1. //div[@class = "product_title"] 
2. //div[@class = "product_name"]

此后,对desc字段使用类似的请求。使用add_css()方法提取大小数据,并使用add_value()方法将last_updated填充为值“昨天” 。

收集完所有数据后,调用ItemLoader.load_item()方法,该方法返回填充了使用add_xpath()add_css()add_value()方法提取的数据的项目。

输入和输出处理器

项目加载器的每个字段包含一个输入处理器和一个输出处理器。

  • 提取数据后,输入处理器对其进行处理,并将其结果存储在 ItemLoader 中。

  • 接下来,收集数据后,调用 ItemLoader.load_item() 方法来获取填充的 Item 对象。

  • 最后,您可以将输出处理器的结果分配给该项目。

以下代码演示了如何调用特定字段的输入和输出处理器 -

l = ItemLoader(Product(), some_selector)
l.add_xpath("title", xpath1) # [1]
l.add_xpath("title", xpath2) # [2]
l.add_css("title", css)      # [3]
l.add_value("title", "demo") # [4]
return l.load_item()         # [5]

第 1 行- 标题数据从 xpath1 中提取并通过输入处理器,其结果被收集并存储在 ItemLoader 中。

第 2 行- 类似地,标题是从 xpath2 中提取的,并通过相同的输入处理器,其结果将添加到为 [1] 收集的数据中。

第 3 行- 标题从 css 选择器中提取并通过相同的输入处理器传递,并将结果添加到为 [1] 和 [2] 收集的数据中。

第 4 行- 接下来,分配值“demo”并通过输入处理器传递。

第 5 行- 最后,从所有字段内部收集数据并将其传递到输出处理器,并将最终值分配给项目。

声明输入和输出处理器

输入和输出处理器在 ItemLoader 定义中声明。除此之外,它们还可以在项目字段元数据中指定。

例如 -

import scrapy 
from scrapy.loader.processors import Join, MapCompose, TakeFirst 
from w3lib.html import remove_tags  

def filter_size(value): 
   if value.isdigit(): 
      return value  

class Item(scrapy.Item): 
   name = scrapy.Field( 
      input_processor = MapCompose(remove_tags), 
      output_processor = Join(), 
   )
   size = scrapy.Field( 
      input_processor = MapCompose(remove_tags, filter_price), 
      output_processor = TakeFirst(), 
   ) 

>>> from scrapy.loader import ItemLoader 
>>> il = ItemLoader(item = Product()) 
>>> il.add_value('title', [u'Hello', u'<strong>world</strong>']) 
>>> il.add_value('size', [u'<span>100 kg</span>']) 
>>> il.load_item()

它将输出显示为 -

{'title': u'Hello world', 'size': u'100 kg'}

项目加载器上下文

项目加载器上下文是在输入和输出处理器之间共享的任意键值的字典。

例如,假设您有一个函数parse_length -

def parse_length(text, loader_context): 
   unit = loader_context.get('unit', 'cm') 
   
   # You can write parsing code of length here  
   return parsed_length

通过接收 loader_context 参数,它告诉 Item Loader 它可以接收 Item Loader 上下文。有多种方法可以更改项目加载器上下文的值 -

  • 修改当前活动的项目加载器上下文 -

loader = ItemLoader (product)
loader.context ["unit"] = "mm"
  • 在项目加载器实例化上 -

loader = ItemLoader(product, unit = "mm")
  • 在使用项目加载器上下文实例化的输入/输出处理器的项目加载器声明上 -

class ProductLoader(ItemLoader):
   length_out = MapCompose(parse_length, unit = "mm")

项目加载器对象

它是一个返回新项目加载器以填充给定项目的对象。它有以下类别 -

class scrapy.loader.ItemLoader([item, selector, response, ]**kwargs)

下表显示了 ItemLoader 对象的参数 -

先生编号 参数及说明
1

物品

它是通过调用 add_xpath()、add_css() 或 add_value() 来填充的项目。

2

选择器

它用于从网站中提取数据。

3

回复

它用于使用default_selector_class构造选择器。

下表显示了 ItemLoader 对象的方法 -

先生编号 方法及说明 例子
1

get_value(值, *处理器, **kwargs)

通过给定的处理器和关键字参数,该值由 get_value() 方法处理。

>>> from scrapy.loader.processors import TakeFirst
>>> loader.get_value(u'title: demoweb', TakeFirst(), 
unicode.upper, re = 'title: (.+)')
'DEMOWEB`
2

add_value(字段名称、值、*处理器、**kwargs)

它处理该值,并在通过字段输入处理器之前通过提供处理器和关键字参数将其添加到首先通过 get_value 传递的字段中。

loader.add_value('title', u'DVD')
loader.add_value('colors', [u'black', u'white'])
loader.add_value('length', u'80')
loader.add_value('price', u'2500')
3

替换值(字段名称,值,*处理器,**kwargs)

它将收集的数据替换为新值。

loader.replace_value('title', u'DVD')
loader.replace_value('colors', [u'black', 
u'white'])
loader.replace_value('length', u'80')
loader.replace_value('price', u'2500')
4

get_xpath(xpath, *处理器, **kwargs)

它用于通过接收XPath提供处理器和关键字参数来提取 unicode 字符串。

# HTML code: <div class = "item-name">DVD</div>
loader.get_xpath("//div[@class = 
'item-name']")

# HTML code: <div id = "length">the length is 
45cm</div>
loader.get_xpath("//div[@id = 'length']", TakeFirst(), 
re = "the length is (.*)")
5

add_xpath(字段名称,xpath,*处理器,**kwargs)

它接收提取 unicode 字符串的字段的XPath 。

# HTML code: <div class = "item-name">DVD</div>
loader.add_xpath('name', '//div
[@class = "item-name"]')

# HTML code: <div id = "length">the length is 
45cm</div>
loader.add_xpath('length', '//div[@id = "length"]',
 re = 'the length is (.*)')
6

Replace_xpath(字段名称,xpath,*处理器,**kwargs)

它使用XPath替换从站点收集的数据。

# HTML code: <div class = "item-name">DVD</div>
loader.replace_xpath('name', '
//div[@class = "item-name"]')

# HTML code: <div id = "length">the length is
 45cm</div>
loader.replace_xpath('length', '
//div[@id = "length"]', re = 'the length is (.*)')
7

get_css(css, *处理器, **kwargs)

它接收用于提取 unicode 字符串的 CSS 选择器。

loader.get_css("div.item-name")
loader.get_css("div#length", TakeFirst(), 
re = "the length is (.*)")
8

add_css(field_name, css, *处理器, **kwargs)

它与 add_value() 方法类似,但有一点不同,它将 CSS 选择器添加到字段中。

loader.add_css('name', 'div.item-name')
loader.add_css('length', 'div#length', 
re = 'the length is (.*)')
9

Replace_css(field_name, css, *处理器, **kwargs)

它使用 CSS 选择器替换提取的数据。

loader.replace_css('name', 'div.item-name')
loader.replace_css('length', 'div#length',
 re = 'the length is (.*)')
10

加载项()

收集数据后,此方法会用收集的数据填充该项目并返回它。

def parse(self, response):
l = ItemLoader(item = Product(), 
response = response)
l.add_xpath('title', '//
div[@class = "product_title"]')
loader.load_item()
11

嵌套_xpath(xpath)

它用于使用 XPath 选择器创建嵌套加载器。

loader = ItemLoader(item = Item())
loader.add_xpath('social', '
a[@class = "social"]/@href')
loader.add_xpath('email', '
a[@class = "email"]/@href')
12

嵌套CSS(CSS)

它用于使用 CSS 选择器创建嵌套加载器。

loader = ItemLoader(item = Item())
loader.add_css('social', 'a[@class = "social"]/@href')
loader.add_css('email', 'a[@class = "email"]/@href')	

下表显示了 ItemLoader 对象的属性 -

先生编号 属性及描述
1

物品

它是项目加载器执行解析的对象。

2

语境

项目加载器的当前上下文处于活动状态。

3

默认项目类别

如果构造函数中未给出,则它用于表示项目。

4

默认输入处理器

未指定输入处理器的字段是唯一使用default_input_processors 的字段。

5

默认输出处理器

未指定输出处理器的字段是唯一使用 default_output_processors 的字段。

6

默认选择器类

如果构造函数中未给出,则它是用于构造选择器的类。

7

选择器

它是一个可用于从站点提取数据的对象。

嵌套加载器

它用于在解析文档子部分中的值时创建嵌套加载器。如果您不创建嵌套加载器,则需要为要提取的每个值指定完整的 XPath 或 CSS。

例如,假设数据是从标题页中提取的 -

<header>
   <a class = "social" href = "http://facebook.com/whatever">facebook</a>
   <a class = "social" href = "http://twitter.com/whatever">twitter</a>
   <a class = "email" href = "mailto:someone@example.com">send mail</a>
</header>

接下来,您可以通过向标头添加相关值来创建带有标头选择器的嵌套加载器 -

loader = ItemLoader(item = Item())
header_loader = loader.nested_xpath('//header')
header_loader.add_xpath('social', 'a[@class = "social"]/@href')
header_loader.add_xpath('email', 'a[@class = "email"]/@href')
loader.load_item()

重用和扩展项目加载器

项目加载器旨在减轻维护工作,当您的项目获得更多蜘蛛时,维护工作将成为一个基本问题。

例如,假设某个站点的产品名称包含在三个破折号中(例如 --DVD---)。如果您不希望它出现在最终产品名称中,您可以通过重用默认的产品项加载器来删除这些破折号,如以下代码所示 -

from scrapy.loader.processors import MapCompose 
from demoproject.ItemLoaders import DemoLoader  

def strip_dashes(x): 
   return x.strip('-')  

class SiteSpecificLoader(DemoLoader): 
   title_in = MapCompose(strip_dashes, DemoLoader.title_in)

可用的内置处理器

以下是一些常用的内置处理器 -

类 scrapy.loader.processors.Identity

它返回原始值而不改变它。例如 -

>>> from scrapy.loader.processors import Identity
>>> proc = Identity()
>>> proc(['a', 'b', 'c'])
['a', 'b', 'c']

类 scrapy.loader.processors.TakeFirst

它返回接收值列表中第一个非空/非空的值。例如 -

>>> from scrapy.loader.processors import TakeFirst
>>> proc = TakeFirst()
>>> proc(['', 'a', 'b', 'c'])
'a'

类 scrapy.loader.processors.Join(separator = u' ')

它返回附加到分隔符的值。默认分隔符是 u' ',它相当于函数u' '.join。例如 -

>>> from scrapy.loader.processors import Join
>>> proc = Join()
>>> proc(['a', 'b', 'c'])
u'a b c'
>>> proc = Join('<br>')
>>> proc(['a', 'b', 'c'])
u'a<br>b<br>c'

类 scrapy.loader.processors.Compose(*functions, **default_loader_context)

它由处理器定义,其中每个输入值都传递给第一个函数,该函数的结果传递给第二个函数,依此类推,直到 ast 函数返回最终值作为输出。

例如 -

>>> from scrapy.loader.processors import Compose
>>> proc = Compose(lambda v: v[0], str.upper)
>>> proc(['python', 'scrapy'])
'PYTHON'

类 scrapy.loader.processors.MapCompose(*functions, **default_loader_context)

它是一个处理器,其中迭代输入值并将第一个函数应用于每个元素。接下来,这些函数调用的结果被连接起来构建新的可迭代对象,然后将其应用于第二个函数,依此类推,直到最后一个函数。

例如 -

>>> def filter_scrapy(x): 
   return None if x == 'scrapy' else x  

>>> from scrapy.loader.processors import MapCompose 
>>> proc = MapCompose(filter_scrapy, unicode.upper) 
>>> proc([u'hi', u'everyone', u'im', u'pythonscrapy']) 
[u'HI, u'IM', u'PYTHONSCRAPY'] 

类 scrapy.loader.processors.SelectJmes(json_path)

此类使用提供的 json 路径查询值并返回输出。

例如 -

>>> from scrapy.loader.processors import SelectJmes, Compose, MapCompose
>>> proc = SelectJmes("hello")
>>> proc({'hello': 'scrapy'})
'scrapy'
>>> proc({'hello': {'scrapy': 'world'}})
{'scrapy': 'world'}

以下是通过导入 json 查询值的代码 -

>>> import json
>>> proc_single_json_str = Compose(json.loads, SelectJmes("hello"))
>>> proc_single_json_str('{"hello": "scrapy"}')
u'scrapy'
>>> proc_json_list = Compose(json.loads, MapCompose(SelectJmes('hello')))
>>> proc_json_list('[{"hello":"scrapy"}, {"world":"env"}]')
[u'scrapy']

Scrapy - 外壳

描述

Scrapy shell 可以使用无错误代码来抓取数据,而无需使用蜘蛛。Scrapy shell 的主要目的是测试提取的代码、XPath 或 CSS 表达式。它还有助于指定您要从中抓取数据的网页。

配置外壳

可以通过安装IPython(用于交互式计算)控制台来配置 shell ,这是一个功能强大的交互式 shell,可以提供自动完成、彩色输出等功能。

如果您在 Unix 平台上工作,那么最好安装 IPython。如果 IPython 无法访问,您也可以使用bpython 。

您可以通过设置名为 SCRAPY_PYTHON_SHELL 的环境变量或定义 scrapy.cfg 文件来配置 shell,如下所示 -

[settings]
shell = bpython

启动外壳

可以使用以下命令启动 Scrapy shell -

scrapy shell <url>

url指定需要抓取数据的 URL

使用外壳

shell 提供了一些额外的快捷方式和 Scrapy 对象,如下表所述 -

可用的快捷键

Shell 在项目中提供了以下可用的快捷方式 -

先生编号 快捷方式及说明
1

帮助()

它提供了可用的对象和快捷方式以及帮助选项。

2

获取(请求或网址)

它收集来自请求或 URL 的响应,并且关联的对象将得到正确更新。

3

查看(响应)

您可以在本地浏览器中查看给定请求的响应以进行观察,并正确显示外部链接,它会在响应正文中附加一个基本标记。

可用的 Scrapy 对象

Shell 在项目中提供了以下可用的 Scrapy 对象 -

先生编号 对象及描述
1

爬行器

它指定当前的爬虫对象。

2

蜘蛛

如果当前 URL 没有蜘蛛,那么它将通过定义新的蜘蛛来处理 URL 或蜘蛛对象。

3

要求

它指定最后收集的页面的请求对象。

4

回复

它指定最后收集的页面的响应对象。

5

设置

它提供了当前的 Scrapy 设置。

Shell 会话示例

让我们尝试抓取 scrapy.org 网站,然后开始按照所述从 reddit.com 抓取数据。

在继续之前,首先我们将启动 shell,如以下命令所示 -

scrapy shell 'http://scrapy.org' --nolog

使用上面的 URL 时,Scrapy 将显示可用的对象 -

[s] Available Scrapy objects:
[s]   crawler    <scrapy.crawler.Crawler object at 0x1e16b50>
[s]   item       {}
[s]   request    <GET http://scrapy.org >
[s]   response   <200 http://scrapy.org >
[s]   settings   <scrapy.settings.Settings object at 0x2bfd650>
[s]   spider     <Spider 'default' at 0x20c6f50>
[s] Useful shortcuts:
[s]   shelp()           Provides available objects and shortcuts with help option
[s]   fetch(req_or_url) Collects the response from the request or URL and associated 
objects will get update
[s]   view(response)    View the response for the given request

接下来,从对象的工作开始,如下所示 -

>> response.xpath('//title/text()').extract_first() 
u'Scrapy | A Fast and Powerful Scraping and Web Crawling Framework'  
>> fetch("http://reddit.com") 
[s] Available Scrapy objects: 
[s]   crawler     
[s]   item       {} 
[s]   request     
[s]   response   <200 https://www.reddit.com/> 
[s]   settings    
[s]   spider      
[s] Useful shortcuts: 
[s]   shelp()           Shell help (print this help) 
[s]   fetch(req_or_url) Fetch request (or URL) and update local objects 
[s]   view(response)    View response in a browser  
>> response.xpath('//title/text()').extract() 
[u'reddit: the front page of the internet']  
>> request = request.replace(method="POST")  
>> fetch(request) 
[s] Available Scrapy objects: 
[s]   crawler     
... 

从 Spider 中调用 Shell 来检查响应

仅当您期望获得该响应时,您才可以检查蜘蛛处理的响应。

例如 -

import scrapy 

class SpiderDemo(scrapy.Spider): 
   name = "spiderdemo" 
   start_urls = [ 
      "http://mysite.com", 
      "http://mysite1.org", 
      "http://mysite2.net", 
   ]  
   
   def parse(self, response): 
      # You can inspect one specific response 
      if ".net" in response.url: 
         from scrapy.shell import inspect_response 
         inspect_response(response, self)

如上面的代码所示,您可以使用以下函数从蜘蛛调用 shell 来检查响应 -

scrapy.shell.inspect_response

现在运行蜘蛛,您将看到以下屏幕 -

2016-02-08 18:15:20-0400 [scrapy] DEBUG: Crawled (200)  (referer: None) 
2016-02-08 18:15:20-0400 [scrapy] DEBUG: Crawled (200)  (referer: None) 
2016-02-08 18:15:20-0400 [scrapy] DEBUG: Crawled (200)  (referer: None) 
[s] Available Scrapy objects: 
[s]   crawler     
...  
>> response.url 
'http://mysite2.org' 

您可以使用以下代码检查提取的代码是否正常工作 -

>> response.xpath('//div[@class = "val"]')

它将输出显示为

[]

上面的行仅显示空白输出。现在您可以调用 shell 来检查响应,如下所示 -

>> view(response)

它将响应显示为

True

Scrapy - 项目管道

描述

物料管道是一种处理报废物料的方法。当一个项目被发送到项目管道时,它会被蜘蛛抓取并使用多个按顺序执行的组件进行处理。

每当收到物品时,它都会决定以下任一操作 -

  • 继续处理该项目。
  • 将其从管道中丢弃。
  • 停止处理该项目。

项目管道通常用于以下目的 -

  • 将抓取的项目存储在数据库中。
  • 如果收到的项目是重复的,那么它将丢弃重复的项目。
  • 它将检查该项目是否包含目标字段。
  • 清除 HTML 数据。

句法

您可以使用以下方法编写项目管道 -

process_item(self, item, spider) 

上述方法包含以下参数 -

  • Item(项目对象或字典)- 它指定抓取的项目。
  • Spider (spider object) - 刮擦物品的蜘蛛。

您可以使用下表中给出的其他方法 -

先生编号 方法及说明 参数
1

open_spider(自身,蜘蛛

打开spider时选择它。

Spider(蜘蛛对象)- 它指的是被打开的蜘蛛。

2

close_spider(自身,蜘蛛

当蜘蛛关闭时选择它。

Spider(蜘蛛对象)- 它指的是被关闭的蜘蛛。

3

from_crawler( cls, 爬虫)

借助爬虫,管道可以访问Scrapy的信号和设置等核心组件。

crawler(Crawler对象)-它指的是使用此管道的爬虫。

例子

以下是不同概念中使用的项目管道的示例。

丢弃没有标签的物品

在以下代码中,管道平衡那些不包含增值税的商品的(价格)属性(excludes_vat 属性),并忽略那些没有价格标签的商品 -

from Scrapy.exceptions import DropItem  
class PricePipeline(object): 
   vat = 2.25 

   def process_item(self, item, spider): 
      if item['price']: 
         if item['excludes_vat']: 
            item['price'] = item['price'] * self.vat 
            return item 
         else: 
            raise DropItem("Missing price in %s" % item) 

将项目写入 JSON 文件

以下代码会将所有蜘蛛抓取的所有项目存储到单个items.jl文件中,该文件每行包含一个 JSON 格式的序列化形式的项目。代码中使用JsonWriterPipeline类展示如何编写项目管道 -

import json  

class JsonWriterPipeline(object): 
   def __init__(self): 
      self.file = open('items.jl', 'wb') 

   def process_item(self, item, spider): 
      line = json.dumps(dict(item)) + "\n" 
      self.file.write(line) 
      return item

将项目写入 MongoDB

您可以在Scrapy设置中指定MongoDB地址和数据库名称,并且MongoDB集合可以以项目类命名。下面的代码描述了如何使用from_crawler()