scrapy框架基本使用
- 創建工程
- scrapy startproject proName
- 進入工程目錄
- cd proName
- 創建爬蟲文件
- scrapy genspider spiderName www.xxx.com
- 編寫爬蟲文件
- 執行工程
- scrapy crawl spiderName
爬蟲文件的編寫
- 定義好了一個類,該類的父類是Spider,Spider是scrapy所有類的父類
- 類中定義好了三個屬性和一個方法
- name:爬蟲文件的名稱
- start_urls:起始url列表
- 作用:可以對列表中的url進行get請求的發送
- allow_domains:允許的域名
- parse(self, response):
- 將起始URL列表中的URL請求成功後,Response就是獲取的響應對象。在該方法中負責實現數據解析。
- Scrapy工程默認是遵守robots協議的,需要在配置文件中進行操作。
- 不遵從robots協議。
- 可以指定日誌的等級,這樣在輸出結果的時候就只會顯示出對應等級以上的日誌
- LOG_LEVEL = 'WARNING'
數據解析
- response.xpath()
- 注意:提取標籤內容時返回的不是字符串。可是Selector對象,字符串是存儲在該對象中的。需要調用extract()/getall()或者extract_first()/get()。將Selector對象中的字符串取出。
持久化存儲
- 基於終端指令:
- 只可以將parse方法中的返回值存儲到指定後綴的文本文件中。
- 通過指定方式執行工程
- scrapy crawl spiderName -o fileName.csv
- 基於管道:
- 實現流程:
- 1.在爬蟲文件中解析數據
- 2.在Item類中定義相關屬性(解析的數據有幾個字段就定義幾個屬性)
- item就是一個字典
- 3.將在爬蟲文件中解析的數據存儲封裝到Item對象中
- 只可以使用item['name'] = name來訪問屬性
- 4.將存儲瞭解析數據的Item對象提交給管道
- yield item
- 5.在管道文件中接收Item對象,且對其進行任意形式的持久化存儲操作
- process_item(self, item, spider)是用來接收爬蟲文件提交過來的item對象(一次只能接收一個item對象)。
- 6.在配置文件中開啓管道
- 如何實現數據的備份? -指的是將爬取到的一組數據存儲到多個不同的載體(文件、MySQL、Redis)中
- 持久化存儲的操作必須要寫在管道文件中。
- 一個管道類對應一種形式的持久化存儲。
- 如果想將數據存儲到多個載體中則必須要有多個管道類。
- 問題:那兩個管道類都接收到item,且對其進行持久化存儲,爬蟲文件提交的item可以同時提交給兩個管道類嗎?
- 爬蟲文件提交的item只可以提交給優先級最高的那一個管道類。
- 如何讓優先級低的管道類也可以獲取接收到item呢?
- 可以讓優先級高的管道類在process_item中通過return item的形式將item傳遞給下一個即將被執行的管道類。
手動請求發送實現的全棧數據爬取
- 如何通過代碼手動對指定的URL進行請求發送。
- yield scrapy.Request(next_url, callback=self.parse):get請求
- 如何手動發起post請求?
- yield scrapy.FormRequest(next_url, formdata, callback=self.parse)
- 注意:在scrapy中一般不發送post請求。
請求傳參
- 作用:實現深度爬取
- 深度爬取:爬取的數據沒有在同一頁面
- 實現:
- yield scrapy.Request(detail_url, callback=self.parse_detail, meta={"item": item})
- 可以將meta字典傳遞給callback
- callback接收meta:
- meta = response.meta
- item = meta['item]
如何提高scrapy的爬取效率?
- 增加併發:
- 默認scrapy開啓的線程爲32/16個,可以適當進行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100 則併發設置成了100。
- 降低日誌級別:
- 在運行scrapy時,會有大量日誌信息的輸出,爲了減少CPU的使用率,可以設置log輸出信息爲INFO或者ERROR或者WARNING即可。在配置文件中編寫:LOG_LEVEL = 'INFO'
- 禁止cookie:
- 如果不是真的需要cookie,則在scrapy爬取數據時可以禁止cookie,從而減少CPU的使用率,提升爬取效率。在配置文件中編寫:COOKIES_ENABLED = False
- 禁止重試:
- 對失敗的HTTP進行重新請求(重試),會減慢爬取速度。因此可以禁止重試。在配置文件中編寫:RETRY_ENABLED = False
- 減少下載超時:
- 如果對一個非常慢的鏈接進行爬取。減少下載超時可以能讓卡住的鏈接快速被放棄,從而提升效率。在配置文件中編寫:DOWNLOAD_TIMEOUT = 10 則設置超時時間爲十秒。
中間件
- 下載中間件
- 爬蟲中間件
- 作用:
- 下載中間件處於引擎和下載器之間,批量攔截請求和響應。
- 攔截請求
- process_request(self, request, spider):每次發起請求請求都會被該方法攔截到。
- 參數request就是攔截到的請求
- 參數spider表示的就是爬蟲文件中爬蟲實例化好的對象,可以實現中間件和爬蟲類之間的數據交互
- 請求頭的僞裝。
- process_request:
- request.headers['xxxx'] = 'xxx'
- 代理
- process_exception:
- request.meta['proxy'] = 'http://ip:port'
- 攔截響應。
- process_response(self, request, response, spider):只要返回一個響應就會被該方法攔截到。
- 篡改響應數據。
- 攔截異常的請求對象
- process_exception(self, request, exception, spider):只要有異常的請求就會被該方法攔截到。該方法負責對異常的請求進行修正。且使用return request將修正後的請求對象進行重新發送。
CrawlSpider
是Spider的一個子類,之前創建的爬蟲文件的爬蟲類的父類就是Spider
作用:用於實現全站數據爬取
使用:
- 創建工程
- cd 工程目錄
- 創建爬蟲文件:
- scrapy genspider -t crawl spiderName www.xxx.com
- 執行工程
鏈接提取器、規則解析器是crawlspider獨有的
鏈接提取器LinkExtractor
- link = LinkExtractor(allow=r'Items/')
- 實例化一個鏈接提取器對象
- 作用:根據指定規則(allow)進行鏈接(url)的提取。
規則解析器Rule
- rules = ( Rule(link, callback='parse_item', follow=True), )
- 實例化一個Rule對象,用的是該對象的構造方法。
- 作用:可以接受鏈接提取器提取到的鏈接去對其進行請求發送,然後根據指定形式(callback)進行解析
- follow=True:將每一頁碼以此作爲起始的url,可以捕獲到所有頁碼對應的url
注意:
- 1.一個鏈接提取器對應一個規則解析器。
- 2.可以有多個鏈接提取器和規則解析器。
- 3.使用CrawlSpider實現深度爬取的話,最好結合着手動請求發送一起使用。
- 4.如何使用CrawlSpider將一個網站中所有的鏈接捕獲到?
- LinkExtractor(allow=r'') 即可
follow=True:
- 讓鏈接提取器繼續作用到(鏈接提取器)所提取到的鏈接對應的頁面中。
分佈式
- 概念:使用多臺機器搭建一個分佈式機羣在分佈式機羣中共同運行同一組程序,讓其對於同一個網絡資源進行聯合數據爬取。
- 原生的scrapy框架是無法實現分佈式?
- 調度器無法被分佈式機羣共享。
- 管道無法被共享。 -如何實現分佈式?
- 使用scrapy結合的scrapy-redis組件實現分佈式。
- scrapy-redis組件作用:
- 給scrapy提供可以被共享的管道和調度器。
- pip install scrapy-redis
- 實現流程:
- 1.創建工程。
- 2.cd 工程。
- 3.創建爬蟲文件。
- 基於CrawlSpider的爬蟲文件
- 4.修改爬蟲文件。
- 導包:from scrapy_redis.spiders import RedisCrawlSpider
- 修改當前爬蟲類的父類:RedisCrawlSpider
- 刪除start_urls,添加一個新屬性:
- redis_key = 'xxx',可以被共享的調度器隊列的名稱
- 基於常規的操作獲取URL,發送請求解析數據。
- 5.修改配置文件settings.py
- 增加一個去重容器類的配置。作用,使redis的set集合來存儲請求的指紋數據,從而實現請求去重的持久化。
- DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
- 使用scrapy_redis組件自己的調度器。
- SCHEDULER = "scrapy_redis.scheduler.Scheduler"
- 配置調度器是否要持久化,也就是當爬蟲結束了,要不要清空ready中請求隊列和去重指紋的set。如果是True,則表示要持久化存儲。就不清空數據。否則清空數據。
- SCHEDULER_PERSIST = True
- 指定管道:
- ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400 }
- 指定redis服務器:
- REDIS_HOST = 'redis服務的ip地址'
- REDIS_PORT = 6379
- 6.對redis的配置文件進行配置(redis.windows.conf)
- 取消默認綁定。
- 將bind 127.0.0.1進行註釋
- 關閉保護模式。
- protected-mode yes:將yes改爲no
- 7.啓動redis的服務器和客戶端
- redis服務端的啓動:
- 在終端裏執行:redis-server.exe redis.windows.conf
- 8.執行分佈式程序
- 9.向調度器的隊列中扔入一個起始的url:
- 在redis-cli:lpush sunQueue 爬取的url
- redis-cli:
- proName:items命名的數據結構
增量式
- 概念:監測網站數據更新的情況,爬取最新更新出來的數據。
- 核心:去重
- 實現增量:
- 對爬取數據的url進行檢測,使用一個記錄表存儲爬取過得數據的url,但凡記錄表中存有的URL,說明URL對應數據爬取過了,否則表示沒有爬取過爲新數據
- 記錄表:
- redis的set集合充當記錄表