前面兩章介紹了scrapy的安裝和項目的新建,那麼這一章就講講spider吧。html
scrapy有個命令是runspider, 這個命令的做用就是將一個spider當作一個python文件去執行,而不用建立一個完整的項目。能夠說是最簡單的一個爬蟲項目了,只有一個文件,這也體現出了spider對於scrapy的重要性,item和pipline無關緊要,settings等也可使用默認的,但是spider必須本身構造。而咱們寫爬蟲的時候大部分時間和精力也是耗費在這裏,因此spider的重要性就不言而喻了。python
此次教程將結合官方文檔和源碼一塊兒來說解,但願你們可以喜歡。dom
首先看看官方文檔對於spider的介紹:scrapy
最上面一段就不解釋了,就是介紹spider的做用和功能。對於spider來講主要經歷以下幾件事:ide
1.根據url生成Request並指定回調方法處理Response。第一個Request是經過start_requests()產生的,該方法下面會講到。
post
2. 在回調方法中,解析頁面的Response,返回Item實例或者Request實例,或者這兩種實例的可迭代對象。網站
3.在回調方法中,一般使用Selectors(也可使用BeautifulSoup,lxml等)來提取數據。this
4.最後spider會return item給Pipline完成數據的清洗,持久化等操做。url
scrapy爲咱們提供了幾款基礎的spider,咱們須要繼承這些來實現本身的spider。咱們接下來就根據資料及源碼來了解它們。spa
class scrapy.spiders.Spider 下面是它的源碼:
class Spider(object_ref): """Base class for scrapy spiders. All spiders must inherit from this class. """ name = None custom_settings = None def __init__(self, name=None, **kwargs): if name is not None: self.name = name elif not getattr(self, 'name', None): raise ValueError("%s must have a name" % type(self).__name__) self.__dict__.update(kwargs) if not hasattr(self, 'start_urls'): self.start_urls = [] @property def logger(self): logger = logging.getLogger(self.name) return logging.LoggerAdapter(logger, {'spider': self}) def log(self, message, level=logging.DEBUG, **kw): """Log the given message at the given log level This helper wraps a log call to the logger within the spider, but you can use it directly (e.g. Spider.logger.info('msg')) or use any other Python logger too. """ self.logger.log(level, message, **kw) @classmethod def from_crawler(cls, crawler, *args, **kwargs): spider = cls(*args, **kwargs) spider._set_crawler(crawler) return spider def set_crawler(self, crawler): warnings.warn("set_crawler is deprecated, instantiate and bound the " "spider to this crawler with from_crawler method " "instead.", category=ScrapyDeprecationWarning, stacklevel=2) assert not hasattr(self, 'crawler'), "Spider already bounded to a " \ "crawler" self._set_crawler(crawler) def _set_crawler(self, crawler): self.crawler = crawler self.settings = crawler.settings crawler.signals.connect(self.close, signals.spider_closed) def start_requests(self): for url in self.start_urls: yield self.make_requests_from_url(url) def make_requests_from_url(self, url): return Request(url, dont_filter=True) def parse(self, response): raise NotImplementedError @classmethod def update_settings(cls, settings): settings.setdict(cls.custom_settings or {}, priority='spider') @classmethod def handles_request(cls, request): return url_is_from_spider(request.url, cls) @staticmethod def close(spider, reason): closed = getattr(spider, 'closed', None) if callable(closed): return closed(reason) def __str__(self): return "<%s %r at 0x%0x>" % (type(self).__name__, self.name, id(self)) __repr__ = __str__
該類的基類是object_ref,其定義以下圖所示:
從源碼中能夠看到這個類的子類的實例都會記錄它自己的存活情況,這個做用會在之後講解,目前用不到。
類scrapy.spiders.Spider 是最簡單的spider,全部的spider包括本身定義的和scrapy提供的都會繼承它。它只是提供最基本的特性,也是我最經常使用的spider類。
name:
這個屬性是字符串變量,是這個類的名稱,代碼會經過它來定位spider,因此它必須惟一,它是spider最重要的屬性。回頭看看源碼中__init__的定義,能夠發現這個屬性是能夠修改的,若是不喜歡或者有須要重命名spider的name,能夠在啓動的時候傳參修改name屬性。
allowed_domains:
這個屬性是一個列表,裏面記載了容許採集的網站的域名,該值若是沒定義或者爲空時表示全部的域名都不進行過濾操做。若是url的域名不在這個變量中,那麼這個url將不會被處理。不想使用域名過濾功能時能夠在settings中註釋掉OffsiteMiddleware, 我的不建議這麼作。
start_urls:
這個屬性是一個列表或者元組,其做用是存放起始urls,至關於此次任務的種子。使用默認模板建立spider時,該值是個元組,建立元組而且只有一個元素時須要在元素後面添加「,」來消除歧義,否則會報錯:「ValueError: Missing scheme in request url: h」。這邊常常有人出錯,爲了不這個錯誤能夠根據上一章內容,將模板中start_urls的值設置爲列表。
custom_settings:
這個屬性值是一個字典,存放settings鍵值對,用於覆蓋項目中的settings.py的值,能夠作到在一個項目中的不一樣spider能夠有不一樣的配置。不過這個值要慎用,有些settings的值覆蓋也沒有起做用,eg:「LOG_FILE」。若是想每一個spider都有本身的log文件的話就不能這麼作。由於日誌操做在這個方法執行以前,那麼不管怎麼改都改不了以前的行爲。不過這個問題scrapy研發團隊已經注意到了,相信不久的未來會進行處理的。
crawler:
這個值從源碼能夠看出來自於方法from_crawler()。該值是一個Crawler 實例, 其做用後面的教程會講解,這邊就不細說了。
settings:
這個值也是來自於方法from_crawler()。是一個Settings 實例,這個後面也會細說,稍安勿躁哈。
logger:
顧名思義,記錄日誌用的,也是後面講,耐心等候哈。
from_crawler:
這是一個類方法,scrapy建立spider的時候會調用。調用位置在crawler.py 的類Crawler中,源碼能夠本身去看看,就不帶你們看了。這個方法的源碼在上面,咱們能夠看到,在實例化這個spider之後,這個實例纔有的settings和crawler屬性,因此在__init__方法中是無法訪問這倆屬性的。若是非要在__init__方法中使用相關屬性,那麼只能重寫該方法,你們能夠嘗試寫寫。
start_requests():
這個方法必須返回一個可迭代對象,切記!!!!上面就有源碼很簡單,就不細說了。若是想對屬性start_urls作一些操做(增刪改),並但願結果做爲種子url去採集網站的時候,能夠重寫這個方法來實現。有了這個方法,甚至都不用在代碼中定義start_urls。好比咱們想要讀取持久化的url執行採集操做,那麼就不必轉存進start_urls裏面,能夠直接請求這些urls。當種子urls須要post請求的話,也須要重寫該方法。
make_requests_from_url(url):
這個方法顧名思義,要是還不懂就看看上面的源碼。這裏只說一點,由於這裏的Request初始化沒有回調方法,就是默認採用parse方法做爲回調。另外這裏的dont_filter值爲True,這個值的做用是該url不會被過濾,至於具體細節請聽下回分解。
parse(self, response):
這個方法對於有經驗的同窗來講再熟悉不過了,我就簡單的說說。這個方法做爲默認回調方法,Request沒有指定回調方法的時候會調用它,這個回調方法和別的回調方法同樣返回值只能是Request, 字典和item對象,或者它們的可迭代對象。
log(message[, level, component]):
這個方法是對logger的包裝,看看源碼就好,沒什麼什麼可說的。
closed(reason):
當這個spider結束時這個方法會被調用,參數是一個字符串,是結束的緣由。這種用法之後會介紹,這裏只需記住,想在spider結束時作一些操做時能夠寫在這裏。
scrapy基礎spider算是介紹完了,有興趣的小夥伴能夠對照一個好的實例來看這個文章,或許幫助更大。若是有什麼疑問,你們能夠在評論區討論,共同進步。