本文轉載自以下鏈接:
https://scrapy-chs.readthedocs.io/zh_CN/latest/topics/spiders.html
https://doc.scrapy.org/en/latest/topics/spiders.html
1、Spiders
對spider來說,爬取的循環類似下文:
1.以初始的URL初始化Request,並設置回調函數。
當該request下載完畢並返回時,將生成response,並作為參數傳給該回調函數。
spider中初始的request是通過調用 start_requests()來獲取的。
start_requests()讀取 start_urls 中的URL, 並以 parse 為回調函數生成 Request 。
2.在回調函數內分析返回的(網頁)內容,返回 Item 對象或者 Request 或者一個包括二者的可迭代容器。
返回的Request對象之后會經過Scrapy處理,下載相應的內容,並調用設置的callback函數(函數可相同)。
3.在回調函數內,您可以使用 選擇器(Selectors)(您也可以使用BeautifulSoup, lxml 或者您想用的任何解析器)來分析網頁內容,並根據分析的數據生成item。
4.最后,由spider返回的item將被存到數據庫(由某些 Item Pipeline 處理)或使用 Feed exports 存入到文件中。
2、Spider參數
spider參數一般用來定義初始URL或者指定限制爬取網站的部分。 您也可以使用其來配置spider的任何功能。
在運行 crawl 時添加 -a 可以傳遞Spider參數:
scrapy crawl myspider -a category=electronics
Spider在構造器(constructor)中獲取參數:
import scrapy
class MySpider(Spider):
name = 'myspider'
def __init__(self, category=None, *args, **kwargs):
super(MySpider, self).__init__(*args, **kwargs)
self.start_urls = ['http://www.example.com/categories/%s' % category]
3、內置Spider參考手冊
Spider
class scrapy.spider.Spider
Spider是最簡單的spider。每個其他的spider必須繼承自該類(包括Scrapy自帶的其他spider以及您自己編寫的spider)。
Spider並沒有提供什么特殊的功能。 其僅僅請求給定的 start_urls/start_requests ,並根據返回的結果(resulting responses)調用spider的 parse 方法。
name
定義spider名字的字符串(string)。spider的名字定義了Scrapy如何定位(並初始化)spider,所以其必須是唯一的。
不過您可以生成多個相同的spider實例(instance),這沒有任何限制。 name是spider最重要的屬性,而且是必須的。
如果該spider爬取單個網站(single domain),一個常見的做法是以該網站(domain)(加或不加 后綴 )來命名spider。
例如,如果spider爬取 mywebsite.com ,該spider通常會被命名為 mywebsite 。
allowed_domains
可選。包含了spider允許爬取的域名(domain)列表(list)。 當 OffsiteMiddleware 啟用時, 域名不在列表中的URL不會被跟進。
具體咋生效的還不知道
start_urls
URL列表。當沒有制定特定的URL時,spider將從該列表中開始進行爬取。
因此,第一個被獲取到的頁面的URL將是該列表之一。 后續的URL將會從獲取到的數據中提取。
遍歷URL列表中的每個鏈接均發起Request請求獲取返回多個Response
custom_settings
A dictionary of settings that will be overridden from the project wide configuration when running this spider.
It must be defined as a class attribute since the settings are updated before instantiation.
使用的話需要覆蓋settings中的相關配置
class QuotesSpider(scrapy.Spider):
name = 'quotes'
allowed_domains = ['quotes.toscrape.com']
start_urls = ['http://quotes.toscrape.com/']
custom_settings = {
'DEFAULT_REQUEST_HEADERS':{
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
}
crawler
This attribute is set by the from_crawler() class method after initializating the class, and links to the Crawler object to which this spider instance is bound.
Crawlers encapsulate a lot of components in the project for their single entry access (such as extensions, middlewares, signals managers, etc). See Crawler API to know more about them.
settings
Configuration on which this spider is been ran. This is a Settings instance, see the Settings topic for a detailed introduction on this subject.
logger
Python logger created with the Spider’s name.
You can use it to send log messages through it as described on Logging from Spiders.
from_crawler(crawler, *args, **kwargs)
This is the class method used by Scrapy to create your spiders.
You probably won’t need to override this directly, since the default implementation acts as a proxy to the __init__() method, calling it with the given arguments args and named arguments kwargs.
Nonetheless, this method sets the crawler and settings attributes in the new instance, so they can be accessed later inside the spider’s code.
參數:
crawler (Crawler instance) – crawler to which the spider will be bound
args (list) – arguments passed to the __init__() method
kwargs (dict) – keyword arguments passed to the __init__() method
使用示例:
def __init__(self, mongo_url, mongo_db,*args, **kwargs):
super(QuotesSpider, self).__init__(*args, **kwargs)
self.mongo_uri = mongo_url
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
"""從settings文件獲取配置信息"""
return cls(
mongo_url=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DB')
)
start_requests()
該方法必須返回一個可迭代對象(iterable)。該對象包含了spider用於爬取的第一個Request。
當spider啟動爬取並且未指定URL時,該方法被調用。 當指定了URL時,make_requests_from_url() 將被調用來創建Request對象。
該方法僅僅會被Scrapy調用一次,因此您可以將其實現為生成器。
該方法的默認實現是使用 start_urls 的url生成Request。
如果您想要修改最初爬取某個網站的Request對象,您可以重寫(override)該方法。
例如,如果您需要在啟動時以POST登錄某個網站,你可以這么寫:
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
使用示例:
import scrapy
class HttpbinSpider(scrapy.Spider):
name = 'httpbin'
allowed_domains = ['httpbin.org']
start_urls = ['http://httpbin.org/post']
def start_requests(self):
yield scrapy.Request(url='http://httpbin.org/post',method='POST',callback=self.parse_post)
def parse(self, response):
pass
def parse_post(self,response):
print('Hello',response.headers)
make_requests_from_url(url) =>(新版本不再使用)
該方法接受一個URL並返回用於爬取的 Request 對象。 該方法在初始化request時被 start_requests() 調用,也被用於轉化url為request。
默認未被復寫(overridden)的情況下,該方法返回的Request對象中, parse() 作為回調函數,dont_filter參數也被設置為開啟。 (詳情參見 Request).
源碼:
def start_requests(self):
cls = self.__class__
if method_is_overridden(cls, Spider, 'make_requests_from_url'):
warnings.warn(
"Spider.make_requests_from_url method is deprecated; it "
"won't be called in future Scrapy releases. Please "
"override Spider.start_requests method instead (see %s.%s)." % (
cls.__module__, cls.__name__
),
)
for url in self.start_urls:
yield self.make_requests_from_url(url)
else:
for url in self.start_urls:
yield Request(url, dont_filter=True)
def make_requests_from_url(self, url):
""" This method is deprecated. """
return Request(url, dont_filter=True)
parse(response)
當response沒有指定回調函數時,該方法是Scrapy處理下載的response的默認方法。
parse 負責處理response並返回處理的數據以及(/或)跟進的URL。 Spider 對其他的Request的回調函數也有相同的要求。
該方法及其他的Request回調函數必須返回一個包含 Request 及(或) Item 的可迭代的對象。
參數: response (Response) – 用於分析的response
log(message[, level, component]) =>(新版本用法發生改變)
使用 scrapy.log.msg() 方法記錄(log)message。 log中自動帶上該spider的 name 屬性。 更多數據請參見 Logging 。
新版本使用示例:https://doc.scrapy.org/en/latest/topics/logging.html?highlight=logger
import scrapy
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['https://scrapinghub.com']
def parse(self, response):
self.logger.info('Parse function called on %s', response.url)
closed(reason)
當spider關閉時,該函數被調用。 該方法提供了一個替代調用signals.connect()來監聽 spider_closed 信號的快捷方式。
Let’s see an example:
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)
Return multiple Requests and items from a single callback:
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').extract():
yield {"title": h3}
for url in response.xpath('//a/@href').extract():
yield scrapy.Request(url, callback=self.parse)
Instead of start_urls you can use start_requests() directly; to give data more structure you can use Items:
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').extract():
yield MyItem(title=h3)
for url in response.xpath('//a/@href').extract():
yield scrapy.Request(url, callback=self.parse)