Scrapy – 蜘蛛
spider是定义一个特定站点(或一组站点)如何被抓取的类,包括如何执行抓取(即跟踪链接)以及如何从页面中提取结构化数据(即抓取项)。换言之,spider是为特定站点(或者在某些情况下,一组站点)定义爬行和解析页面的自定义行为的地方。
对于蜘蛛来说,抓取周期是这样的:
-
首先生成对第一个URL进行爬网的初始请求,然后指定一个回调函数,该函数使用从这些请求下载的响应进行调用。
要执行的第一个请求是通过调用
start_requests()(默认)生成的方法Request对于中指定的URLstart_urls以及parse方法作为请求的回调函数。 -
在回调函数中,解析响应(网页)并返回 item objects ,
Request对象,或这些对象中的一个不可重复的对象。这些请求还将包含回调(可能相同),然后由scrappy下载,然后由指定的回调处理它们的响应。 -
在回调函数中,解析页面内容,通常使用 选择器 (但您也可以使用beautifulsoup、lxml或任何您喜欢的机制)并使用解析的数据生成项。
-
最后,从spider返回的项目通常被持久化到数据库(在某些 Item Pipeline )或者使用 Feed 导出 .
尽管这个循环(或多或少)适用于任何类型的蜘蛛,但是为了不同的目的,有不同类型的默认蜘蛛被捆绑成 Scrapy 。我们将在这里讨论这些类型。
scrapy.Spider¶
-
class
scrapy.spiders.Spider[源代码]¶ -
这是最简单的蜘蛛,也是每个蜘蛛都必须继承的蜘蛛(包括与碎屑捆绑在一起的蜘蛛,还有你自己写的蜘蛛)。它不提供任何特殊功能。它只是提供了一个默认值
start_requests()从发送请求的实现start_urlsspider属性并调用spider的方法parse对于每个结果响应。-
name¶ -
定义此蜘蛛名称的字符串。spider名称是scrappy定位(和实例化)spider的方式,因此它必须是唯一的。但是,没有什么可以阻止您实例化同一个蜘蛛的多个实例。这是最重要的蜘蛛属性,也是必需的。
如果蜘蛛 爬取 一个域,通常的做法是在域后命名蜘蛛,无论有没有 TLD . 例如,一只爬行的蜘蛛
mywebsite.com经常被称为mywebsite.
-
allowed_domains¶ -
包含允许此蜘蛛爬行的域的字符串的可选列表。对于不属于此列表(或其子域)中指定的域名的URL请求,如果
OffsiteMiddleware启用。假设您的目标URL是
https://www.example.com/1.html然后添加'example.com'列在名单上。
-
start_urls¶ -
当没有指定特定的URL时,蜘蛛将从中开始爬行的URL列表。所以,下载的第一页将是这里列出的那些。随后
Request将从包含在起始URL中的数据依次生成。
-
custom_settings¶ -
运行此spider时,将从项目范围配置中重写的设置字典。它必须被定义为类属性,因为在实例化之前更新了设置。
有关可用内置设置的列表,请参阅: 内置设置参考 .
-
crawler¶ -
此属性由
from_crawler()初始化类后的类方法,并链接到Crawler此蜘蛛实例绑定到的对象。Crawler封装了项目中的许多组件,用于它们的单入口访问(例如扩展、中间件、信号管理器等)。见 爬虫API 了解更多。
-
settings¶ -
用于运行此蜘蛛的配置。这是一个
Settings实例,请参见 设置 有关此主题的详细介绍。
-
logger¶ -
用蜘蛛创建的python记录器
name. 您可以使用它通过它发送日志消息,如中所述 从蜘蛛记录 .
-
from_crawler(crawler, *args, **kwargs)[源代码]¶ -
这是Scrapy用来创建蜘蛛的类方法。
您可能不需要直接重写它,因为默认实现充当
__init__()方法,使用给定参数调用它args和命名参数kwargs.尽管如此,此方法设置了
crawler和settings新实例中的属性,以便稍后在蜘蛛代码中访问它们。- 参数
-
-
crawler (
Crawlerinstance) -- 蜘蛛将被绑到的爬行器 -
args (list) -- 传递给的参数
__init__()方法 -
kwargs (dict) -- 传递给的关键字参数
__init__()方法
-
-
start_requests()[源代码]¶ -
此方法必须返回一个iterable,其中包含对此spider进行爬网的第一个请求。当蜘蛛被打开爬取的时候,它被称为 Scrapy。Scrapy只调用一次,因此可以安全地实现
start_requests()作为发电机。默认实现生成
Request(url, dont_filter=True)对于每个URLstart_urls.如果要更改用于开始抓取域的请求,这是要重写的方法。例如,如果您需要从使用POST请求登录开始,可以执行以下操作:
class MySpider(scrapy.Spider): name = 'myspider' def start_requests(self): return [scrapy.FormRequest("http://www.example.com/login", formdata={'user': 'john', 'pass': 'secret'}, callback=self.logged_in)] def logged_in(self, response): # here you would extract links to follow and return Requests for # each of them, with another callback pass
-
parse(response)[源代码]¶ -
这是Scrapy在请求未指定回调时用来处理下载响应的默认回调。
这个
parse方法负责处理响应,并返回 爬取 的数据和/或更多的URL。其他请求回调与Spider班级。此方法以及任何其他请求回调都必须返回
Request和/或 item objects .- 参数
-
response (
Response) -- 解析的响应
-
log(message[, level, component])[源代码]¶ -
通过Spider的
logger,保持向后兼容性。有关详细信息,请参阅 从蜘蛛记录 .
-
closed(reason)¶ -
蜘蛛关闭时调用。此方法为
spider_closed信号。
-
我们来看一个例子:
import scrapy class MySpider(scrapy.Spider): name = 'example.com' allowed_domains = ['example.com'] start_urls = [ 'http://www.example.com/1.html', 'http://www.example.com/2.html', 'http://www.example.com/3.html', ] def parse(self, response): self.logger.info('A response from %s just arrived!', response.url)
从单个回调返回多个请求和项目:
import scrapy class MySpider(scrapy.Spider): name = 'example.com' allowed_domains = ['example.com'] start_urls = [ 'http://www.example.com/1.html', 'http://www.example.com/2.html', 'http://www.example.com/3.html', ] def parse(self, response): for h3 in response.xpath('//h3').getall(): yield {"title": h3} for href in response.xpath('//a/@href').getall(): yield scrapy.Request(response.urljoin(href), self.parse)
而不是 start_urls 你可以用 start_requests() 直接;给数据更多的结构,你可以使用 Item 物体::
import scrapy from myproject.items import MyItem class MySpider(scrapy.Spider): name = 'example.com' allowed_domains = ['example.com'] def start_requests(self): yield scrapy.Request('http://www.example.com/1.html', self.parse) yield scrapy.Request('http://www.example.com/2.html', self.parse) yield scrapy.Request('http://www.example.com/3.html', self.parse) def parse(self, response): for h3 in response.xpath('//h3').getall(): yield MyItem(title=h3) for href in response.xpath('//a/@href').getall(): yield scrapy.Request(response.urljoin(href), self.parse)
蜘蛛论点¶
蜘蛛可以接受改变其行为的论据。spider参数的一些常见用途是定义起始URL或将爬行限制在站点的某些部分,但它们可以用于配置spider的任何功能。
蜘蛛参数通过 crawl 命令使用 -a 选项。例如::
scrapy crawl myspider -a category=electronics
蜘蛛可以在它们的 __init__ 方法::
import scrapy class MySpider(scrapy.Spider): name = 'myspider' def __init__(self, category=None, *args, **kwargs): super(MySpider, self).__init__(*args, **kwargs) self.start_urls = [f'http://www.example.com/categories/{category}'] # ...
默认值 __init__ 方法将获取任何spider参数,并将其作为属性复制到spider。上面的例子也可以写如下:
import scrapy class MySpider(scrapy.Spider): name = 'myspider' def start_requests(self): yield scrapy.Request(f'http://www.example.com/categories/{self.category}')
请记住,spider参数只是字符串。蜘蛛本身不会进行任何解析。如果你要设置 start_urls 属性来自命令行,您必须使用类似的 ast.literal_eval() 或 json.loads() 然后将其设置为属性。否则,您将在 start_urls 字符串(一个非常常见的Python陷阱),导致每个字符被视为一个单独的URL。
有效的用例是设置 HttpAuthMiddleware 或用户代理 UserAgentMiddleware ::
scrapy crawl myspider -a http_user=myuser -a http_pass=mypassword -a user_agent=mybot
蜘蛛参数也可以通过scrapyD传递 schedule.json 应用程序编程接口。见 Scrapyd documentation .
类蜘蛛¶
Scrapy附带了一些有用的通用蜘蛛,您可以使用它们来对蜘蛛进行子类化。他们的目标是为一些常见的抓取案例提供方便的功能,比如根据特定规则跟踪站点上的所有链接,从 Sitemaps 或分析XML/CSV源。
对于以下蜘蛛中使用的示例,我们假设您有一个项目 TestItem 宣布为 myproject.items 模块:
import scrapy class TestItem(scrapy.Item): id = scrapy.Field() name = scrapy.Field() description = scrapy.Field()
CrawlSpider¶
-
class
scrapy.spiders.CrawlSpider[源代码]¶ -
这是最常用的爬行常规网站的蜘蛛,因为它通过定义一组规则为跟踪链接提供了一种方便的机制。它可能不是最适合您的特定网站或项目的,但它对于某些情况来说已经足够通用了,因此您可以从它开始,并根据需要覆盖它以获得更多的自定义功能,或者只实现您自己的蜘蛛。
除了从spider继承的属性(必须指定),这个类还支持一个新的属性:
-
rules¶ -
这是一个(或多个)列表
Rule物体。各Rule定义对网站进行爬行的特定行为。规则对象如下所述。如果多个规则与同一链接匹配,则将根据在该属性中定义的顺序使用第一个规则。
这个蜘蛛还公开了一个可重写的方法:
-
parse_start_url(response, **kwargs)[源代码]¶ -
为spider中的url生成的每个响应调用此方法
start_urls属性。它允许解析初始响应,并且必须返回 item object ,ARequest对象,或包含任何对象的iterable。
-
爬行规则¶
-
class
scrapy.spiders.Rule(link_extractor=None, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None, errback=None)[源代码]¶ -
link_extractor是一个 Link Extractor 对象,该对象定义如何从每个已爬网页提取链接。每个生成的链接将用于生成Request对象,其中包含链接的文本meta字典(在link_text键)。如果省略,将使用没有参数创建的默认链接提取器,从而导致提取所有链接。callback对用指定的链接提取程序提取的每个链接调用的可调用或字符串(在这种情况下,将使用具有该名称的spider对象中的方法)。此回调接收Response作为第一个参数,必须返回 item objects 和/或Request对象(或其任何子类)。如上所述,收到Response对象将包含生成Request在其meta字典(在link_text关键)cb_kwargs是包含要传递给回调函数的关键字参数的dict。follow是一个布尔值,用于指定是否从使用此规则提取的每个响应中遵循链接。如果callback没有follow默认为True,否则默认为False.process_links是一个可调用的,或一个字符串(在这种情况下,将使用具有该名称的蜘蛛对象中的方法),对于使用指定的link_extractor. 这主要用于过滤目的。process_request是可调用的(或字符串,在这种情况下,将使用具有该名称的spider对象中的方法),它将为Request按此规则提取。此可调用文件应将所述请求作为第一个参数,并且Response从中发出请求作为第二个参数。它必须返回Request对象或None(过滤掉请求)。errback在处理规则生成的请求时引发任何异常时要调用的可调用或字符串(在这种情况下,将使用来自spider对象的具有该名称的方法)。它收到一个Twisted Failure实例作为第一个参数。
警告
由于其内部实现,在编写时必须显式设置新请求的回调 CrawlSpider -基于蜘蛛;否则会发生意外行为。
2.0 新版功能: 这个 错误 参数。
爬行蜘蛛示例¶
现在让我们来看一个例子,爬行蜘蛛的规则是:
import scrapy from scrapy.spiders import CrawlSpider, Rule from scrapy.linkextractors import LinkExtractor class MySpider(CrawlSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com'] rules = ( # Extract links matching 'category.php' (but not matching 'subsection.php') # and follow links from them (since no callback means follow=True by default). Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))), # Extract links matching 'item.php' and parse them with the spider's method parse_item Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'), ) def parse_item(self, response): self.logger.info('Hi, this is an item page! %s', response.url) item = scrapy.Item() item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)') item['name'] = response.xpath('//td[@id="item_name"]/text()').get() item['description'] = response.xpath('//td[@id="item_description"]/text()').get() item['link_text'] = response.meta['link_text'] url = response.xpath('//td[@id="additional_data"]/@href').get() return response.follow(url, self.parse_additional_page, cb_kwargs=dict(item=item)) def parse_additional_page(self, response, item): item['additional_data'] = response.xpath('//p[@id="additional_data"]/text()').get() return item
这个蜘蛛会开始对example.com的主页进行爬行,收集类别链接和项目链接,并用 parse_item 方法。对于每个项目响应,将使用xpath从HTML中提取一些数据,并且 Item 会装满它的。
XMLFeedSpider¶
-
class
scrapy.spiders.XMLFeedSpider[源代码]¶ -
XMLFeedSpider是为解析XML提要而设计的,它通过使用特定的节点名对这些提要进行迭代。迭代器可以从以下选项中选择:
iternodes,xml和html. 建议使用iternodes由于性能原因,迭代器xml和html迭代器一次生成整个DOM以便解析它。然而,使用html因为迭代器在分析带有错误标记的XML时可能很有用。要设置迭代器和标记名,必须定义以下类属性:
-
iterator¶ -
定义要使用的迭代器的字符串。它可以是:
-
'iternodes'-基于正则表达式的快速迭代器 -
'html'-使用的迭代器Selector. 请记住,这使用了DOM解析,必须将所有的DOM加载到内存中,这对于大型提要来说可能是一个问题。 -
'xml'-使用的迭代器Selector. 请记住,这使用了DOM解析,必须将所有的DOM加载到内存中,这对于大型提要来说可能是一个问题。
默认为:
'iternodes'. -
-
itertag¶ -
具有要迭代的节点(或元素)名称的字符串。例子::
itertag = 'product'
-
namespaces¶ -
列表
(prefix, uri)定义该文档中可用的命名空间的元组,这些命名空间将使用此蜘蛛进行处理。这个prefix和uri将用于使用register_namespace()方法。然后,可以在
itertag属性。例子::
class YourSpider(XMLFeedSpider): namespaces = [('n', 'http://www.sitemaps.org/schemas/sitemap/0.9')] itertag = 'n:url' # ...
除了这些新属性之外,这个蜘蛛还具有以下可重写的方法:
-
adapt_response(response)[源代码]¶ -
一种方法,当响应从蜘蛛中间件到达时,在蜘蛛开始解析它之前,立即接收响应。它可以用于在解析响应体之前对其进行修改。此方法接收响应并返回响应(可以是相同的或另一个响应)。
-
parse_node(response, selector)[源代码]¶ -
对与提供的标记名匹配的节点调用此方法 (
itertag)接收响应和Selector对于每个节点。重写此方法是必需的。否则,你的蜘蛛就不能工作了。此方法必须返回 item object ,ARequest对象,或包含任何对象的iterable。
-
process_results(response, results)[源代码]¶ -
这个方法是为spider返回的每个结果(项或请求)调用的,它用于在将结果返回到框架核心之前执行所需的任何最后一次处理,例如设置项id。它接收结果列表和产生这些结果的响应。它必须返回结果列表(项或请求)。
-
警告
由于其内部实现,在编写时必须显式设置新请求的回调 XMLFeedSpider -基于蜘蛛;否则会发生意外行为。
XmlFeedSpider示例¶
这些蜘蛛很容易使用,让我们来看一个例子:
from scrapy.spiders import XMLFeedSpider from myproject.items import TestItem class MySpider(XMLFeedSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com/feed.xml'] iterator = 'iternodes' # This is actually unnecessary, since it's the default value itertag = 'item' def parse_node(self, response, node): self.logger.info('Hi, this is a <%s> node!: %s', self.itertag, ''.join(node.getall())) item = TestItem() item['id'] = node.xpath('@id').get() item['name'] = node.xpath('name').get() item['description'] = node.xpath('description').get() return item
基本上,我们所做的就是创建一个蜘蛛,从给定的 start_urls ,然后遍历 item 标签,打印出来,并将一些随机数据存储在 Item .
CSVFeedSpider¶
-
class
scrapy.spiders.CSVFeedSpider[源代码]¶ -
这个spider与xmlFeedSpider非常相似,只是它迭代行,而不是节点。在每次迭代中被调用的方法是
parse_row().-
delimiter¶ -
带有csv文件中每个字段分隔符的字符串默认为
','(逗号)
-
quotechar¶ -
带有csv文件中每个字段的外壳字符的字符串默认为
'"'(引号)。
-
headers¶ -
csv文件中的列名列表。
-
parse_row(response, row)[源代码]¶ -
接收响应和dict(代表每一行),其中为csv文件的每个提供的(或检测到的)头文件都有一个键。这个蜘蛛还提供了超越的机会
adapt_response和process_results用于预处理和后处理目的的方法。
-
CSVFeedspider示例¶
我们来看一个类似于前一个的例子,但是使用 CSVFeedSpider ::
from scrapy.spiders import CSVFeedSpider from myproject.items import TestItem class MySpider(CSVFeedSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com/feed.csv'] delimiter = ';' quotechar = "'" headers = ['id', 'name', 'description'] def parse_row(self, response, row): self.logger.info('Hi, this is a row!: %r', row) item = TestItem() item['id'] = row['id'] item['name'] = row['name'] item['description'] = row['description'] return item
SitemapSpider¶
-
class
scrapy.spiders.SitemapSpider[源代码]¶ -
SiteMapSpider允许您通过使用 Sitemaps .
它支持嵌套的站点地图和从中发现站点地图URL robots.txt .
-
sitemap_urls¶ -
指向要爬网其URL的网站地图的URL列表。
您也可以指向 robots.txt 它将被解析为从中提取站点地图URL。
-
sitemap_rules¶ -
元组列表
(regex, callback)在哪里?-
regex是一个正则表达式,用于匹配从站点地图中提取的URL。regex可以是str或已编译的regex对象。 -
回调是用于处理与正则表达式匹配的URL的回调。
callback可以是字符串(指示spider方法的名称)或可调用的。
例如::
sitemap_rules = [('/product/', 'parse_product')]
规则按顺序应用,只使用第一个匹配的规则。
如果省略此属性,则在站点地图中找到的所有URL都将使用
parse回调。 -
-
sitemap_follow¶ -
应遵循的站点地图正则表达式列表。这只适用于使用 Sitemap index files 指向其他站点 Mapfile 。
默认情况下,将遵循所有站点地图。
-
sitemap_alternate_links¶ -
指定是否为一个
url应该遵循。这些是同一网站的链接,使用同一网站内传递的另一种语言url块。例如::
<url> <loc>http://example.com/</loc> <xhtml:link rel="alternate" hreflang="de" href="http://example.com/de"/> </url>
用
sitemap_alternate_links设置,这将检索两个URL。用sitemap_alternate_links只有残疾人http://example.com/将被取回。sitemap_alternate_links残疾人。
-
sitemap_filter(entries)[源代码]¶ -
这是一个过滤器函数,可以重写该函数以根据其属性选择站点地图条目。
例如::
<url> <loc>http://example.com/</loc> <lastmod>2005-01-01</lastmod> </url>
我们可以定义一个
sitemap_filter要筛选的函数entries日期:from datetime import datetime from scrapy.spiders import SitemapSpider class FilteredSitemapSpider(SitemapSpider): name = 'filtered_sitemap_spider' allowed_domains = ['example.com'] sitemap_urls = ['http://example.com/sitemap.xml'] def sitemap_filter(self, entries): for entry in entries: date_time = datetime.strptime(entry['lastmod'], '%Y-%m-%d') if date_time.year >= 2005: yield entry
这只能找回
entries2005年及以后年份修改。条目是从站点地图文档中提取的dict对象。通常,键是标记名,值是其中的文本。
重要的是要注意:
-
由于loc属性是必需的,因此不带此标记的条目将被丢弃。
-
备用链接用键存储在列表中
alternate(见sitemap_alternate_links) -
名称空间被删除,因此名为
{{namespace}}tagname成为唯一tagname
如果省略此方法,则将处理站点地图中找到的所有条目,同时观察其他属性及其设置。
-
-
SiteMapSpider示例¶
最简单的示例:使用 parse 回叫:
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/sitemap.xml'] def parse(self, response): pass # ... scrape item here ...
使用特定回调处理某些URL,使用其他回调处理其他URL::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/sitemap.xml'] sitemap_rules = [ ('/product/', 'parse_product'), ('/category/', 'parse_category'), ] def parse_product(self, response): pass # ... scrape product ... def parse_category(self, response): pass # ... scrape category ...
遵循中定义的站点地图 robots.txt 文件,仅跟踪其URL包含 /sitemap_shop ::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/robots.txt'] sitemap_rules = [ ('/shop/', 'parse_shop'), ] sitemap_follow = ['/sitemap_shops'] def parse_shop(self, response): pass # ... scrape shop here ...
将SiteMapSpider与其他URL源合并::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/robots.txt'] sitemap_rules = [ ('/shop/', 'parse_shop'), ] other_urls = ['http://www.example.com/about'] def start_requests(self): requests = list(super(MySpider, self).start_requests()) requests += [scrapy.Request(x, self.parse_other) for x in self.other_urls] return requests def parse_shop(self, response): pass # ... scrape shop here ... def parse_other(self, response): pass # ... scrape other here ...
scrapy.Spider¶
-
class
scrapy.spiders.Spider[源代码]¶ -
这是最简单的蜘蛛,也是每个蜘蛛都必须继承的蜘蛛(包括与碎屑捆绑在一起的蜘蛛,还有你自己写的蜘蛛)。它不提供任何特殊功能。它只是提供了一个默认值
start_requests()从发送请求的实现start_urlsspider属性并调用spider的方法parse对于每个结果响应。-
name¶ -
定义此蜘蛛名称的字符串。spider名称是scrappy定位(和实例化)spider的方式,因此它必须是唯一的。但是,没有什么可以阻止您实例化同一个蜘蛛的多个实例。这是最重要的蜘蛛属性,也是必需的。
如果蜘蛛 爬取 一个域,通常的做法是在域后命名蜘蛛,无论有没有 TLD . 例如,一只爬行的蜘蛛
mywebsite.com经常被称为mywebsite.
-
allowed_domains¶ -
包含允许此蜘蛛爬行的域的字符串的可选列表。对于不属于此列表(或其子域)中指定的域名的URL请求,如果
OffsiteMiddleware启用。假设您的目标URL是
https://www.example.com/1.html然后添加'example.com'列在名单上。
-
start_urls¶ -
当没有指定特定的URL时,蜘蛛将从中开始爬行的URL列表。所以,下载的第一页将是这里列出的那些。随后
Request将从包含在起始URL中的数据依次生成。
-
custom_settings¶ -
运行此spider时,将从项目范围配置中重写的设置字典。它必须被定义为类属性,因为在实例化之前更新了设置。
有关可用内置设置的列表,请参阅: 内置设置参考 .
-
crawler¶ -
此属性由
from_crawler()初始化类后的类方法,并链接到Crawler此蜘蛛实例绑定到的对象。Crawler封装了项目中的许多组件,用于它们的单入口访问(例如扩展、中间件、信号管理器等)。见 爬虫API 了解更多。
-
settings¶ -
用于运行此蜘蛛的配置。这是一个
Settings实例,请参见 设置 有关此主题的详细介绍。
-
logger¶ -
用蜘蛛创建的python记录器
name. 您可以使用它通过它发送日志消息,如中所述 从蜘蛛记录 .
-
from_crawler(crawler, *args, **kwargs)[源代码]¶ -
这是Scrapy用来创建蜘蛛的类方法。
您可能不需要直接重写它,因为默认实现充当
__init__()方法,使用给定参数调用它args和命名参数kwargs.尽管如此,此方法设置了
crawler和settings新实例中的属性,以便稍后在蜘蛛代码中访问它们。- 参数
-
-
crawler (
Crawlerinstance) -- 蜘蛛将被绑到的爬行器 -
args (list) -- 传递给的参数
__init__()方法 -
kwargs (dict) -- 传递给的关键字参数
__init__()方法
-
-
start_requests()[源代码]¶ -
此方法必须返回一个iterable,其中包含对此spider进行爬网的第一个请求。当蜘蛛被打开爬取的时候,它被称为 Scrapy。Scrapy只调用一次,因此可以安全地实现
start_requests()作为发电机。默认实现生成
Request(url, dont_filter=True)对于每个URLstart_urls.如果要更改用于开始抓取域的请求,这是要重写的方法。例如,如果您需要从使用POST请求登录开始,可以执行以下操作:
class MySpider(scrapy.Spider): name = 'myspider' def start_requests(self): return [scrapy.FormRequest("http://www.example.com/login", formdata={'user': 'john', 'pass': 'secret'}, callback=self.logged_in)] def logged_in(self, response): # here you would extract links to follow and return Requests for # each of them, with another callback pass
-
parse(response)[源代码]¶ -
这是Scrapy在请求未指定回调时用来处理下载响应的默认回调。
这个
parse方法负责处理响应,并返回 爬取 的数据和/或更多的URL。其他请求回调与Spider班级。此方法以及任何其他请求回调都必须返回
Request和/或 item objects .- 参数
-
response (
Response) -- 解析的响应
-
log(message[, level, component])[源代码]¶ -
通过Spider的
logger,保持向后兼容性。有关详细信息,请参阅 从蜘蛛记录 .
-
closed(reason)¶ -
蜘蛛关闭时调用。此方法为
spider_closed信号。
-
我们来看一个例子:
import scrapy class MySpider(scrapy.Spider): name = 'example.com' allowed_domains = ['example.com'] start_urls = [ 'http://www.example.com/1.html', 'http://www.example.com/2.html', 'http://www.example.com/3.html', ] def parse(self, response): self.logger.info('A response from %s just arrived!', response.url)
从单个回调返回多个请求和项目:
import scrapy class MySpider(scrapy.Spider): name = 'example.com' allowed_domains = ['example.com'] start_urls = [ 'http://www.example.com/1.html', 'http://www.example.com/2.html', 'http://www.example.com/3.html', ] def parse(self, response): for h3 in response.xpath('//h3').getall(): yield {"title": h3} for href in response.xpath('//a/@href').getall(): yield scrapy.Request(response.urljoin(href), self.parse)
而不是 start_urls 你可以用 start_requests() 直接;给数据更多的结构,你可以使用 Item 物体::
import scrapy from myproject.items import MyItem class MySpider(scrapy.Spider): name = 'example.com' allowed_domains = ['example.com'] def start_requests(self): yield scrapy.Request('http://www.example.com/1.html', self.parse) yield scrapy.Request('http://www.example.com/2.html', self.parse) yield scrapy.Request('http://www.example.com/3.html', self.parse) def parse(self, response): for h3 in response.xpath('//h3').getall(): yield MyItem(title=h3) for href in response.xpath('//a/@href').getall(): yield scrapy.Request(response.urljoin(href), self.parse)
蜘蛛论点¶
蜘蛛可以接受改变其行为的论据。spider参数的一些常见用途是定义起始URL或将爬行限制在站点的某些部分,但它们可以用于配置spider的任何功能。
蜘蛛参数通过 crawl 命令使用 -a 选项。例如::
scrapy crawl myspider -a category=electronics
蜘蛛可以在它们的 __init__ 方法::
import scrapy class MySpider(scrapy.Spider): name = 'myspider' def __init__(self, category=None, *args, **kwargs): super(MySpider, self).__init__(*args, **kwargs) self.start_urls = [f'http://www.example.com/categories/{category}'] # ...
默认值 __init__ 方法将获取任何spider参数,并将其作为属性复制到spider。上面的例子也可以写如下:
import scrapy class MySpider(scrapy.Spider): name = 'myspider' def start_requests(self): yield scrapy.Request(f'http://www.example.com/categories/{self.category}')
请记住,spider参数只是字符串。蜘蛛本身不会进行任何解析。如果你要设置 start_urls 属性来自命令行,您必须使用类似的 ast.literal_eval() 或 json.loads() 然后将其设置为属性。否则,您将在 start_urls 字符串(一个非常常见的Python陷阱),导致每个字符被视为一个单独的URL。
有效的用例是设置 HttpAuthMiddleware 或用户代理 UserAgentMiddleware ::
scrapy crawl myspider -a http_user=myuser -a http_pass=mypassword -a user_agent=mybot
蜘蛛参数也可以通过scrapyD传递 schedule.json 应用程序编程接口。见 Scrapyd documentation .
类蜘蛛¶
Scrapy附带了一些有用的通用蜘蛛,您可以使用它们来对蜘蛛进行子类化。他们的目标是为一些常见的抓取案例提供方便的功能,比如根据特定规则跟踪站点上的所有链接,从 Sitemaps 或分析XML/CSV源。
对于以下蜘蛛中使用的示例,我们假设您有一个项目 TestItem 宣布为 myproject.items 模块:
import scrapy class TestItem(scrapy.Item): id = scrapy.Field() name = scrapy.Field() description = scrapy.Field()
CrawlSpider¶
-
class
scrapy.spiders.CrawlSpider[源代码]¶ -
这是最常用的爬行常规网站的蜘蛛,因为它通过定义一组规则为跟踪链接提供了一种方便的机制。它可能不是最适合您的特定网站或项目的,但它对于某些情况来说已经足够通用了,因此您可以从它开始,并根据需要覆盖它以获得更多的自定义功能,或者只实现您自己的蜘蛛。
除了从spider继承的属性(必须指定),这个类还支持一个新的属性:
-
rules¶ -
这是一个(或多个)列表
Rule物体。各Rule定义对网站进行爬行的特定行为。规则对象如下所述。如果多个规则与同一链接匹配,则将根据在该属性中定义的顺序使用第一个规则。
这个蜘蛛还公开了一个可重写的方法:
-
parse_start_url(response, **kwargs)[源代码]¶ -
为spider中的url生成的每个响应调用此方法
start_urls属性。它允许解析初始响应,并且必须返回 item object ,ARequest对象,或包含任何对象的iterable。
-
爬行规则¶
-
class
scrapy.spiders.Rule(link_extractor=None, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None, errback=None)[源代码]¶ -
link_extractor是一个 Link Extractor 对象,该对象定义如何从每个已爬网页提取链接。每个生成的链接将用于生成Request对象,其中包含链接的文本meta字典(在link_text键)。如果省略,将使用没有参数创建的默认链接提取器,从而导致提取所有链接。callback对用指定的链接提取程序提取的每个链接调用的可调用或字符串(在这种情况下,将使用具有该名称的spider对象中的方法)。此回调接收Response作为第一个参数,必须返回 item objects 和/或Request对象(或其任何子类)。如上所述,收到Response对象将包含生成Request在其meta字典(在link_text关键)cb_kwargs是包含要传递给回调函数的关键字参数的dict。follow是一个布尔值,用于指定是否从使用此规则提取的每个响应中遵循链接。如果callback没有follow默认为True,否则默认为False.process_links是一个可调用的,或一个字符串(在这种情况下,将使用具有该名称的蜘蛛对象中的方法),对于使用指定的link_extractor. 这主要用于过滤目的。process_request是可调用的(或字符串,在这种情况下,将使用具有该名称的spider对象中的方法),它将为Request按此规则提取。此可调用文件应将所述请求作为第一个参数,并且Response从中发出请求作为第二个参数。它必须返回Request对象或None(过滤掉请求)。errback在处理规则生成的请求时引发任何异常时要调用的可调用或字符串(在这种情况下,将使用来自spider对象的具有该名称的方法)。它收到一个Twisted Failure实例作为第一个参数。
警告
由于其内部实现,在编写时必须显式设置新请求的回调 CrawlSpider -基于蜘蛛;否则会发生意外行为。
2.0 新版功能: 这个 错误 参数。
爬行蜘蛛示例¶
现在让我们来看一个例子,爬行蜘蛛的规则是:
import scrapy from scrapy.spiders import CrawlSpider, Rule from scrapy.linkextractors import LinkExtractor class MySpider(CrawlSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com'] rules = ( # Extract links matching 'category.php' (but not matching 'subsection.php') # and follow links from them (since no callback means follow=True by default). Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))), # Extract links matching 'item.php' and parse them with the spider's method parse_item Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'), ) def parse_item(self, response): self.logger.info('Hi, this is an item page! %s', response.url) item = scrapy.Item() item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)') item['name'] = response.xpath('//td[@id="item_name"]/text()').get() item['description'] = response.xpath('//td[@id="item_description"]/text()').get() item['link_text'] = response.meta['link_text'] url = response.xpath('//td[@id="additional_data"]/@href').get() return response.follow(url, self.parse_additional_page, cb_kwargs=dict(item=item)) def parse_additional_page(self, response, item): item['additional_data'] = response.xpath('//p[@id="additional_data"]/text()').get() return item
这个蜘蛛会开始对example.com的主页进行爬行,收集类别链接和项目链接,并用 parse_item 方法。对于每个项目响应,将使用xpath从HTML中提取一些数据,并且 Item 会装满它的。
XMLFeedSpider¶
-
class
scrapy.spiders.XMLFeedSpider[源代码]¶ -
XMLFeedSpider是为解析XML提要而设计的,它通过使用特定的节点名对这些提要进行迭代。迭代器可以从以下选项中选择:
iternodes,xml和html. 建议使用iternodes由于性能原因,迭代器xml和html迭代器一次生成整个DOM以便解析它。然而,使用html因为迭代器在分析带有错误标记的XML时可能很有用。要设置迭代器和标记名,必须定义以下类属性:
-
iterator¶ -
定义要使用的迭代器的字符串。它可以是:
-
'iternodes'-基于正则表达式的快速迭代器 -
'html'-使用的迭代器Selector. 请记住,这使用了DOM解析,必须将所有的DOM加载到内存中,这对于大型提要来说可能是一个问题。 -
'xml'-使用的迭代器Selector. 请记住,这使用了DOM解析,必须将所有的DOM加载到内存中,这对于大型提要来说可能是一个问题。
默认为:
'iternodes'. -
-
itertag¶ -
具有要迭代的节点(或元素)名称的字符串。例子::
itertag = 'product'
-
namespaces¶ -
列表
(prefix, uri)定义该文档中可用的命名空间的元组,这些命名空间将使用此蜘蛛进行处理。这个prefix和uri将用于使用register_namespace()方法。然后,可以在
itertag属性。例子::
class YourSpider(XMLFeedSpider): namespaces = [('n', 'http://www.sitemaps.org/schemas/sitemap/0.9')] itertag = 'n:url' # ...
除了这些新属性之外,这个蜘蛛还具有以下可重写的方法:
-
adapt_response(response)[源代码]¶ -
一种方法,当响应从蜘蛛中间件到达时,在蜘蛛开始解析它之前,立即接收响应。它可以用于在解析响应体之前对其进行修改。此方法接收响应并返回响应(可以是相同的或另一个响应)。
-
parse_node(response, selector)[源代码]¶ -
对与提供的标记名匹配的节点调用此方法 (
itertag)接收响应和Selector对于每个节点。重写此方法是必需的。否则,你的蜘蛛就不能工作了。此方法必须返回 item object ,ARequest对象,或包含任何对象的iterable。
-
process_results(response, results)[源代码]¶ -
这个方法是为spider返回的每个结果(项或请求)调用的,它用于在将结果返回到框架核心之前执行所需的任何最后一次处理,例如设置项id。它接收结果列表和产生这些结果的响应。它必须返回结果列表(项或请求)。
-
警告
由于其内部实现,在编写时必须显式设置新请求的回调 XMLFeedSpider -基于蜘蛛;否则会发生意外行为。
XmlFeedSpider示例¶
这些蜘蛛很容易使用,让我们来看一个例子:
from scrapy.spiders import XMLFeedSpider from myproject.items import TestItem class MySpider(XMLFeedSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com/feed.xml'] iterator = 'iternodes' # This is actually unnecessary, since it's the default value itertag = 'item' def parse_node(self, response, node): self.logger.info('Hi, this is a <%s> node!: %s', self.itertag, ''.join(node.getall())) item = TestItem() item['id'] = node.xpath('@id').get() item['name'] = node.xpath('name').get() item['description'] = node.xpath('description').get() return item
基本上,我们所做的就是创建一个蜘蛛,从给定的 start_urls ,然后遍历 item 标签,打印出来,并将一些随机数据存储在 Item .
CSVFeedSpider¶
-
class
scrapy.spiders.CSVFeedSpider[源代码]¶ -
这个spider与xmlFeedSpider非常相似,只是它迭代行,而不是节点。在每次迭代中被调用的方法是
parse_row().-
delimiter¶ -
带有csv文件中每个字段分隔符的字符串默认为
','(逗号)
-
quotechar¶ -
带有csv文件中每个字段的外壳字符的字符串默认为
'"'(引号)。
-
headers¶ -
csv文件中的列名列表。
-
parse_row(response, row)[源代码]¶ -
接收响应和dict(代表每一行),其中为csv文件的每个提供的(或检测到的)头文件都有一个键。这个蜘蛛还提供了超越的机会
adapt_response和process_results用于预处理和后处理目的的方法。
-
CSVFeedspider示例¶
我们来看一个类似于前一个的例子,但是使用 CSVFeedSpider ::
from scrapy.spiders import CSVFeedSpider from myproject.items import TestItem class MySpider(CSVFeedSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com/feed.csv'] delimiter = ';' quotechar = "'" headers = ['id', 'name', 'description'] def parse_row(self, response, row): self.logger.info('Hi, this is a row!: %r', row) item = TestItem() item['id'] = row['id'] item['name'] = row['name'] item['description'] = row['description'] return item
SitemapSpider¶
-
class
scrapy.spiders.SitemapSpider[源代码]¶ -
SiteMapSpider允许您通过使用 Sitemaps .
它支持嵌套的站点地图和从中发现站点地图URL robots.txt .
-
sitemap_urls¶ -
指向要爬网其URL的网站地图的URL列表。
您也可以指向 robots.txt 它将被解析为从中提取站点地图URL。
-
sitemap_rules¶ -
元组列表
(regex, callback)在哪里?-
regex是一个正则表达式,用于匹配从站点地图中提取的URL。regex可以是str或已编译的regex对象。 -
回调是用于处理与正则表达式匹配的URL的回调。
callback可以是字符串(指示spider方法的名称)或可调用的。
例如::
sitemap_rules = [('/product/', 'parse_product')]
规则按顺序应用,只使用第一个匹配的规则。
如果省略此属性,则在站点地图中找到的所有URL都将使用
parse回调。 -
-
sitemap_follow¶ -
应遵循的站点地图正则表达式列表。这只适用于使用 Sitemap index files 指向其他站点 Mapfile 。
默认情况下,将遵循所有站点地图。
-
sitemap_alternate_links¶ -
指定是否为一个
url应该遵循。这些是同一网站的链接,使用同一网站内传递的另一种语言url块。例如::
<url> <loc>http://example.com/</loc> <xhtml:link rel="alternate" hreflang="de" href="http://example.com/de"/> </url>
用
sitemap_alternate_links设置,这将检索两个URL。用sitemap_alternate_links只有残疾人http://example.com/将被取回。sitemap_alternate_links残疾人。
-
sitemap_filter(entries)[源代码]¶ -
这是一个过滤器函数,可以重写该函数以根据其属性选择站点地图条目。
例如::
<url> <loc>http://example.com/</loc> <lastmod>2005-01-01</lastmod> </url>
我们可以定义一个
sitemap_filter要筛选的函数entries日期:from datetime import datetime from scrapy.spiders import SitemapSpider class FilteredSitemapSpider(SitemapSpider): name = 'filtered_sitemap_spider' allowed_domains = ['example.com'] sitemap_urls = ['http://example.com/sitemap.xml'] def sitemap_filter(self, entries): for entry in entries: date_time = datetime.strptime(entry['lastmod'], '%Y-%m-%d') if date_time.year >= 2005: yield entry
这只能找回
entries2005年及以后年份修改。条目是从站点地图文档中提取的dict对象。通常,键是标记名,值是其中的文本。
重要的是要注意:
-
由于loc属性是必需的,因此不带此标记的条目将被丢弃。
-
备用链接用键存储在列表中
alternate(见sitemap_alternate_links) -
名称空间被删除,因此名为
{{namespace}}tagname成为唯一tagname
如果省略此方法,则将处理站点地图中找到的所有条目,同时观察其他属性及其设置。
-
-
SiteMapSpider示例¶
最简单的示例:使用 parse 回叫:
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/sitemap.xml'] def parse(self, response): pass # ... scrape item here ...
使用特定回调处理某些URL,使用其他回调处理其他URL::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/sitemap.xml'] sitemap_rules = [ ('/product/', 'parse_product'), ('/category/', 'parse_category'), ] def parse_product(self, response): pass # ... scrape product ... def parse_category(self, response): pass # ... scrape category ...
遵循中定义的站点地图 robots.txt 文件,仅跟踪其URL包含 /sitemap_shop ::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/robots.txt'] sitemap_rules = [ ('/shop/', 'parse_shop'), ] sitemap_follow = ['/sitemap_shops'] def parse_shop(self, response): pass # ... scrape shop here ...
将SiteMapSpider与其他URL源合并::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/robots.txt'] sitemap_rules = [ ('/shop/', 'parse_shop'), ] other_urls = ['http://www.example.com/about'] def start_requests(self): requests = list(super(MySpider, self).start_requests()) requests += [scrapy.Request(x, self.parse_other) for x in self.other_urls] return requests def parse_shop(self, response): pass # ... scrape shop here ... def parse_other(self, response): pass # ... scrape other here ...
CrawlSpider¶
-
class
scrapy.spiders.CrawlSpider[源代码]¶ -
这是最常用的爬行常规网站的蜘蛛,因为它通过定义一组规则为跟踪链接提供了一种方便的机制。它可能不是最适合您的特定网站或项目的,但它对于某些情况来说已经足够通用了,因此您可以从它开始,并根据需要覆盖它以获得更多的自定义功能,或者只实现您自己的蜘蛛。
除了从spider继承的属性(必须指定),这个类还支持一个新的属性:
-
rules¶ -
这是一个(或多个)列表
Rule物体。各Rule定义对网站进行爬行的特定行为。规则对象如下所述。如果多个规则与同一链接匹配,则将根据在该属性中定义的顺序使用第一个规则。
这个蜘蛛还公开了一个可重写的方法:
-
parse_start_url(response, **kwargs)[源代码]¶ -
为spider中的url生成的每个响应调用此方法
start_urls属性。它允许解析初始响应,并且必须返回 item object ,ARequest对象,或包含任何对象的iterable。
-
爬行规则¶
-
class
scrapy.spiders.Rule(link_extractor=None, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None, errback=None)[源代码]¶ -
link_extractor是一个 Link Extractor 对象,该对象定义如何从每个已爬网页提取链接。每个生成的链接将用于生成Request对象,其中包含链接的文本meta字典(在link_text键)。如果省略,将使用没有参数创建的默认链接提取器,从而导致提取所有链接。callback对用指定的链接提取程序提取的每个链接调用的可调用或字符串(在这种情况下,将使用具有该名称的spider对象中的方法)。此回调接收Response作为第一个参数,必须返回 item objects 和/或Request对象(或其任何子类)。如上所述,收到Response对象将包含生成Request在其meta字典(在link_text关键)cb_kwargs是包含要传递给回调函数的关键字参数的dict。follow是一个布尔值,用于指定是否从使用此规则提取的每个响应中遵循链接。如果callback没有follow默认为True,否则默认为False.process_links是一个可调用的,或一个字符串(在这种情况下,将使用具有该名称的蜘蛛对象中的方法),对于使用指定的link_extractor. 这主要用于过滤目的。process_request是可调用的(或字符串,在这种情况下,将使用具有该名称的spider对象中的方法),它将为Request按此规则提取。此可调用文件应将所述请求作为第一个参数,并且Response从中发出请求作为第二个参数。它必须返回Request对象或None(过滤掉请求)。errback在处理规则生成的请求时引发任何异常时要调用的可调用或字符串(在这种情况下,将使用来自spider对象的具有该名称的方法)。它收到一个Twisted Failure实例作为第一个参数。
警告
由于其内部实现,在编写时必须显式设置新请求的回调 CrawlSpider -基于蜘蛛;否则会发生意外行为。
2.0 新版功能: 这个 错误 参数。
爬行蜘蛛示例¶
现在让我们来看一个例子,爬行蜘蛛的规则是:
import scrapy from scrapy.spiders import CrawlSpider, Rule from scrapy.linkextractors import LinkExtractor class MySpider(CrawlSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com'] rules = ( # Extract links matching 'category.php' (but not matching 'subsection.php') # and follow links from them (since no callback means follow=True by default). Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))), # Extract links matching 'item.php' and parse them with the spider's method parse_item Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'), ) def parse_item(self, response): self.logger.info('Hi, this is an item page! %s', response.url) item = scrapy.Item() item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)') item['name'] = response.xpath('//td[@id="item_name"]/text()').get() item['description'] = response.xpath('//td[@id="item_description"]/text()').get() item['link_text'] = response.meta['link_text'] url = response.xpath('//td[@id="additional_data"]/@href').get() return response.follow(url, self.parse_additional_page, cb_kwargs=dict(item=item)) def parse_additional_page(self, response, item): item['additional_data'] = response.xpath('//p[@id="additional_data"]/text()').get() return item
这个蜘蛛会开始对example.com的主页进行爬行,收集类别链接和项目链接,并用 parse_item 方法。对于每个项目响应,将使用xpath从HTML中提取一些数据,并且 Item 会装满它的。
爬行规则¶
-
class
scrapy.spiders.Rule(link_extractor=None, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None, errback=None)[源代码]¶ -
link_extractor是一个 Link Extractor 对象,该对象定义如何从每个已爬网页提取链接。每个生成的链接将用于生成Request对象,其中包含链接的文本meta字典(在link_text键)。如果省略,将使用没有参数创建的默认链接提取器,从而导致提取所有链接。callback对用指定的链接提取程序提取的每个链接调用的可调用或字符串(在这种情况下,将使用具有该名称的spider对象中的方法)。此回调接收Response作为第一个参数,必须返回 item objects 和/或Request对象(或其任何子类)。如上所述,收到Response对象将包含生成Request在其meta字典(在link_text关键)cb_kwargs是包含要传递给回调函数的关键字参数的dict。follow是一个布尔值,用于指定是否从使用此规则提取的每个响应中遵循链接。如果callback没有follow默认为True,否则默认为False.process_links是一个可调用的,或一个字符串(在这种情况下,将使用具有该名称的蜘蛛对象中的方法),对于使用指定的link_extractor. 这主要用于过滤目的。process_request是可调用的(或字符串,在这种情况下,将使用具有该名称的spider对象中的方法),它将为Request按此规则提取。此可调用文件应将所述请求作为第一个参数,并且Response从中发出请求作为第二个参数。它必须返回Request对象或None(过滤掉请求)。errback在处理规则生成的请求时引发任何异常时要调用的可调用或字符串(在这种情况下,将使用来自spider对象的具有该名称的方法)。它收到一个Twisted Failure实例作为第一个参数。
警告
由于其内部实现,在编写时必须显式设置新请求的回调 CrawlSpider -基于蜘蛛;否则会发生意外行为。
2.0 新版功能: 这个 错误 参数。
爬行蜘蛛示例¶
现在让我们来看一个例子,爬行蜘蛛的规则是:
import scrapy from scrapy.spiders import CrawlSpider, Rule from scrapy.linkextractors import LinkExtractor class MySpider(CrawlSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com'] rules = ( # Extract links matching 'category.php' (but not matching 'subsection.php') # and follow links from them (since no callback means follow=True by default). Rule(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))), # Extract links matching 'item.php' and parse them with the spider's method parse_item Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'), ) def parse_item(self, response): self.logger.info('Hi, this is an item page! %s', response.url) item = scrapy.Item() item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)') item['name'] = response.xpath('//td[@id="item_name"]/text()').get() item['description'] = response.xpath('//td[@id="item_description"]/text()').get() item['link_text'] = response.meta['link_text'] url = response.xpath('//td[@id="additional_data"]/@href').get() return response.follow(url, self.parse_additional_page, cb_kwargs=dict(item=item)) def parse_additional_page(self, response, item): item['additional_data'] = response.xpath('//p[@id="additional_data"]/text()').get() return item
这个蜘蛛会开始对example.com的主页进行爬行,收集类别链接和项目链接,并用 parse_item 方法。对于每个项目响应,将使用xpath从HTML中提取一些数据,并且 Item 会装满它的。
XMLFeedSpider¶
-
class
scrapy.spiders.XMLFeedSpider[源代码]¶ -
XMLFeedSpider是为解析XML提要而设计的,它通过使用特定的节点名对这些提要进行迭代。迭代器可以从以下选项中选择:
iternodes,xml和html. 建议使用iternodes由于性能原因,迭代器xml和html迭代器一次生成整个DOM以便解析它。然而,使用html因为迭代器在分析带有错误标记的XML时可能很有用。要设置迭代器和标记名,必须定义以下类属性:
-
iterator¶ -
定义要使用的迭代器的字符串。它可以是:
-
'iternodes'-基于正则表达式的快速迭代器 -
'html'-使用的迭代器Selector. 请记住,这使用了DOM解析,必须将所有的DOM加载到内存中,这对于大型提要来说可能是一个问题。 -
'xml'-使用的迭代器Selector. 请记住,这使用了DOM解析,必须将所有的DOM加载到内存中,这对于大型提要来说可能是一个问题。
默认为:
'iternodes'. -
-
itertag¶ -
具有要迭代的节点(或元素)名称的字符串。例子::
itertag = 'product'
-
namespaces¶ -
列表
(prefix, uri)定义该文档中可用的命名空间的元组,这些命名空间将使用此蜘蛛进行处理。这个prefix和uri将用于使用register_namespace()方法。然后,可以在
itertag属性。例子::
class YourSpider(XMLFeedSpider): namespaces = [('n', 'http://www.sitemaps.org/schemas/sitemap/0.9')] itertag = 'n:url' # ...
除了这些新属性之外,这个蜘蛛还具有以下可重写的方法:
-
adapt_response(response)[源代码]¶ -
一种方法,当响应从蜘蛛中间件到达时,在蜘蛛开始解析它之前,立即接收响应。它可以用于在解析响应体之前对其进行修改。此方法接收响应并返回响应(可以是相同的或另一个响应)。
-
parse_node(response, selector)[源代码]¶ -
对与提供的标记名匹配的节点调用此方法 (
itertag)接收响应和Selector对于每个节点。重写此方法是必需的。否则,你的蜘蛛就不能工作了。此方法必须返回 item object ,ARequest对象,或包含任何对象的iterable。
-
process_results(response, results)[源代码]¶ -
这个方法是为spider返回的每个结果(项或请求)调用的,它用于在将结果返回到框架核心之前执行所需的任何最后一次处理,例如设置项id。它接收结果列表和产生这些结果的响应。它必须返回结果列表(项或请求)。
-
警告
由于其内部实现,在编写时必须显式设置新请求的回调 XMLFeedSpider -基于蜘蛛;否则会发生意外行为。
XmlFeedSpider示例¶
这些蜘蛛很容易使用,让我们来看一个例子:
from scrapy.spiders import XMLFeedSpider from myproject.items import TestItem class MySpider(XMLFeedSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com/feed.xml'] iterator = 'iternodes' # This is actually unnecessary, since it's the default value itertag = 'item' def parse_node(self, response, node): self.logger.info('Hi, this is a <%s> node!: %s', self.itertag, ''.join(node.getall())) item = TestItem() item['id'] = node.xpath('@id').get() item['name'] = node.xpath('name').get() item['description'] = node.xpath('description').get() return item
基本上,我们所做的就是创建一个蜘蛛,从给定的 start_urls ,然后遍历 item 标签,打印出来,并将一些随机数据存储在 Item .
XmlFeedSpider示例¶
这些蜘蛛很容易使用,让我们来看一个例子:
from scrapy.spiders import XMLFeedSpider from myproject.items import TestItem class MySpider(XMLFeedSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com/feed.xml'] iterator = 'iternodes' # This is actually unnecessary, since it's the default value itertag = 'item' def parse_node(self, response, node): self.logger.info('Hi, this is a <%s> node!: %s', self.itertag, ''.join(node.getall())) item = TestItem() item['id'] = node.xpath('@id').get() item['name'] = node.xpath('name').get() item['description'] = node.xpath('description').get() return item
基本上,我们所做的就是创建一个蜘蛛,从给定的 start_urls ,然后遍历 item 标签,打印出来,并将一些随机数据存储在 Item .
CSVFeedSpider¶
-
class
scrapy.spiders.CSVFeedSpider[源代码]¶ -
这个spider与xmlFeedSpider非常相似,只是它迭代行,而不是节点。在每次迭代中被调用的方法是
parse_row().-
delimiter¶ -
带有csv文件中每个字段分隔符的字符串默认为
','(逗号)
-
quotechar¶ -
带有csv文件中每个字段的外壳字符的字符串默认为
'"'(引号)。
-
headers¶ -
csv文件中的列名列表。
-
parse_row(response, row)[源代码]¶ -
接收响应和dict(代表每一行),其中为csv文件的每个提供的(或检测到的)头文件都有一个键。这个蜘蛛还提供了超越的机会
adapt_response和process_results用于预处理和后处理目的的方法。
-
CSVFeedspider示例¶
我们来看一个类似于前一个的例子,但是使用 CSVFeedSpider ::
from scrapy.spiders import CSVFeedSpider from myproject.items import TestItem class MySpider(CSVFeedSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com/feed.csv'] delimiter = ';' quotechar = "'" headers = ['id', 'name', 'description'] def parse_row(self, response, row): self.logger.info('Hi, this is a row!: %r', row) item = TestItem() item['id'] = row['id'] item['name'] = row['name'] item['description'] = row['description'] return item
CSVFeedspider示例¶
我们来看一个类似于前一个的例子,但是使用 CSVFeedSpider ::
from scrapy.spiders import CSVFeedSpider from myproject.items import TestItem class MySpider(CSVFeedSpider): name = 'example.com' allowed_domains = ['example.com'] start_urls = ['http://www.example.com/feed.csv'] delimiter = ';' quotechar = "'" headers = ['id', 'name', 'description'] def parse_row(self, response, row): self.logger.info('Hi, this is a row!: %r', row) item = TestItem() item['id'] = row['id'] item['name'] = row['name'] item['description'] = row['description'] return item
SitemapSpider¶
-
class
scrapy.spiders.SitemapSpider[源代码]¶ -
SiteMapSpider允许您通过使用 Sitemaps .
它支持嵌套的站点地图和从中发现站点地图URL robots.txt .
-
sitemap_urls¶ -
指向要爬网其URL的网站地图的URL列表。
您也可以指向 robots.txt 它将被解析为从中提取站点地图URL。
-
sitemap_rules¶ -
元组列表
(regex, callback)在哪里?-
regex是一个正则表达式,用于匹配从站点地图中提取的URL。regex可以是str或已编译的regex对象。 -
回调是用于处理与正则表达式匹配的URL的回调。
callback可以是字符串(指示spider方法的名称)或可调用的。
例如::
sitemap_rules = [('/product/', 'parse_product')]
规则按顺序应用,只使用第一个匹配的规则。
如果省略此属性,则在站点地图中找到的所有URL都将使用
parse回调。 -
-
sitemap_follow¶ -
应遵循的站点地图正则表达式列表。这只适用于使用 Sitemap index files 指向其他站点 Mapfile 。
默认情况下,将遵循所有站点地图。
-
sitemap_alternate_links¶ -
指定是否为一个
url应该遵循。这些是同一网站的链接,使用同一网站内传递的另一种语言url块。例如::
<url> <loc>http://example.com/</loc> <xhtml:link rel="alternate" hreflang="de" href="http://example.com/de"/> </url>
用
sitemap_alternate_links设置,这将检索两个URL。用sitemap_alternate_links只有残疾人http://example.com/将被取回。sitemap_alternate_links残疾人。
-
sitemap_filter(entries)[源代码]¶ -
这是一个过滤器函数,可以重写该函数以根据其属性选择站点地图条目。
例如::
<url> <loc>http://example.com/</loc> <lastmod>2005-01-01</lastmod> </url>
我们可以定义一个
sitemap_filter要筛选的函数entries日期:from datetime import datetime from scrapy.spiders import SitemapSpider class FilteredSitemapSpider(SitemapSpider): name = 'filtered_sitemap_spider' allowed_domains = ['example.com'] sitemap_urls = ['http://example.com/sitemap.xml'] def sitemap_filter(self, entries): for entry in entries: date_time = datetime.strptime(entry['lastmod'], '%Y-%m-%d') if date_time.year >= 2005: yield entry
这只能找回
entries2005年及以后年份修改。条目是从站点地图文档中提取的dict对象。通常,键是标记名,值是其中的文本。
重要的是要注意:
-
由于loc属性是必需的,因此不带此标记的条目将被丢弃。
-
备用链接用键存储在列表中
alternate(见sitemap_alternate_links) -
名称空间被删除,因此名为
{{namespace}}tagname成为唯一tagname
如果省略此方法,则将处理站点地图中找到的所有条目,同时观察其他属性及其设置。
-
-
SiteMapSpider示例¶
最简单的示例:使用 parse 回叫:
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/sitemap.xml'] def parse(self, response): pass # ... scrape item here ...
使用特定回调处理某些URL,使用其他回调处理其他URL::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/sitemap.xml'] sitemap_rules = [ ('/product/', 'parse_product'), ('/category/', 'parse_category'), ] def parse_product(self, response): pass # ... scrape product ... def parse_category(self, response): pass # ... scrape category ...
遵循中定义的站点地图 robots.txt 文件,仅跟踪其URL包含 /sitemap_shop ::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/robots.txt'] sitemap_rules = [ ('/shop/', 'parse_shop'), ] sitemap_follow = ['/sitemap_shops'] def parse_shop(self, response): pass # ... scrape shop here ...
将SiteMapSpider与其他URL源合并::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/robots.txt'] sitemap_rules = [ ('/shop/', 'parse_shop'), ] other_urls = ['http://www.example.com/about'] def start_requests(self): requests = list(super(MySpider, self).start_requests()) requests += [scrapy.Request(x, self.parse_other) for x in self.other_urls] return requests def parse_shop(self, response): pass # ... scrape shop here ... def parse_other(self, response): pass # ... scrape other here ...
SiteMapSpider示例¶
最简单的示例:使用 parse 回叫:
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/sitemap.xml'] def parse(self, response): pass # ... scrape item here ...
使用特定回调处理某些URL,使用其他回调处理其他URL::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/sitemap.xml'] sitemap_rules = [ ('/product/', 'parse_product'), ('/category/', 'parse_category'), ] def parse_product(self, response): pass # ... scrape product ... def parse_category(self, response): pass # ... scrape category ...
遵循中定义的站点地图 robots.txt 文件,仅跟踪其URL包含 /sitemap_shop ::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/robots.txt'] sitemap_rules = [ ('/shop/', 'parse_shop'), ] sitemap_follow = ['/sitemap_shops'] def parse_shop(self, response): pass # ... scrape shop here ...
将SiteMapSpider与其他URL源合并::
from scrapy.spiders import SitemapSpider class MySpider(SitemapSpider): sitemap_urls = ['http://www.example.com/robots.txt'] sitemap_rules = [ ('/shop/', 'parse_shop'), ] other_urls = ['http://www.example.com/about'] def start_requests(self): requests = list(super(MySpider, self).start_requests()) requests += [scrapy.Request(x, self.parse_other) for x in self.other_urls] return requests def parse_shop(self, response): pass # ... scrape shop here ... def parse_other(self, response): pass # ... scrape other here ...