1. scrapy.CrawlSpider
scrapy框架提供了多種類型的spider,大致分為兩類,一類為基本spider(scrapy.Spider),另一類為通用spider(scrapy.spiders.CrawlSpider、scrapy.spiders.XMLFeedSpider、scrapy.spiders.CSVFeedSpider、scrapy.spiders.SitemapSpider),並且值得注意的是,通用spider類型,均繼承scrapy.Spider,那么我們在使用通用spider來抓取網頁的時候,其解析方法名不能是parse(那樣就重寫了其父類Spider的parse方法,造成沖突)。
為什么可以使用CrawlSpider進行全站抓取呢? 那么可以想像一下, 我們如果不使用它如何實現全站抓取, 首先我們需要解析一個網站的首頁, 解析出其所有的資源鏈接(ajax方式或綁定dom事件實現跳轉忽略),請求該頁面所有的資源鏈接, 再在資源鏈接下遞歸地查找子頁的資源鏈接,最后在我們需要的資源詳情頁結構化數據並持久化在文件中。這里只是簡單的介紹一下全站抓取的大致思路,事實上,其細節的實現,流程的控制是很復雜的,所以scrapy封裝了一個CrawlSpider,使得數據的爬取變得簡單高效,因為它通過定義一組規則為跟蹤鏈接提供了便利的機制。它可能不是最適合您的特定網站或項目,但它在幾種情況下足夠通用,因此您可以從它開始並根據需要覆蓋它以獲得更多自定義功能。
2. 重要屬性
A . rules:這是一個(或多個)Rule
對象的列表。每個都Rule
定義了爬網站點的特定行為。規則對象如下所述。如果多個規則匹配相同的鏈接,則將根據它們在此屬性中定義的順序使用第一個規則。
補充:class scrapy.spiders.
Rule
(link_extractor,callback = None,cb_kwargs = None,follow = None,process_links = None,process_request = None )
1.link_extractor
是一個Link Extractor對象,它定義如何從每個已爬網頁面中提取鏈接,可以是正則表達式,用於在跟進的時候篩選url(*重要*)。
2.callback
是一個可調用的或一個字符串(在這種情況下,將使用來自具有該名稱的spider對象的方法)為使用指定的link_extractor提取的每個鏈接調用。此回調接收響應作為其第一個參數,並且必須返回包含Item
和/或 Request
對象(或其任何子類)的列表(*重要*)。
3.cb_kwargs
是一個包含要傳遞給回調函數的關鍵字參數的dict。
4.follow
是一個布爾值,指定是否應該從使用此規則提取的每個響應中跟蹤鏈接。如果callback
是follow
默認值True
,則默認為False(*重要*)
。
5.process_links
是一個可調用的,或一個字符串(在這種情況下,將使用來自具有該名稱的spider對象的方法),將使用指定的每個響應從每個響應中提取的每個鏈接列表調用該方法link_extractor
。這主要用於過濾目的。
6.process_request
是一個可調用的,或一個字符串(在這種情況下,將使用來自具有該名稱的spider對象的方法),該方法將在此規則提取的每個請求中調用,並且必須返回請求或None(以過濾掉請求)
B . ...................(Spider的allowed_domains、start_urls等
)
3. 實戰需求
""" 爬取微信小程序社區所有教程(http://www.wxapp-union.com/portal.php?mod=list&catid=2),並以json格式存儲在文件中 """
4. 實現
補充:新建CrawlSpider模板的爬蟲的命令 scrapy genspider -t crawl wxappcrawl wxapp-union.com
settings.py
# Obey robots.txt rules ROBOTSTXT_OBEY = False # Override the default request headers: DEFAULT_REQUEST_HEADERS = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36', } DOWNLOAD_DELAY = 3 # Configure item pipelines # See https://doc.scrapy.org/en/latest/topics/item-pipeline.html ITEM_PIPELINES = { 'wxapp.pipelines.WxappPipeline': 300, }
wxappcrawl .py
1 # -*- coding: utf-8 -*- 2 import scrapy 3 from scrapy.linkextractors import LinkExtractor 4 from scrapy.spiders import CrawlSpider, Rule 5 from .. import items 6 7 8 class WxappcrawlSpider(CrawlSpider): 9 name = 'wxappcrawl' 10 allowed_domains = ['wxapp-union.com'] 11 start_urls = ['http://www.wxapp-union.com/portal.php?mod=list&catid=2&page=1'] 12 13 ''' 14 allow設置之后, 會在執行其父類(scrapy.Spider)的parse方法的時候, 提取response中符合這一正則的所有 15 url, 並添加到調度器下的請求隊列(無重復)中 16 ''' 17 rules = ( 18 # 爬取每一頁 19 Rule(LinkExtractor(allow=r'.+?mod=list&catid=2&page=\d'), follow=True), 20 # 爬取具體的文章頁 21 Rule(LinkExtractor(allow=r'.+/article-\d+-\d+\.html'), callback='parse_article', follow=False), 22 ) 23 24 def parse_article(self, response): 25 ''' 26 解析文章頁,並返回實體 27 ''' 28 article_title = response.xpath("//h1[@class='ph']/text()").get().strip() 29 article_author = response.xpath("//p[@class='authors']/a/text()").get().strip() 30 article_ctime = response.xpath("//p[@class='authors']/span[@class='time']/text()").get() 31 article_content_list = response.xpath("//td[@id='article_content']/*/text()").getall() 32 article_content = ''.join(article_content_list) 33 34 yield items.WxappItem( 35 title = article_title, 36 author = article_author, 37 ctime = article_ctime, 38 content = article_content 39 )
items.py
1 # -*- coding: utf-8 -*- 2 3 # Define here the models for your scraped items 4 # 5 # See documentation in: 6 # https://doc.scrapy.org/en/latest/topics/items.html 7 8 import scrapy 9 10 11 class WxappItem(scrapy.Item): 12 # define the fields for your item here like: 13 # name = scrapy.Field() 14 15 title = scrapy.Field() 16 author = scrapy.Field() 17 ctime = scrapy.Field() 18 content = scrapy.Field()
pipelines.py
1 # -*- coding: utf-8 -*- 2 3 # Define your item pipelines here 4 # 5 # Don't forget to add your pipeline to the ITEM_PIPELINES setting 6 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html 7 8 from scrapy.exporters import JsonLinesItemExporter 9 10 class WxappPipeline(object): 11 12 def __init__(self): 13 self.file = open('./wxapp.json', 'wb') 14 self.exporter = JsonLinesItemExporter(file=self.file, ensure_ascii=False, encoding='utf-8') 15 16 def open_spider(self, spider): 17 pass 18 19 def process_item(self, item, spider): 20 self.exporter.export_item(item) 21 return item 22 23 def close_spider(self, spider): 24 self.file.close()
run.py (在項目根目錄下(與scrapy.cfg同級)新建啟動爬蟲的py文件)
1 from scrapy import cmdline 2 3 cmdline.execute("scrapy crawl wxappcrawl".split()) 4 5 # cmdline.execute(['scrapy', 'crawl', 'wxappcrawl'])
哈哈·,收工!