Scrapy 简明教程
Scrapy - Overview
Scrapy 是一个使用 Python 编写的高速、开放源代码 Web 爬取框架,它用于借助基于 XPath 的选择器从网页提取数据。
Scrapy 最初于 2008 年 6 月 26 日发布,并获得 BSD 许可,并在 2015 年 6 月发布了 1.0 里程碑版本。
Why Use Scrapy?
-
构建和扩展大型爬取项目更为轻松。
-
它具有一个内置机制,称为选择器,用于从网站中提取数据。
-
它以异步方式处理请求,且速度很快。
-
它使用 Auto-throttling mechanism 自动调整爬取速度。
-
Ensures developer accessibility.
Features of Scrapy
-
Scrapy 是一个开源且免费的 web 爬取框架。
-
Scrapy 生成以 JSON、CSV 和 XML 等格式进行馈送导出的数据。
-
Scrapy 内置了通过 XPath 或 CSS 表达式从来源中选择和提取数据的支持。
-
基于爬虫的 Scrapy 允许自动从网页中提取数据。
Scrapy - Environment
在本章中,我们将讨论如何安装和设置 Scrapy。Scrapy 必须与 Python 一起安装。
可以通过 pip 安装 Scrapy。要安装,运行以下命令 −
pip install Scrapy
Windows
Note - 在 Windows 操作系统上不支持 Python 3。
Step 1 - 从 Python 安装 Python 2.7
通过将以下路径添加到 PATH 来设置环境变量 −
C:\Python27\;C:\Python27\Scripts\;
你可以使用以下命令来检查 Python 版本 −
python --version
Step 2 - 安装 OpenSSL 。
在你的环境变量中添加 C:\OpenSSL-Win32\bin。
Note - OpenSSL 预装在除 Windows 以外的所有操作系统中。
Step 3 - 安装 Visual C++ 2008 再发行包。
Step 4 - 安装 pywin32 。
Step 5 - 为早于 2.7.9 的 Python 安装 pip 。
你可以使用下面的命令检查 pip 版本 -
pip --version
Step 6 - 要安装 scrapy,运行以下命令 -
pip install Scrapy
Anaconda
conda install -c scrapinghub scrapy
Scrapinghub 公司支持 Linux、Windows 和 OS X 的官方 conda 包。
Note - 如果你在使用 pip 安装时遇到问题,建议通过上面的命令安装 Scrapy。
Ubuntu 9.10 or Above
最新版的 Python 已预先安装在 Ubuntu 操作系统上。使用由 Scrapinghub 提供的 Ubuntu 包 aptgettable。要使用这些包 -
Step 1 - 你需要将用于对 Scrapy 包进行签名的 GPG 密钥导入 APT 密钥环 -
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 627220E7
Step 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
Step 3 - 更新包列表并安装 scrapy -
sudo apt-get update && sudo apt-get install scrapy
Mac OS X
使用下面的命令安装 Xcode 命令行工具 -
xcode-select --install
安装一个新的更新版本而不是使用系统 Python,该版本不会与系统中的其他部分发生冲突。
Step 1 - 安装 homebrew 。
Step 2 - 设置环境 PATH 变量,以指定 homebrew 包应在系统包之前使用 -
echo "export PATH = /usr/local/bin:/usr/local/sbin:$PATH" >> ~/.bashrc
Step 3 - 要确保已经完成更改,使用以下命令重新加载 .bashrc -
source ~/.bashrc
Step 4 - 接下来,使用下面的命令安装 Python -
brew install python
Step 5 - 使用下面的命令安装 Scrapy -
pip install Scrapy
Scrapy - Command Line Tools
Configuration Settings
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
Default Structure Scrapy Project
以下结构展示了 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]
Using Scrapy Tool
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
Creating a Project
您可以使用以下命令在 Scrapy 中创建项目 −
scrapy startproject project_name
这会创建名为 project_name 的项目目录。然后,使用以下命令转到新创建的项目 −
cd project_name
Controlling Projects
您可以使用 Scrapy 工具控制项目和管理它们,还可以使用以下命令创建新的爬虫 −
scrapy genspider mydomain mydomain.com
crawl 等命令必须在 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 − 它用于运行快速基准测试(基准值指出 Scrapy 每分钟可以爬取多少页面)。
Custom Project Commands
您可以使用 COMMANDS_MODULE 在 Scrapy 项目中设置自定义项目命令。它在设置中包含一个默认的空字符串。您可以添加以下自定义命令−
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 - Spiders
scrapy.Spider
它是一个爬虫,每个其他爬虫都必须从中继承。它具有以下类 −
class scrapy.spiders.Spider
下表显示了 scrapy.Spider 类的字段 −
Sr.No |
Field & Description |
1 |
name 它是爬虫的名称。 |
2 |
allowed_domains 它是爬虫抓取的域的列表。 |
3 |
start_urls 它是 URL 的列表,它们将成为以后抓取的根源,爬虫将从中开始抓取。 |
4 |
custom_settings 这些是设置,在运行爬虫时,将从项目范围配置中覆盖。 |
5 |
crawler 它是一个属性,链接到 spider 实例所绑定的 Crawler 对象。 |
6 |
settings 这些是用于运行爬虫的设置。 |
7 |
logger 它是一个 Python 日志记录器,用于发送日志消息。 |
8 |
from_crawler(crawler,*args, kwargs)*它是一个类方法,用于创建爬虫。参数是 − *crawler − 爬虫实例将与其绑定的爬取器。 args(list) − 这些参数传递给 init () 方法。 kwargs(dict) − 这些关键字参数传递给 init () 方法。 |
9 |
start_requests() 如果未指定特定的 URL 并且针对爬取打开了蜘蛛,则 Scrapy 会调用 start_requests() 方法。 |
10 |
make_requests_from_url(url) 这是一个用于将 url 转换为请求的方法。 |
11 |
parse(response) 此方法处理响应并返回废弃数据,并遵循更多 URL。 |
12 |
log(message[,level,component]) 这是一个通过 Spider 记录器发送日志消息的方法。 |
13 |
closed(reason) 此方法在 Spider 关闭时调用。 |
Spider Arguments
Spider 参数用于指定开始 URL,并使用 crawl 命令与 -a 选项一起传递,如下所示 −
scrapy crawl first_scrapy -a group = accessories
以下代码演示了 Spider 如何接收参数 −
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]
Generic Spiders
你可以使用通用 Spider 对你的 Spider 进行子类化。它们的目的是根据特定规则遵循网站上的所有链接,以便从所有页面中提取数据。
对于以下 Spider 中使用的示例,让我们假设我们有一个包含以下字段的项目 −
import scrapy
from scrapy.item import Item, Field
class First_scrapyItem(scrapy.Item):
product_title = Field()
product_link = Field()
product_description = Field()
CrawlSpider
CrawlSpider 定义了一组要遵循的规则,以便遵循链接并提取多个页面。它具有以下类 −
class scrapy.spiders.CrawlSpider
下面是 CrawlSpider 类的属性 −
rules
这是一个规则对象的列表,它定义了爬虫如何遵循链接。
下表显示了 CrawlSpider 类的规则 −
Sr.No |
Rule & Description |
1 |
LinkExtractor 它指定了 Spider 如何遵循链接并提取数据。 |
2 |
callback 它应该在每个页面被废弃之后调用。 |
3 |
follow 它指定是否继续遵循链接。 |
parse_start_url(response)
它可以通过允许解析初始响应来返回项目或请求对象。
Note − 确保在编写规则时,将 parse 函数重命名为除 parse 之外的其他名称,因为 parse 函数由 CrawlSpider 用于实现其逻辑。
让我们看一看以下示例,其中 Spider 开始爬取 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 feed 进行抓取并迭代节点的爬虫的基础类。它有以下类:
class scrapy.spiders.XMLFeedSpider
下表显示用于设置迭代器和标签名的类属性:
Sr.No |
Attribute & Description |
1 |
iterator 它定义了要使用的迭代器。它可以是 iternodes、html 或 xml。默认值为 iternodes。 |
2 |
itertag 它是一个用于迭代的节点名称字符串。 |
3 |
namespaces 它由 (prefix, uri) 元组列表定义,该列表使用 register_namespace() 方法自动注册命名空间。 |
4 |
adapt_response(response) 当来自爬虫中间件的响应到达时,它接收响应并修改响应正文,在爬虫开始解析它之前。 |
5 |
parse_node(response,selector) 当调用每个与提供标签名称匹配的节点时,它接收响应和一个选择器。 Note -如果你不重写该方法,你的爬虫将不起作用。 |
6 |
process_results(response,results) 返回爬虫返回的结果和响应列表。 |
CSVFeedSpider
它遍历每行,接收 CSV 文件作为响应,并调用 parse_row() 方法。它有以下类:
class scrapy.spiders.CSVFeedSpider
下表显示了关于 CSV 文件的设置选项:
Sr.No |
Option & Description |
1 |
delimiter 它是一个包含逗号(“,”)分隔符的字符串,用于每个字段。 |
2 |
quotechar 它是一个包含引号(“"”)的字符串,用于每个字段。 |
3 |
headers 它是一个包含字段可以从中提取的语句的列表。 |
4 |
parse_row(response,row) 它接收响应和每一行以及头部的键。 |
CSVFeedSpider Example
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
SitemapSpider 在 Sitemaps 的帮助下,通过从 robots.txt 定位 URL 来爬取网站。它具有以下类:
class scrapy.spiders.SitemapSpider
下表显示了 SitemapSpider 的字段:
Sr.No |
Field & Description |
1 |
sitemap_urls 要抓取指向网站地图的 URL 列表。 |
2 |
sitemap_rules 元组 (regex, callback)的列表,其中 regex 是正则表达式,而 callback 用于处理匹配正则表达式的 URL。 |
3 |
sitemap_follow 要遵循的网站地图正则表达式列表。 |
4 |
sitemap_alternate_links 指定要为单一网址遵循的备用链接。 |
SitemapSpider Example
以下 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 中网址为 /sitemap_company 的 sitemap。
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 - Selectors
Description
当您抓取网页时,您需要通过使用名为 selectors 的机制提取 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>
Constructing Selectors
您可以通过传递 text 或 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!!!']
Using Selectors
使用上述简单代码片段,您可以构建 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
Nesting Selectors
使用上述代码,您可以嵌套选择器,以使用 .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']
Selectors Using Regular Expressions
Scrapy 允许使用正则表达式提取数据,它使用 .re() 方法。从以上的 HTML 代码中,我们将提取图片名称,如下所示:
>>response.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
上面的行显示图片名称如下:
[u'Link 1',
u'Link 2',
u'Link 3']
Using Relative XPaths
当您使用 XPaths(它始于 / )时,嵌套选择器和 XPath 与文档的绝对路径相关,而不是选择器的相对路径。
如果您想提取 <p> 元素,首先获取所有 div 元素:
>>mydiv = response.xpath('//div')
接下来,您可以通过在 XPath 前加上一个点来提取里面的所有 'p' 元素,如下面的 .//p 所示:
>>for p in mydiv.xpath('.//p').extract()
Using EXSLT Extensions
EXSLT 是一个社区,它为 XSLT(可扩展样式表语言转换)发布扩展,它将 XML 文档转换为 XHTML 文档。您可以使用 XPath 表达式中注册的命名空间中的 EXSLT 扩展,如下表所示:
Sr.No |
Prefix & Usage |
Namespace |
1 |
re regular expressions |
|
2 |
set set manipulation |
您可以在上一部分检查使用正则表达式提取数据的简单代码格式。
在将 XPath 与 Scrapy 选择器一起使用时,有一些 XPath 技巧很有用。有关详细信息,请单击此 link 。
Scrapy - Items
Declaring Items
你可以使用类定义语法以及如下所示的字段对象来声明项目 -
import scrapy
class MyProducts(scrapy.Item):
productName = Field()
productLink = Field()
imageURL = Field()
price = Field()
size = Field()
Item Fields
项目字段用于显示每个字段的元数据。由于字段对象上的值没有限制,可访问的元数据键不会包含元数据的任何参考列表。字段对象用于指定所有字段元数据,你可以根据项目中的要求指定任何其他字段键。可以使用 Item.fields 属性访问字段对象。
Working with Items
在你使用项目时可以定义一些常见的函数。有关详细信息,请点击此处的 link 。
Extending Items
可以通过声明原始项目的子类来扩展项目。例如 -
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)
Scrapy - Item Loaders
Declaring Item Loaders
项目加载器的声明类似于项目。
例如 -
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 属性用于声明默认输入/输出处理器。
Using Item Loaders to Populate Items
要使用项目加载器,首先使用类字典对象实例化或没有类字典对象实例化项目,该项目使用 ItemLoader.default_item_class 属性中指定的项目类。
-
您可以使用选择器将值收集到项目加载器中。
-
您可以在相同项目的字段中添加更多值,此时项目加载器将使用合适的处理器来添加这些值。
以下代码展示使用项目加载器填充项目的的过程:
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() 方法抽取 title 域:
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() 方法抽取的数据的项目。
Input and Output Processors
项目加载器的每个域都包含一个输入处理器和一个输出处理器。
-
在抽取数据时,输入处理器对数据进行处理,其结果存储在 ItemLoader 中。
-
接下来,在收集完数据后,调用 ItemLoader.load_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]
Line 1 - 从 xpath1 抽取标题数据并传递通过输入处理器,然后收集其结果并存储在 ItemLoader 中。
Line 2 - 同样,从 xpath2 抽取标题并传递通过相同的输入处理器,然后将其结果添加到为 [1] 收集的数据中。
Line 3 - 从 css 选择器抽取标题并传递通过相同的输入处理器,然后将结果添加到为 [1] 和 [2] 收集的数据中。
Line 4 - 接下来,分配值“demo”并传递通过输入处理器。
Line 5 - 最后,从所有域内部收集数据并传递至输出处理器,最后的值分配给项目。
Declaring Input and Output Processors
输入和输出处理器在项目加载器的定义中声明。除此外,它们还可以 Item Field 元数据中指定。
例如 -
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'}
Item Loader Context
项目加载器上下文是 input 和 output 处理器共享的任意键值 dict。
例如,假设您具有函数 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 上下文。有几种方法可以更改 Item Loader 上下文的 value −
-
修改当前的活动 Item Loader 上下文 −
loader = ItemLoader (product)
loader.context ["unit"] = "mm"
-
在 Item Loader 实例化时 −
loader = ItemLoader(product, unit = "mm")
-
在 Item Loader 声名为输入/输出处理器时会实例化 Item Loader 上下文 −
class ProductLoader(ItemLoader):
length_out = MapCompose(parse_length, unit = "mm")
ItemLoader Objects
它是一个对象,返回一个 Item Loader,以填充给定的项目。它有以下类 −
class scrapy.loader.ItemLoader([item, selector, response, ]**kwargs)
下表显示 ItemLoader 对象的参数 −
Sr.No |
Parameter & Description |
1 |
item 它是通过调用 add_xpath()、add_css() 或 add_value() 填充的项目。 |
2 |
selector 用于从网站提取数据。 |
3 |
response 用于通过 default_selector_class 构建选择器。 |
下表显示 ItemLoader 对象的方法 −
Sr.No |
Method & Description |
Example |
1 |
get_value(value, *processors, **kwargs) 通过给定的处理器和关键字参数,值由 get_value() 方法处理。 |
>>> from scrapy.loader.processors import TakeFirst>>> loader.get_value(u’title: demoweb', TakeFirst(),unicode.upper, re = 'title: (.+)')'DEMOWEB` |
2 |
add_value(field_name, value, *processors, **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 |
replace_value(field_name, value, *processors, **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, *processors, **kwargs) 通过接收 XPath,通过提供处理器和关键字参数,用于提取 unicode 字符串。 |
= HTML 代码:<div class = "item-name">DVD</div>loader.get_xpath("//div[@class =[id="_html_code_div_id_lengththe_length_is"]= HTML 代码:<div id = "length">the length is45cm</div>loader.get_xpath("//div[@id = 'length']", TakeFirst(),re = "the length is (.*)") |
5 |
add_xpath(field_name, xpath, *processors, **kwargs) 它接收要提取 unicode 字符串的字段的 XPath。 |
= HTML 代码:<div class = "item-name">DVD</div> loader.add_xpath('name', '//div [id="_html_code_div_id_lengththe_length_is"] = HTML 代码:<div id = "length">the length is 45cm</div> loader.add_xpath('length', '//div[@id = "length"]', re = 'the length is (.*)') |
6 |
replace_xpath(field_name, xpath, *processors, **kwargs) 它使用 XPath 从网站中替换收集的数据。 |
= HTML 代码:<div class = "item-name">DVD</div> loader.replace_xpath('name', ' [id="_html_code_div_id_lengththe_length_is"] = HTML 代码:<div id = "length">the length is 45cm</div> loader.replace_xpath('length', ' |
7 |
get_css(css, *processors, **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, *processors, **kwargs) It is similar to add_value() method with one difference that it adds CSS selector to the field. |
loader.add_css('name', 'div.item-name') loader.add_css('length', 'div#length', re = 'the length is (.*)') |
9 |
replace_css(field_name, css, *processors, **kwargs) It replaces the extracted data using CSS selector. |
loader.replace_css('name', 'div.item-name') loader.replace_css('length', 'div#length', re = 'the length is (.*)') |
10 |
load_item() When the data is collected, this method fills the item with collected data and returns it. |
def parse(self, response): l = ItemLoader(item = Product(), response = response) l.add_xpath('title', '// div[@class = "product_title"]') loader.load_item() |
11 |
nested_xpath(xpath) It is used to create nested loaders with an XPath selector. |
loader = ItemLoader(item = Item()) loader.add_xpath('social', ' a[@class="social"]/@href') loader.add_xpath('email', ' a[@class="email"]/@href') |
12 |
nested_css(css) 它用于使用 CSS 选择器创建嵌套加载器。 |
loader = ItemLoader(item = Item()) loader.add_css('social', 'a[@class="social"]/@href') loader.add_css('email', 'a[@class="email"]/@href') |
下表显示了 ItemLoader 对象的属性:
Sr.No |
Attribute & Description |
1 |
item Item Loader 执行解析的对象。 |
2 |
context Item Loader 当前的活动上下文。 |
3 |
default_item_class 如果在构造函数中没有给出,它用于表示该项。 |
4 |
default_input_processor 未指定输入处理器的字段是唯一使用 default_input_processors 的字段。 |
5 |
default_output_processor 未指定输出处理器的字段是唯一使用 default_output_processors 的字段。 |
6 |
default_selector_class 这是用于构建选择器的类,如果在构造函数中未给出该类。 |
7 |
selector 这是一个可以用于从网站中提取数据的对象。 |
Nested Loaders
它用于在解析文档子部分中的值时创建嵌套加载器。如果你不创建嵌套加载器,你需要为要提取的每个值指定完整的 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()
Reusing and extending Item Loaders
项目加载器旨在减轻在项目获取更多爬虫时出现的维护问题。
例如,假设某个网站的产品名称包含三个破折号(例如 --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)
Available Built-in Processors
以下是常用的内置处理器 −
class scrapy.loader.processors.Identity
它返回原始值而不做任何更改。例如 −
>>> from scrapy.loader.processors import Identity
>>> proc = Identity()
>>> proc(['a', 'b', 'c'])
['a', 'b', 'c']
class scrapy.loader.processors.TakeFirst
它从接收值列表中返回第一个非空/非空值。例如 −
>>> from scrapy.loader.processors import TakeFirst
>>> proc = TakeFirst()
>>> proc(['', 'a', 'b', 'c'])
'a'
class 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'
class scrapy.loader.processors.Compose(*functions, **default_loader_context)
它由一个处理器定义,其中它的每个输入值都传递到第一个函数,该函数的结果传递到第二个函数,依此类推,直到最后函数返回最终值作为输出。
例如 -
>>> from scrapy.loader.processors import Compose
>>> proc = Compose(lambda v: v[0], str.upper)
>>> proc(['python', 'scrapy'])
'PYTHON'
class 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']
class 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 - Shell
Description
Scrapy shell 可用于使用无错误的代码来抓取数据,而无需使用爬虫。Scrapy shell 的主要目的是测试已提取的代码、XPath 或 CSS 表达式。它还有助于指定您要从中抓取数据的网页。
Configuring the Shell
可以通过安装 IPython (用于交互式计算)控制台来配置 shell,这是一个功能强大的交互式 shell,它提供了自动完成、着色输出等功能。
如果您在 Unix 平台上工作,那么最好安装 IPython。如果 IPython 不可访问,您还可以使用 bpython 。
您可以通过设置名为 SCRAPY_PYTHON_SHELL 的环境变量或按如下方式定义 scrapy.cfg 文件来配置 shell:
[settings]
shell = bpython
Using the Shell
shell 提供一些附加快捷方式和 Scrapy 对象,如下表所述:
Available Shortcuts
shell 在项目中提供了以下可用快捷方式:
Sr.No |
Shortcut & Description |
1 |
shelp() 它通过帮助选项提供了可用的对象和快捷方式。 |
2 |
fetch(request_or_url) 它收集来自请求或网址的响应,并且关联的对象会被恰当地更新。 |
3 |
view(response) 您可以在浏览器的本地浏览器中查看给定请求的响应以进行观察,并且为了正确地显示外部链接,它会追加一个基础标记到响应体。 |
Available Scrapy Objects
Shell 在 project 中提供了以下可用的 Scrapy 对象 −
Sr.No |
Object & Description |
1 |
crawler 它指定了当前的爬虫对象。 |
2 |
spider 如果没有当前网址的爬虫,那么它将通过定义新的爬虫来处理网址或爬虫对象。 |
3 |
request 它指定了最后一个收集页面的请求对象。 |
4 |
response 它指定了最后一个收集页面的响应对象。 |
5 |
settings 它提供了当前的 Scrapy 设置。 |
Example of Shell Session
让我们尝试爬取 scrapy.org 网站,然后按照说明开始从 reddit.com 爬取数据。
在继续之前,首先我们将按照以下命令启动 shell −
scrapy shell 'http://scrapy.org' --nolog
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
...
Invoking the Shell from Spiders to Inspect Responses
只有当您希望获取该响应时,您才能检查从爬虫处理的响应。
例如 −
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 - Item Pipeline
Description
Item Pipeline 是一种对收集到的项目进行处理的方法。当一个项目被发送到项目管道时,它会被一个爬虫程序抓取出来,然后使用几个按顺序执行的组件进行处理。
每当接收到一个项目时,就会决定采取以下两种操作之一 −
-
Keep processing the item.
-
Drop it from pipeline.
-
Stop processing the item.
项目管道通常用于以下目的 −
-
将抓取到的项目存储在数据库中。
-
如果接收到的项目是一个重复的项目,那它会将重复的项目删除。
-
它将检查该项目是否带有目标字段。
-
Clearing HTML data.
Syntax
您可以使用以下方法编写项目管道 −
process_item(self, item, spider)
上述方法包含以下参数 −
-
Item (Item 对象或字典)- 它指定要抓取的 Item。
-
spider (spider 对象)- 发送该 Item 的 spider。
你也可以使用下表中给出的各种方法-
Sr.No |
Method & Description |
Parameters |
1 |
open_spider(self, spider) 当 spider 被打开时选择它。 |
spider(spider 对象)- 它指被打开的 spider。 |
2 |
close_spider(self, spider) 当 spider 被关闭时选择它。 |
spider (spider 对象)- 它指被关闭的 spider。 |
3 |
from_crawler(cls, crawler) 借助 crawler, 该管道可以访问 Scrapy 的核心组件,如信号和设定。 |
crawler (Crawler 对象)- 它指使用此管道的 crawler。 |
Example
以下是用于不同概念的 Item 管道的范例。
Dropping Items with No Tag
在以下代码中,管道平衡了那些不包含增值税(excludes_vat 属性)的 Item 的(price)属性并忽略不带价签的 Item.-
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)
Writing Items to a JSON File
以下代码将把所有 spider 抓取的所有 Item 存储到单个 items.jl 文件中,其中包含每个以 JSON 格式序列化的行里的一个 Item。 JsonWriterPipeline 类在代码中用于展示如何编写 Item 管道-
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
Writing Items to MongoDB
你可以在 Scrapy 设置中指定 MongoDB 地址和数据库名称,并且 MongoDB 集合可以以 Item 类命名。以下代码描述了如何正确使用 from_crawler() 方法来收集资源-
import pymongo
class MongoPipeline(object):
collection_name = 'Scrapy_list'
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri = crawler.settings.get('MONGO_URI'),
mongo_db = crawler.settings.get('MONGO_DB', 'lists')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
self.db[self.collection_name].insert(dict(item))
return item
Duplicating Filters
过滤器会检查重复的 Item, 并且会删除已经处理的 Item。在以下代码中,我们为我们的 Item 已经使用一个唯一的 id, 但是 spider 返回了多个带有相同 id 的 Item -
from scrapy.exceptions import DropItem
class DuplicatesPipeline(object):
def __init__(self):
self.ids_seen = set()
def process_item(self, item, spider):
if item['id'] in self.ids_seen:
raise DropItem("Repeated items found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item
Scrapy - Feed exports
Serialization Formats
通过使用多种序列化格式和存储后端,数据提要导出可使用项目导出器并根据抓取的项目生成提要。
下表展示受支持的格式:
Sr.No |
Format & Description |
1 |
JSON FEED_FORMAT 为 jsonExporter 使用的是 scrapy.exporters.JsonItemExporter 类 |
2 |
JSON lines FEED_FROMAT 为 jsonlinesExporter 使用的是 scrapy.exporters.JsonLinesItemExporter 类 |
3 |
CSV FEED_FORMAT 为 CSVExporter 使用的是 scrapy.exporters.CsvItemExporter 类 |
4 |
XML FEED_FORMAT 为 xmlExporter 使用的是 scrapy.exporters.XmlItemExporter 类 |
通过使用 FEED_EXPORTERS 设置,受支持的格式还可以得到扩展 −
Sr.No |
Format & Description |
1 |
Pickle FEED_FORMAT 为 pickelExporter 使用的是 scrapy.exporters.PickleItemExporter 类 |
2 |
Marshal FEED_FORMAT 为 marshalExporter 使用的是 scrapy.exporters.MarshalItemExporter 类 |
Storage Backends
存储后端定义了在何处存储使用 URI 的数据提要。
下表展示了受支持的存储后端 −
Sr.No |
Storage Backend & Description |
1 |
Local filesystem URI 方案为 file,它用于存储数据提要。 |
2 |
FTP URI 方案为 ftp,它用于存储数据提要。 |
3 |
|
4 |
Standard output URI 方案为 stdout 数据提要存储在标准输出。 |
Settings
下表显示了用于配置 Feed 导出的设置:
Sr.No |
Setting & Description |
1 |
FEED_URI 这是用于启用 Feed 导出的导出 Feed 的 URI。 |
2 |
FEED_FORMAT 这是用于 Feed 的序列化格式。 |
3 |
FEED_EXPORT_FIELDS 用于定义需要导出的字段。 |
4 |
FEED_STORE_EMPTY 它定义是否导出没有项目的 Feed。 |
5 |
FEED_STORAGES 它是一个具有其他 Feed 存储后端的字典。 |
6 |
FEED_STORAGES_BASE 它是一个具有内置 Feed 存储后端的字典。 |
7 |
FEED_EXPORTERS 它是一个具有其他 Feed 导出的字典。 |
8 |
FEED_EXPORTERS_BASE 它是一个具有内置 Feed 导出的字典。 |
Scrapy - Requests and Responses
Request Objects
请求对象是一个生成响应的 HTTP 请求。它具有以下类:
class scrapy.http.Request(url[, callback, method = 'GET', headers, body, cookies, meta,
encoding = 'utf-8', priority = 0, dont_filter = False, errback])
下表显示请求对象的各个参数:
Sr.No |
Parameter & Description |
1 |
url 是一个指定 URL 请求的字符串。 |
2 |
callback 是一个可调用函数,该函数将请求的响应用作第一个参数。 |
3 |
method 是一个指定 HTTP 方法请求的字符串。 |
4 |
headers 是一个具有请求头部的词典。 |
5 |
body 是一个具有请求正文的字符串或 unicode。 |
6 |
cookies 是一个包含请求 cookie 的列表。 |
7 |
meta 是一个包含请求元数据值的词典。 |
8 |
encoding 是一个包含用于对 URL 编码的 utf-8 编码的字符串。 |
9 |
priority 是一个整型,其中调度程序使用优先级来定义处理请求的顺序。 |
10 |
dont_filter 是一个布尔值,指定调度程序不得过滤该请求。 |
11 |
errback 是一个可调用函数,在处理请求时引发异常时调用。 |
Passing Additional Data to Callback Functions
请求的回调函数在以其第一个参数下载响应时调用。
例如 -
def parse_page1(self, response):
return scrapy.Request("http://www.something.com/some_page.html",
callback = self.parse_page2)
def parse_page2(self, response):
self.logger.info("%s page visited", response.url)
如果您想要将参数传递给可调用函数并在第二个回调中接收这些参数,则可以使用 Request.meta 属性,如下例所示:
def parse_page1(self, response):
item = DemoItem()
item['foremost_link'] = response.url
request = scrapy.Request("http://www.something.com/some_page.html",
callback = self.parse_page2)
request.meta['item'] = item
return request
def parse_page2(self, response):
item = response.meta['item']
item['other_link'] = response.url
return item
Using errbacks to Catch Exceptions in Request Processing
当在处理请求时引发异常时,调用 errback 函数。
以下示例演示了这一点−
import scrapy
from scrapy.spidermiddlewares.httperror import HttpError
from twisted.internet.error import DNSLookupError
from twisted.internet.error import TimeoutError, TCPTimedOutError
class DemoSpider(scrapy.Spider):
name = "demo"
start_urls = [
"http://www.httpbin.org/", # HTTP 200 expected
"http://www.httpbin.org/status/404", # Webpage not found
"http://www.httpbin.org/status/500", # Internal server error
"http://www.httpbin.org:12345/", # timeout expected
"http://www.httphttpbinbin.org/", # DNS error expected
]
def start_requests(self):
for u in self.start_urls:
yield scrapy.Request(u, callback = self.parse_httpbin,
errback = self.errback_httpbin,
dont_filter=True)
def parse_httpbin(self, response):
self.logger.info('Recieved response from {}'.format(response.url))
# ...
def errback_httpbin(self, failure):
# logs failures
self.logger.error(repr(failure))
if failure.check(HttpError):
response = failure.value.response
self.logger.error("HttpError occurred on %s", response.url)
elif failure.check(DNSLookupError):
request = failure.request
self.logger.error("DNSLookupError occurred on %s", request.url)
elif failure.check(TimeoutError, TCPTimedOutError):
request = failure.request
self.logger.error("TimeoutError occurred on %s", request.url)
Request.meta Special Keys
request.meta 特殊键是 Scrapy 识别的特殊 meta 键列表。
下表显示 Request.meta 的一些键:
Sr.No |
Key & Description |
1 |
dont_redirect 当设置为 true 时,这是一个关键,不依据响应的状态重新定向请求。 |
2 |
dont_retry 当设置为 true 时,这是一个关键,不会重试失败的请求,并且会被中间件忽略。 |
3 |
handle_httpstatus_list 这是一个定义每个请求基础允许哪些响应代码的关键。 |
4 |
handle_httpstatus_all 这是一个关键,用于通过将其设置为 true 来允许任何请求响应代码。 |
5 |
dont_merge_cookies 这是一个关键,用于通过将其设置为 true 来避免与现有 cookie 合并。 |
6 |
cookiejar 这是一个关键,用于为每个蜘蛛保持多个 cookie 会话。 |
7 |
dont_cache 这是一个关键,用于避免在每个策略上缓存 HTTP 请求和响应。 |
8 |
redirect_urls 这是一个关键,包含请求通过的 URL。 |
9 |
bindaddress 这是可用于执行请求的传出 IP 地址的 IP。 |
10 |
dont_obey_robotstxt 当设置为 true 时,这是一个关键,即使启用了 ROBOTSTXT_OBEY,也不会过滤 robots.txt 排除标准禁止的请求。 |
11 |
download_timeout 它用于为每个蜘蛛设置超时(以秒为单位),下载器将在超时之前等待此超时。 |
12 |
download_maxsize 它用于为每个蜘蛛设置最大大小(以字节为单位),这是下载器将下载的大小。 |
13 |
可以针对 Request 对象设置代理,以将 HTTP 代理设置为用于请求。 |
Request Subclasses
你可以通过对 request 类进行子类化来实现自己的自定义功能。内置请求子类如下 −
FormRequest Objects
FormRequest 类通过扩展基本请求来处理 HTML 表单。它具有以下类 −
class scrapy.http.FormRequest(url[,formdata, callback, method = 'GET', headers, body,
cookies, meta, encoding = 'utf-8', priority = 0, dont_filter = False, errback])
以下是参数 −
formdata − 这是一个具有 HTML 表单数据的字典,该字典被分配给请求正文。
Note − 其余参数与 request 类相同,并在 Request Objects 部分中进行了说明。
除了请求方法之外, FormRequest 对象还支持以下类方法 −
classmethod from_response(response[, formname = None, formnumber = 0, formdata = None,
formxpath = None, formcss = None, clickdata = None, dont_click = False, ...])
下表显示了上面类的参数 -
Sr.No |
Parameter & Description |
1 |
response 这是一个用于使用 HTML 表单响应预先填充表单字段的对象。 |
2 |
formname 如果指定,这是一个将使用名称属性的表单的字符串。 |
3 |
formnumber 当响应中有多个表单时,这是一个要使用的表单的整数。 |
4 |
formdata 这是一个用于覆盖的表单数据字段的字典。 |
5 |
formxpath 当指定时,这是使用 xpath 匹配的表单。 |
6 |
formcss 当指定时,这是使用 css 选择器匹配的表单。 |
7 |
clickdata 这是一个用于观察已单击控件的属性字典。 |
8 |
dont_click 当设置为 true 时,表单中的数据将被提交且不会单击任何元素。 |
Examples
以下是部分请求用例 -
Using FormRequest to send data via HTTP POST
下面的代码演示了在蜘蛛中重复 HTML 表单 POST 时,如何返回 FormRequest 对象 -
return [FormRequest(url = "http://www.something.com/post/action",
formdata = {'firstname': 'John', 'lastname': 'dave'},
callback = self.after_post)]
Using FormRequest.from_response() to simulate a user login
通常,网站使用元素通过它们提供预先填充的表单字段。
当你希望这些字段在抓取时自动填充时,可以使用 FormRequest.form_response() 方法。
以下示例演示了这一点。
import scrapy
class DemoSpider(scrapy.Spider):
name = 'demo'
start_urls = ['http://www.something.com/users/login.php']
def parse(self, response):
return scrapy.FormRequest.from_response(
response,
formdata = {'username': 'admin', 'password': 'confidential'},
callback = self.after_login
)
def after_login(self, response):
if "authentication failed" in response.body:
self.logger.error("Login failed")
return
# You can continue scraping here
Response Objects
这是一个表征 HTTP 响应的对象,它被输入到需要处理的爬虫中。它有以下类 -
class scrapy.http.Response(url[, status = 200, headers, body, flags])
下表显示了响应对象的参数 -
Sr.No |
Parameter & Description |
1 |
url 这是一个指定 URL 响应字符串。 |
2 |
status 这是一个包含 HTTP 状态响应的整数。 |
3 |
headers 这是包含响应头的字典。 |
4 |
body 这是一个包含响应体的字符串。 |
5 |
flags 这是一个包含响应标志的列表。 |
Response Subclasses
你可以通过对响应类进行子类化来实现你自定义的功能。内置的响应子类如下:
TextResponse objects
TextResponse 对象被用于二进制数据,例如图像、声音等,它有能力编码基本的响应类。它包含以下类:
class scrapy.http.TextResponse(url[, encoding[,status = 200, headers, body, flags]])
以下是参数 −
encoding − 这是一个用于对响应进行编码的字符串。
Note − 剩余的参数与响应类相同,在 Response Objects 部分中对其进行了说明。
下表显示了 TextResponse 对象在响应方法之外支持的属性:
Sr.No |
Attribute & Description |
1 |
text 这是一个响应体,可以多次访问 response.text。 |
2 |
encoding 这是一个包含用于响应的编码的字符串。 |
3 |
selector 这是一个在首次访问时实例化的属性,并且使用响应作为目标。 |
下表显示了 TextResponse 对象在响应方法之外支持的方法:
Sr.No |
Method & Description |
1 |
xpath (query) 这是一个指向 TextResponse.selector.xpath(query) 的捷径。 |
2 |
css (query) 这是一个指向 TextResponse.selector.css(query) 的捷径。 |
3 |
body_as_unicode() 这是一个响应体,可以作为一种方法进行访问,在其中可以多次访问 response.text。 |
Scrapy - Link Extractors
Description
顾名思义,链接提取器是可以用于使用 scrapy.http.Response 对象从网页中提取链接的对象。在 Scrapy 中,有内建的提取器,例如 scrapy.linkextractors 导入 LinkExtractor 。您可以通过实现简单界面根据需要自定义您自己的链接提取器。
每个链接提取器都有一个称为 extract_links 的公共方法,它包括一个 Response 对象并返回一个 scrapy.link.Link 对象列表。您只能实例化链接提取器一次,并多次调用 extract_links 方法以使用不同的响应来提取链接。CrawlSpiderclass 使用链接提取器和一组规则,其主要目的是提取链接。
Built-in Link Extractor’s Reference
通常,链接提取器与 Scrapy 一起分组,并在 scrapy.linkextractors 模块中提供。默认情况下,链接提取器将是 LinkExtractor,其功能与 LxmlLinkExtractor 相同 −
from scrapy.linkextractors import LinkExtractor
LxmlLinkExtractor
class scrapy.linkextractors.lxmlhtml.LxmlLinkExtractor(allow = (), deny = (),
allow_domains = (), deny_domains = (), deny_extensions = None, restrict_xpaths = (),
restrict_css = (), tags = ('a', 'area'), attrs = ('href', ),
canonicalize = True, unique = True, process_value = None)
LxmlLinkExtractor 是一个强烈推荐的链接提取器,因为它具有方便的过滤选项,并且与 lxml 的强大 HTMLParser 一起使用。
Sr.No |
Parameter & Description |
1 |
allow (正则表达式(或列表))它允许一个单个表达式或表达式组与要提取的 url 匹配。如果未提及,它将匹配所有链接。 |
2 |
deny (正则表达式(或列表))它阻止或排除与不应提取的 url 匹配的一个表达式或表达式组。如果未提及或留空,则不会消除不需要的链接。 |
3 |
allow_domains (str 或列表)它允许一个单个字符串或字符串列表与要从中提取链接的域名匹配。 |
4 |
deny_domains (str 或列表)它阻止或排除与不应从中提取链接的域名匹配的一个单个字符串或字符串列表。 |
5 |
deny_extensions (列表)在提取链接时,它会阻止带有扩展名的字符串列表。如果未设置,则默认设置为 IGNORED_EXTENSIONS,其中包含 scrapy.linkextractors 包中预定义的列表。 |
6 |
restrict_xpaths (str 或列表)它是 XPath 列表区域,从中提取链接的响应。如果给出,链接将仅从由 XPath 选定的文本中提取。 |
7 |
restrict_css (str 或列表)它的行为类似于 restrict_xpaths 参数,该参数将从响应中 CSS 选定的区域中提取链接。 |
8 |
tags (str 或列表)在提取链接时应考虑的单个标签或标签列表。默认情况下,它将为 (’a’, ’area’)。 |
9 |
attrs (列表)在提取链接时应考虑一个单个属性或属性列表。默认情况下,它将为 (’href’,)。 |
10 |
canonicalize (布尔值)使用 scrapy.utils.url.canonicalize_url 将提取的 url 转换成标准形式。默认情况下,它将为 True。 |
11 |
unique (布尔型)如果提取的链接重复,此布尔型将被使用。 |
12 |
process_value (可调用)这是一个接收从扫描标签和属性中获取的值的函数。获取的值可被更改并返回,否则将不会返回任何内容以拒绝链接。如果未被使用,则默认值为 lambda x: x。 |
Scrapy - Settings
Designating the Settings
当你抓取网站时,你必须通知 Scrapy 你正在使用哪些设置。为此,应该使用环境变量 SCRAPY_SETTINGS_MODULE ,其值应为 Python 路径语法。
Populating the Settings
下表显示了一些可以填充设置的机制−
Sr.No |
Mechanism & Description |
1 |
Command line options 此处,传递的参数优先级最高,覆盖其他选项。 -s 用于覆盖一个或多个设置。scrapy crawl myspider -s LOG_FILE = scrapy.log |
2 |
Settings per-spider 通过使用属性 custom_settings,Spider 可以具有自己的设置,从而覆盖 project 设置。class DemoSpider(scrapy.Spider): name = 'demo' custom_settings = { 'SOME_SETTING': 'some value', } |
3 |
Project settings module 此处,您可以填充自定义设置,例如在 settings.py 文件中添加或修改设置。 |
4 |
Default settings per-command 每个 Scrapy 工具命令在 default_settings 属性中定义其自己的设置,以覆盖全局默认设置。 |
5 |
Default global settings 这些设置可在 scrapy.settings.default_settings 模块中找到。 |
Access Settings
它们可通过 self.settings 获得,并在初始化后设置在基础 Spider 中。
以下示例演示了这一点。
class DemoSpider(scrapy.Spider):
name = 'demo'
start_urls = ['http://example.com']
def parse(self, response):
print("Existing settings: %s" % self.settings.attributes.keys())
要在初始化 Spider 之前使用设置,您必须在 Spider 的 init () 方法中覆盖 from_crawler 方法。您可以通过传递给 from_crawler 方法的属性 scrapy.crawler.Crawler.settings 访问设置。
以下示例演示了这一点。
class MyExtension(object):
def __init__(self, log_is_enabled = False):
if log_is_enabled:
print("Enabled log")
@classmethod
def from_crawler(cls, crawler):
settings = crawler.settings
return cls(settings.getbool('LOG_ENABLED'))
Rationale for Setting Names
设置名称被添加为它们配置的组件的前缀。例如,对于 robots.txt 扩展,设置名称可以是 ROBOTSTXT_ENABLED、 ROBOTSTXT_OBEY、ROBOTSTXT_CACHEDIR 等。
Built-in Settings Reference
下表显示了 Scrapy 的内置设置−
Sr.No |
Setting & Description |
1 |
AWS_ACCESS_KEY_ID 用于访问 Amazon Web 服务。默认值:无 |
2 |
AWS_SECRET_ACCESS_KEY 用于访问 Amazon Web 服务。默认值:无 |
3 |
BOT_NAME 可以用于构造 User-Agent 的 bot 名称。默认值:'scrapybot' |
4 |
CONCURRENT_ITEMS Item Processor 中用于并行处理的现有项的最大数量。默认值:100 |
5 |
CONCURRENT_REQUESTS Scrapy 下载器执行的现有请求的最大数量。默认值:16 |
6 |
CONCURRENT_REQUESTS_PER_DOMAIN 同时对任何单个域执行的现有请求的最大数量。默认值:8 |
7 |
CONCURRENT_REQUESTS_PER_IP 同时对任何单个 IP 执行的现有请求的最大数量。默认值:0 |
8 |
DEFAULT_ITEM_CLASS 用于表示项的类。默认值:'scrapy.item.Item' |
9 |
DEFAULT_REQUEST_HEADERS 用于 Scrapy 的 HTTP 请求的默认标头。默认值 −{ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9, / ;q=0.8', 'Accept-Language': 'en',} |
10 |
DEPTH_LIMIT 蜘蛛爬取任何站点的最大深度。默认值: 0 |
11 |
DEPTH_PRIORITY 用于根据深度调整请求优先级的整数。默认值: 0 |
12 |
DEPTH_STATS 表示是否收集深度统计信息。默认值: True |
13 |
DEPTH_STATS_VERBOSE 当启用此设置时,将为每个详细深度收集统计信息中的请求数量。默认值: False |
14 |
DNSCACHE_ENABLED 用于在内存缓存中启用 DNS。默认值: True |
15 |
DNSCACHE_SIZE 定义内存缓存中 DNS 的大小。默认值: 10000 |
16 |
DNS_TIMEOUT 用于设置处理查询的 DNS 超时。默认值: 60 |
17 |
DOWNLOADER 用于爬行过程的下载器。默认值: "scrapy.core.downloader.Downloader" |
18 |
DOWNLOADER_MIDDLEWARES 保存下载器中间件及其顺序的字典。默认值: {} |
19 |
DOWNLOADER_MIDDLEWARES_BASE 保存默认启用下载器中间件的字典。默认值 −{ "scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware": 100, } |
20 |
DOWNLOADER_STATS 此设置用于启用下载器统计信息。默认值: True |
21 |
DOWNLOAD_DELAY 定义下载器从站点下载页面之前的时间总数。默认值: 0 |
22 |
DOWNLOAD_HANDLERS 含下载处理程序的字典。默认值: {} |
23 |
DOWNLOAD_HANDLERS_BASE 是包含默认启用的下载处理程序的字典。默认值 −{ "file": "scrapy.core.downloader.handlers.file.FileDownloadHandler", } |
24 |
DOWNLOAD_TIMEOUT 是下载器在超时之前等待的总时间。默认值: 180 |
25 |
DOWNLOAD_MAXSIZE 是下载器要下载的响应的最大值。默认值: 1073741824 (1024MB) |
26 |
DOWNLOAD_WARNSIZE 定义下载器发出警告的响应大小。默认值: 33554432 (32MB) |
27 |
DUPEFILTER_CLASS 用于检测和筛选重复请求的类。默认值: "scrapy.dupefilters.RFPDupeFilter" |
28 |
DUPEFILTER_DEBUG 将所有重复过滤器记录在这项设置为 true 时。默认值: False |
29 |
EDITOR 它用于使用编辑命令编辑爬虫。默认值:取决于环境 |
30 |
EXTENSIONS 这是一个包含在项目中启用的扩展的字典。默认值:{} |
31 |
EXTENSIONS_BASE 这是一个包含内置扩展的字典。默认值:{ 'scrapy.extensions.corestats.CoreStats': 0, } |
32 |
FEED_TEMPDIR 这是一个目录,用于设置自定义文件夹,其中可以存储爬虫临时文件。 |
33 |
ITEM_PIPELINES 这是一个包含管道的字典。默认值:{} |
34 |
LOG_ENABLED 它定义是否启用日志记录。默认值:True |
35 |
LOG_ENCODING 它定义用于日志记录的编码类型。默认值:'utf-8' |
36 |
LOG_FILE 这是用于日志记录输出的文件的名称。默认值:None |
37 |
LOG_FORMAT 它是一个字符串,可用于设置日志消息格式。默认值:'%(asctime)s [%(name)s] %(levelname)s: %(message)s' |
38 |
LOG_DATEFORMAT 这是一个字符串,可用于设置日期/时间格式。默认值:'%Y-%m-%d %H:%M:%S' |
39 |
LOG_LEVEL 它定义最小日志级别。默认值:'DEBUG' |
40 |
LOG_STDOUT 如果此设置设为 true,则所有进程输出将显示在日志中。默认值:False |
41 |
MEMDEBUG_ENABLED 它定义是否启用内存调试。默认值:False |
42 |
MEMDEBUG_NOTIFY 它定义在启用内存调试时发送到特定地址的内存报告。默认值:[] |
43 |
MEMUSAGE_ENABLED 它定义当 Scrapy 进程超过内存限制时是否启用内存使用。默认值:False |
44 |
MEMUSAGE_LIMIT_MB 它定义允许的最大内存限制(以兆字节为单位)。默认值:0 |
45 |
MEMUSAGE_CHECK_INTERVAL_SECONDS 它用于通过设置间隔长度检查当前的内存使用情况。默认值:60.0 |
46 |
MEMUSAGE_NOTIFY_MAIL 它用于在内存达到限制时通过电子邮件列表进行通知。默认值:False |
47 |
MEMUSAGE_REPORT 它定义在关闭每个爬虫时是否发送内存使用情况报告。默认值:False |
48 |
MEMUSAGE_WARNING_MB 在发出警告之前,它定义了允许的总内存。默认值:0 |
49 |
NEWSPIDER_MODULE 它是一个使用 genspider 命令创建新蜘蛛的模块。默认值:'' |
50 |
RANDOMIZE_DOWNLOAD_DELAY 它定义了 Scrapy 在从网站下载请求时等待的随机时间量。默认值:True |
51 |
REACTOR_THREADPOOL_MAXSIZE 它定义了反应堆线程池的最大大小。默认值:10 |
52 |
REDIRECT_MAX_TIMES 它定义了请求可以被重定向的次数。默认值:20 |
53 |
REDIRECT_PRIORITY_ADJUST 设置此设置时,调整请求的重定向优先级。默认值:+2 |
54 |
RETRY_PRIORITY_ADJUST 设置此设置时,调整请求的重试优先级。默认值:-1 |
55 |
ROBOTSTXT_OBEY 当设置为 true 时,Scrapy 遵守 robots.txt 策略。默认值:False |
56 |
SCHEDULER 它定义了用于爬网目的的调度程序。默认值:'scrapy.core.scheduler.Scheduler' |
57 |
SPIDER_CONTRACTS 它是项目中的一个字典,其中包含要测试蜘蛛的蜘蛛合同。默认值:{} |
58 |
SPIDER_CONTRACTS_BASE 它是一个包含 Scrapy 合同的字典,默认情况下在 Scrapy 中启用。默认值 −{ 'scrapy.contracts.default.UrlContract' : 1, 'scrapy.contracts.default.ReturnsContract': 2,} |
59 |
SPIDER_LOADER_CLASS 它定义了一个实现 SpiderLoader API 以加载蜘蛛的类。默认值:'scrapy.spiderloader.SpiderLoader' |
60 |
SPIDER_MIDDLEWARES 它是一个包含蜘蛛中间件的字典。默认值:{} |
61 |
SPIDER_MIDDLEWARES_BASE 它是一个包含默认情况下在 Scrapy 中启用的蜘蛛中间件的字典。默认值 −{ 'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': 50,} |
62 |
SPIDER_MODULES 它是一个包含 Scrapy 将查找的包含蜘蛛的模块的列表。默认值:[] |
63 |
STATS_CLASS 它是一个实现统计收集器 API 以收集统计信息的类。默认值:'scrapy.statscollectors.MemoryStatsCollector' |
64 |
STATS_DUMP 当此设置设置为 true 时,将统计信息转储到日志中。默认值:True |
65 |
STATSMAILER_RCPTS 在蜘蛛完成抓取后,Scrapy 使用此设置发送统计信息。默认值:[] |
66 |
TELNETCONSOLE_ENABLED 它定义了是否启用 telnet 控制台。默认值:True |
67 |
TELNETCONSOLE_PORT 它为 telnet 控制台定义了一个端口。默认值:[6023, 6073] |
68 |
TEMPLATES_DIR 它是一个包含模板的目录,这些模板可在创建新项目时使用。默认值:scrapy 模块内部的 templates 目录 |
69 |
URLLENGTH_LIMIT 它定义允许爬取 URL 的 URL 长度最大限制。默认值:2083 |
70 |
USER_AGENT 它定义在爬取网站时要使用的 user agent。默认值:"Scrapy/VERSION (+http://scrapy.org)" |
有关其他 Scrapy 设置,请访问此 link 。
Scrapy - Exceptions
CloseSpider
此异常用于停止使用回调请求的蜘蛛。它可以写成−
exception (scrapy.exceptions.CloseSpider)(reason = 'cancelled')
它包含一个名为原因 (str) 的参数,该参数指定关闭的原因。
例如,以下代码显示了此异常用法−
def parse_page(self, response):
if 'Bandwidth exceeded' in response.body:
raise CloseSpider('bandwidth_exceeded')
Scrapy - Create a Project
Description
要从网页中获取数据,首先需要创建你将存储代码的 Scrapy 项目。要创建新目录,运行以下命令:
scrapy startproject first_scrapy
上面的代码将创建一个名为 first_scrapy 的目录,它将包含以下结构:
first_scrapy/
scrapy.cfg # deploy configuration file
first_scrapy/ # project's Python module, you'll import your code from here
__init__.py
items.py # project items file
pipelines.py # project pipelines file
settings.py # project settings file
spiders/ # a directory where you'll later put your spiders
__init__.py
Scrapy - Define an Item
Description
项目是用于收集从网站获取的数据的容器。你必须通过定义你的项目来启动你的爬虫。要定义项目,编辑在目录 first_scrapy 下找到的 items.py 文件(自定义目录)。items.py 看起来如下:
import scrapy
class First_scrapyItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
MyItem 类继承了包含一系列 Scrapy 已经为我们构建的预定义对象的 Item。例如,如果你想从站点中提取名称、URL 和描述,则需要为这三个属性中的每一个定义字段。
因此,让我们添加我们要收集的那些项目:
from scrapy.item import Item, Field
class First_scrapyItem(scrapy.Item):
name = scrapy.Field()
url = scrapy.Field()
desc = scrapy.Field()
Scrapy - First Spider
Description
Spider 是一个类,它定义了从哪里提取数据的初始 URL,以及如何遵循分页链接以及如何提取和解析 items.py 中定义的字段。Scrapy 提供不同类型的蜘蛛,每种蜘蛛都给出了一个特定目的。
在 first_scrapy/spiders 目录下创建一个名为 "first_spider.py" 的文件,在那里我们可以告诉 Scrapy 如何找到我们正在寻找的确切数据。为此,你必须定义一些属性:
-
name - 它定义了蜘蛛的唯一名称。
-
allowed_domains - 它包含蜘蛛要爬取的基本 URL。
-
start-urls − 蜘蛛开始爬行的 URL 列表。
-
parse() − 它是用来提取和解析所爬取数据的函数。
以下代码演示了一个爬虫代码的样例 −
import scrapy
class firstSpider(scrapy.Spider):
name = "first"
allowed_domains = ["dmoz.org"]
start_urls = [
"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
"http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
]
def parse(self, response):
filename = response.url.split("/")[-2] + '.html'
with open(filename, 'wb') as f:
f.write(response.body)
Scrapy - Crawling
Description
要执行你的爬虫程序,在 first_scrapy 目录中运行以下命令 −
scrapy crawl first
其中, first 是创建爬虫程序时指定的爬虫程序名称。
爬虫程序爬取后,可以看到以下输出 −
2016-08-09 18:13:07-0400 [scrapy] INFO: Scrapy started (bot: tutorial)
2016-08-09 18:13:07-0400 [scrapy] INFO: Optional features available: ...
2016-08-09 18:13:07-0400 [scrapy] INFO: Overridden settings: {}
2016-08-09 18:13:07-0400 [scrapy] INFO: Enabled extensions: ...
2016-08-09 18:13:07-0400 [scrapy] INFO: Enabled downloader middlewares: ...
2016-08-09 18:13:07-0400 [scrapy] INFO: Enabled spider middlewares: ...
2016-08-09 18:13:07-0400 [scrapy] INFO: Enabled item pipelines: ...
2016-08-09 18:13:07-0400 [scrapy] INFO: Spider opened
2016-08-09 18:13:08-0400 [scrapy] DEBUG: Crawled (200)
<GET http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> (referer: None)
2016-08-09 18:13:09-0400 [scrapy] DEBUG: Crawled (200)
<GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> (referer: None)
2016-08-09 18:13:09-0400 [scrapy] INFO: Closing spider (finished)
正如你可以在输出中看到的,对于每个 URL 都有一个日志行,该日志行(引用:无)指出 URL 是开始 URL,并且它们没有引用。接下来,你应该看到在 first_scrapy 目录中创建了两个新文件,命名为 Books.html 和 Resources.html。
Scrapy - Extracting Items
Description
-
/html/head/title − 这将选择 HTML 文档的 <head> 元素内的 <title> 元素。
-
/html/head/title/text() − 这将选择同一个 <title> 元素内的文本。
-
//td − 这将选择所有来自 <td> 的元素。
-
//div[@class = "slice"] − 这将选择所有来自 div 的元素,其中包含属性 class = "slice"
选择器有四个基本的方法,如下表所示 −
Sr.No |
Method & Description |
1 |
extract() 它返回一个 unicode 字符串和选择的数据。 |
2 |
re() 返回 unicode 字符串列表,当提供正则表达式作为参数时会提取它们。 |
3 |
xpath() 返回一个选择器列表,它表示由作为参数给出的 xpath 表达式选定的节点。 |
4 |
css() 返回选择器列表,它表示由作为参数给出的 CSS 表达式选定的节点。 |
Using Selectors in the Shell
要使用内置的 Scrapy 外壳演示选择器,你需要在你的系统中安装 IPython 。这里的重要事项是,在运行 Scrapy 时,URL 应该包含在引号内;否则带有“&”字符的 URL 将不起作用。你可以使用以下命令在项目的顶级目录中启动外壳 −
scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/"
一个外壳将如下所示 −
[ ... Scrapy log here ... ]
2014-01-23 17:11:42-0400 [scrapy] DEBUG: Crawled (200)
<GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>(referer: None)
[s] Available Scrapy objects:
[s] crawler <scrapy.crawler.Crawler object at 0x3636b50>
[s] item {}
[s] request <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
[s] response <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
[s] settings <scrapy.settings.Settings object at 0x3fadc50>
[s] spider <Spider 'default' at 0x3cebf50>
[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
In [1]:
当外壳加载时,你可以分别使用 response.body 和 response.header 访问正文或标题。类似地,你可以使用 response.selector.xpath() 或 response.selector.css() 对响应运行查询。
例如 −
In [1]: response.xpath('//title')
Out[1]: [<Selector xpath = '//title' data = u'<title>My Book - Scrapy'>]
In [2]: response.xpath('//title').extract()
Out[2]: [u'<title>My Book - Scrapy: Index: Chapters</title>']
In [3]: response.xpath('//title/text()')
Out[3]: [<Selector xpath = '//title/text()' data = u'My Book - Scrapy: Index:'>]
In [4]: response.xpath('//title/text()').extract()
Out[4]: [u'My Book - Scrapy: Index: Chapters']
In [5]: response.xpath('//title/text()').re('(\w+):')
Out[5]: [u'Scrapy', u'Index', u'Chapters']
Extracting the Data
要从一个普通 HTML 站点中提取数据,我们必须检查该站点的源代码来获取 XPath。检查后,你会看到数据将位于 ul 标签中。选择 li 标签内的元素。
以下代码行显示了不同类型数据的提取 −
对于 li 标签中选择数据 −
response.xpath('//ul/li')
对于选择描述 −
response.xpath('//ul/li/text()').extract()
对于选择网站标题 −
response.xpath('//ul/li/a/text()').extract()
对于选择网站链接 −
response.xpath('//ul/li/a/@href').extract()
以下代码证明了上述提取器的使用 −
import scrapy
class MyprojectSpider(scrapy.Spider):
name = "project"
allowed_domains = ["dmoz.org"]
start_urls = [
"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
"http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
]
def parse(self, response):
for sel in response.xpath('//ul/li'):
title = sel.xpath('a/text()').extract()
link = sel.xpath('a/@href').extract()
desc = sel.xpath('text()').extract()
print title, link, desc
Scrapy - Using an Item
Description
Item 对象是 Python 的正规字典。我们可以使用以下语法来访问类的属性 −
>>> item = DmozItem()
>>> item['title'] = 'sample title'
>>> item['title']
'sample title'
将以上代码添加到以下示例 −
import scrapy
from tutorial.items import DmozItem
class MyprojectSpider(scrapy.Spider):
name = "project"
allowed_domains = ["dmoz.org"]
start_urls = [
"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
"http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
]
def parse(self, response):
for sel in response.xpath('//ul/li'):
item = DmozItem()
item['title'] = sel.xpath('a/text()').extract()
item['link'] = sel.xpath('a/@href').extract()
item['desc'] = sel.xpath('text()').extract()
yield item
以上爬虫的输出将是 −
[scrapy] DEBUG: Scraped from <200
http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
{'desc': [u' - By David Mertz; Addison Wesley. Book in progress, full text,
ASCII format. Asks for feedback. [author website, Gnosis Software, Inc.\n],
'link': [u'http://gnosis.cx/TPiP/'],
'title': [u'Text Processing in Python']}
[scrapy] DEBUG: Scraped from <200
http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>
{'desc': [u' - By Sean McGrath; Prentice Hall PTR, 2000, ISBN 0130211192,
has CD-ROM. Methods to build XML applications fast, Python tutorial, DOM and
SAX, new Pyxie open source XML processing library. [Prentice Hall PTR]\n'],
'link': [u'http://www.informit.com/store/product.aspx?isbn=0130211192'],
'title': [u'XML Processing with Python']}
Scrapy - Following Links
Description
在本章中,我们将学习如何提取我们感兴趣的页面的链接,跟踪它们并从该页面提取数据。为此,我们需要对我们的 previous code 作出如下更改:
import scrapy
from tutorial.items import DmozItem
class MyprojectSpider(scrapy.Spider):
name = "project"
allowed_domains = ["dmoz.org"]
start_urls = [
"http://www.dmoz.org/Computers/Programming/Languages/Python/",
]
def parse(self, response):
for href in response.css("ul.directory.dir-col > li > a::attr('href')"):
url = response.urljoin(href.extract())
yield scrapy.Request(url, callback = self.parse_dir_contents)
def parse_dir_contents(self, response):
for sel in response.xpath('//ul/li'):
item = DmozItem()
item['title'] = sel.xpath('a/text()').extract()
item['link'] = sel.xpath('a/@href').extract()
item['desc'] = sel.xpath('text()').extract()
yield item
上面的代码包含以下方法-
-
parse() - 它将提取我们感兴趣的链接。
-
response.urljoin - parse() 方法将使用这种方法来构建一个新的 url 并提供一个新的请求,稍后会将其发送到 callback。
-
parse_dir_contents() − 这项回叫实际将抓取所需信息。
在此处,Scrapy 使用回叫机制来跟踪链接。利用该机制,可以设计更大的爬虫并且可以跟踪所需的链接以从不同的页面中抓取所需信息。常规方法将是回叫方法,该方法将提取数据项,查找链接来跟踪到下一页,然后针对相同的回叫提供请求。
以下示例生成一个循环,该循环将跟踪链接到下一页。
def parse_articles_follow_next_page(self, response):
for article in response.xpath("//article"):
item = ArticleItem()
... extract article data here
yield item
next_page = response.css("ul.navigation > li.next-page > a::attr('href')")
if next_page:
url = response.urljoin(next_page[0].extract())
yield scrapy.Request(url, self.parse_articles_follow_next_page)
Scrapy - Logging
Description
Logging 表示使用内置日志系统进行的事件跟踪,并定义用于实现应用程序和库的功能和类。日志记录是一种可随时使用的材料,它可以与记录设置中列出的 Scrapy 设置配合使用。
在运行命令时,Scrapy 会设置一些默认设置,并通过 scrapy.utils.log.configure_logging() 处理这些设置。
Log levels
在 Python 中,一个日志消息具有五种不同的严重程度级别。以下列表以升序列出了标准日志消息 -
-
logging.DEBUG – 用于调试消息(严重程度最低)
-
logging.INFO – 用于信息消息
-
logging.WARNING – 用于警告消息
-
logging.ERROR – 用于一般错误
-
logging.CRITICAL − 用于严重错误(最高级别)
How to Log Messages
下面的代码显示使用 logging.info 级别记录消息。
import logging
logging.info("This is an information")
上述记录消息可以用 logging.log 作为参数,显示如下:
import logging
logging.log(logging.INFO, "This is an information")
现在,你还可以使用记录器用日志助手日志将消息包含起来以清楚地显示出日志消息,如下所示:
import logging
logger = logging.getLogger()
logger.info("This is an information")
可以有多个记录器,可以通过使用 logging.getLogger 函数获取其名称来访问它们,显示如下。
import logging
logger = logging.getLogger('mycustomlogger')
logger.info("This is an information")
对于任何模块,可以使用 name 变量来使用自定义记录器,它包含了模块路径,如下所示:
import logging
logger = logging.getLogger(__name__)
logger.info("This is an information")
Logging from Spiders
每个爬取器实例都拥有一个 logger ,并可以使用,如下所示:
import scrapy
class LogSpider(scrapy.Spider):
name = 'logspider'
start_urls = ['http://dmoz.com']
def parse(self, response):
self.logger.info('Parse function called on %s', response.url)
在上面的代码中,记录器是使用爬取器的名称创建的,但是你可以使用 Python 提供的任何自定义记录器,如下所示:
import logging
import scrapy
logger = logging.getLogger('customizedlogger')
class LogSpider(scrapy.Spider):
name = 'logspider'
start_urls = ['http://dmoz.com']
def parse(self, response):
logger.info('Parse function called on %s', response.url)
Logging Configuration
记录器无法自行显示它们发送的消息。因此,它们需要“处理器”来显示这些消息,而处理器会将这些消息重定向到各自的目的地,如文件、电子邮件和标准输出。
根据下列设置,Scrapy 会为记录器配置处理器。
Logging Settings
下列设置用于配置日志 −
-
LOG_FILE 和 LOG_ENABLED 决定了日志消息的目标。
-
当你把 LOG_ENCODING 设置为 false 时,它将不会显示日志输出信息。
-
LOG_LEVEL 将确定消息的严重程度顺序;严重程度较低的消息将被过滤掉。
-
LOG_FORMAT 和 LOG_DATEFORMAT 用于为所有消息指定布局。
-
当你把 LOG_STDOUT 设置为 true,所有标准输出和错误信息的过程都会重定向到日志。
Command-line Options
可以通过传递命令行参数来覆盖 Scrapy 设置,如下表所示:
Sr.No |
Command & Description |
1 |
--logfile FILE Overrides LOG_FILE |
2 |
--loglevel/-L LEVEL Overrides LOG_LEVEL |
3 |
--nolog Sets LOG_ENABLED to False |
scrapy.utils.log module
此函数可用于初始化 Scrapy 的默认日志记录。
scrapy.utils.log.configure_logging(settings = None, install_root_handler = True)
Sr.No |
Parameter & Description |
1 |
settings (dict, None) 它创建并配置根记录器的处理器。默认情况下,它是 None。 |
2 |
install_root_handler (bool) 它指定安装根日志处理程序。默认情况下,它为 True。 |
以上函数 −
-
通过 Python 标准日志记录路由警告和 Twisted 日志记录。
-
将 DEBUG 分配给 Scrapy 和 ERROR 级别分配给 Twisted 日志记录器。
-
如果 LOG_STDOUT 设置为 true,则将 stdout 路由到日志。
可以使用 settings 参数覆盖默认选项。当未指定设置时,则使用默认值。当 install_root_handler 设为 true 时,可以为根日志记录器创建处理程序。如果将其设为 false,则不会设置任何日志输出。在使用 Scrapy 命令时,configure_logging 将自动调用,并且在运行自定义脚本时可以显式运行。
若要手动配置日志记录输出,可以使用 logging.basicConfig() ,如下所示 −
import logging
from scrapy.utils.log import configure_logging
configure_logging(install_root_handler = False)
logging.basicConfig (
filename = 'logging.txt',
format = '%(levelname)s: %(your_message)s',
level = logging.INFO
)
Scrapy - Stats Collection
Description
状态收集器是 Scrapy 提供的一个工具,用于收集以键/值形式表示的状态,并且是通过爬虫 API(爬虫提供对所有 Scrapy 核心组件的访问)进行访问的。状态收集器为每个爬虫提供一个状态表,状态收集器在爬虫打开时自动打开该表并在爬虫关闭时关闭该表。
Common Stats Collector Uses
以下代码使用 stats 属性访问该统计收集器。
class ExtensionThatAccessStats(object):
def __init__(self, stats):
self.stats = stats
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.stats)
下表显示了可以使用各种选项和统计收集器 -
Sr.No |
Parameters |
Description |
1 |
stats.set_value('hostname', socket.gethostname()) |
用于设置统计值。 |
2 |
stats.inc_value('customized_count') |
将增加统计值。 |
3 |
stats.max_value('max_items_scraped', value) |
只有大于之前的值时才能设置统计值。 |
4 |
stats.min_value('min_free_memory_percent', value) |
只有小于之前的值时才能设置统计值。 |
5 |
stats.get_value('customized_count') |
获取统计值。 |
6 |
stats.get_stats() {'custom_count': 1, 'start_time':datetime.datetime(2009, 7, 14, 21, 47, 28, 977139)} |
获取所有统计信息 |
Scrapy - Sending an E-mail
Description
Scrapy 可以使用其名为 Twisted non-blocking IO 的自有工具发送电子邮件,该工具远离爬虫程序的非阻塞 IO。你可以配置发送电子邮件的一些设置,并提供用于发送附件的简单 API。
共有两种实例化 MailSender 的方法,如下表所示 −
Sr.No |
Parameters |
Method |
1 |
from scrapy.mail import MailSender mailer = MailSender() |
通过使用标准构造函数。 |
2 |
mailer = MailSender.from_settings(settings) |
通过使用 Scrapy 设置对象。 |
以下代码行发送不带附件的电子邮件 −
mailer.send(to = ["receiver@example.com"], subject = "subject data", body = "body data",
cc = ["list@example.com"])
MailSender Class Reference
MailSender 类使用 Twisted non-blocking IO 从 Scrapy 发送电子邮件。
class scrapy.mail.MailSender(smtphost = None, mailfrom = None, smtpuser = None,
smtppass = None, smtpport = None)
以下表格显示了 MailSender 类中使用的参数 −
Sr.No |
Parameter & Description |
1 |
smtphost (str) SMTP 主机用于发送电子邮件。如果没有,则会使用 MAIL_HOST 设置。 |
2 |
mailfrom (str) 收件人地址用于发送电子邮件。如果没有,则会使用 MAIL_FROM 设置。 |
3 |
smtpuser 它指定 SMTP 用户。如果没有使用,则会使用 MAIL_USER 设置,并且如果未提及,则没有 SMTP 验证。 |
4 |
smtppass (str) 它指定用于验证的 SMTP 密码。 |
5 |
smtpport (int) 它指定用于连接的 SMTP 端口。 |
6 |
smtptls (boolean) 它使用 SMTP STARTTLS 实现。 |
7 |
smtpssl (boolean) 它使用安全 SSL 连接进行管理。 |
参考中指定了 MailSender 类中具有以下两个方法。第一个方法,
classmethod from_settings(settings)
它通过使用 Scrapy 设置对象合并。它包含以下参数 −
settings (scrapy.settings.Settings object) − 它被视为电子邮件接收者。
另一种方法,
send(to, subject, body, cc = None, attachs = (), mimetype = 'text/plain', charset = None)
下表包含了上述方法的参数 −
Sr.No |
Parameter & Description |
1 |
to (list) 它指的是电子邮件接收者。 |
2 |
subject (str) 它指定电子邮件的主题。 |
3 |
cc (list) 它指的是接收者列表。 |
4 |
body (str) 此处指电子邮件正文数据。 |
5 |
attachs (iterable) 此处指电子邮件的附件、附件的 MIME 类型和附件的名称。 |
6 |
mimetype (str) 它表示电子邮件的 MIME 类型。 |
7 |
charset (str) 它指定了电子邮件内容使用的字符编码。 |
Mail Settings
通过以下设置确保无需编写任何代码,即可使用项目中的 MailSender 类配置电子邮件。
Sr.No |
Settings & Description |
Default Value |
1 |
MAIL_FROM 此处指发送电子邮件的发件人电子邮件。 |
'scrapy@localhost' |
2 |
MAIL_HOST 此处指用于发送电子邮件的 SMTP 主机。 |
'localhost' |
3 |
MAIL_PORT 此处指定了用于发送电子邮件的 SMTP 端口。 |
25 |
4 |
MAIL_USER 此处指 SMTP 验证。如果此设置设为禁用,则不会进行任何验证。 |
None |
5 |
MAIL_PASS 此处提供了用于 SMTP 验证的密码。 |
None |
6 |
MAIL_TLS 此处提供了使用 SSL/TLS 将不安全的连接升级为安全连接的方法。 |
False |
7 |
MAIL_SSL 它使用 SSL 加密连接实现连接。 |
False |
Scrapy - Telnet Console
Access Telnet Console
可以使用以下命令访问 telnet 控制台 −
telnet localhost 6023
基本上,telnet 控制台在 TELNETCONSOLE_PORT 中所述的 TCP 端口中列出。
Variables
下表中所述的某些默认变量用作快捷方式 −
Sr.No |
Shortcut & Description |
1 |
crawler 它引用 Scrapy 爬虫 (scrapy.crawler.Crawler) 对象。 |
2 |
engine 它引用 Crawler.engine 属性。 |
3 |
spider 它引用处于活动状态的爬虫。 |
4 |
slot 它引用引擎槽。 |
5 |
extensions 它引用扩展管理器 (Crawler.extensions) 属性。 |
6 |
stats 它引用状态收集器 (Crawler.stats) 属性。 |
7 |
setting 它引用 Scrapy 设置对象 (Crawler.settings) 属性。 |
8 |
est 它引用打印引擎状态报告。 |
9 |
prefs 它引用用于调试的内存。 |
10 |
p 它引用 pprint.pprint 函数的快捷方式。 |
11 |
hpy 它引用内存调试。 |
Examples
以下是使用 Telnet 控制台说明的一些示例。
Pause, Resume and Stop the Scrapy Engine
要暂停 Scrapy 引擎,请使用以下命令 -
telnet localhost 6023
>>> engine.pause()
>>>
要恢复 Scrapy 引擎,请使用以下命令 -
telnet localhost 6023
>>> engine.unpause()
>>>
要停止 Scrapy 引擎,请使用以下命令 -
telnet localhost 6023
>>> engine.stop()
Connection closed by foreign host.
View Engine Status
Telnet 控制台使用 est() 方法检查 Scrapy 引擎状态,如下面的代码中所示 -
telnet localhost 6023
>>> est()
Execution engine status
time()-engine.start_time : 8.62972998619
engine.has_capacity() : False
len(engine.downloader.active) : 16
engine.scraper.is_idle() : False
engine.spider.name : followall
engine.spider_is_idle(engine.spider) : False
engine.slot.closing : False
len(engine.slot.inprogress) : 16
len(engine.slot.scheduler.dqs or []) : 0
len(engine.slot.scheduler.mqs) : 92
len(engine.scraper.slot.queue) : 0
len(engine.scraper.slot.active) : 0
engine.scraper.slot.active_size : 0
engine.scraper.slot.itemproc_size : 0
engine.scraper.slot.needs_backout() : False
Scrapy - Web Services
Description
一个正在运行的 Scrapy 网络爬虫可以通过 JSON-RPC 控制。它通过 JSONRPC_ENABLED 设置启用。此服务通过 JSON-RPC 2.0 协议提供对主爬虫对象的访问。用于访问爬虫程序对象的端点为 −
http://localhost:6080/crawler
下表包含显示 Web 服务行为的一些设置 −
Sr.No |
Setting & Description |
Default Value |
1 |
JSONRPC_ENABLED 这指布尔值,它决定 Web 服务及其扩展名是否启用。 |
True |
2 |
JSONRPC_LOGFILE 这指用于记录向 Web 服务发出的 HTTP 请求的文件。如果未设置,将使用标准 Scrapy 日志。 |
None |
3 |
JSONRPC_PORT 这指 Web 服务的端口范围。如果设置为无,则将动态分配端口。 |
[6080, 7030] |
4 |
JSONRPC_HOST 这指 Web 服务应监听的接口。 |
'127.0.0.1' |