一、Scrapy簡介 Scrapy是一個為了爬取網站數據,提取結構性數據而編寫的應用框架。 可以應用在包括數據挖掘,信息處理或存儲歷史數據等一系列的程式中。 Scrapy基於事件驅動網路框架 Twisted 編寫。因此,Scrapy基於併發性考慮由非阻塞(即非同步)的實現。 組件 Scrapy Eng ...
一、Scrapy簡介
Scrapy是一個為了爬取網站數據,提取結構性數據而編寫的應用框架。 可以應用在包括數據挖掘,信息處理或存儲歷史數據等一系列的程式中。
Scrapy基於事件驅動網路框架 Twisted 編寫。因此,Scrapy基於併發性考慮由非阻塞(即非同步)的實現。組件
Scrapy Engine
引擎負責控制數據流。
調度器(Scheduler)
調度器從引擎接受request並將他們入隊,以便之後引擎請求他們時提供給引擎。
下載器(Downloader)
下載器負責獲取頁面數據並提供給引擎,而後提供給spider。
Spiders
Spider是Scrapy用戶編寫用於分析response並提取item(即獲取到的item)或額外跟進的URL的類。 每個spider負責處理一個特定(或一些)網站。
Item Pipeline
Item Pipeline負責處理被spider提取出來的item。典型的處理有清理、 驗證及持久化(例如存取到資料庫中)。
下載器中間件(Downloader middlewares)
下載器中間件是在引擎及下載器之間的特定鉤子(specific hook),處理Downloader傳遞給引擎的response。 其提供了一個簡便的機制,通過插入自定義代碼來擴展Scrapy功能。
Spider中間件(Spider middlewares)
Spider中間件是在引擎及Spider之間的特定鉤子(specific hook),處理spider的輸入(response)和輸出(items及requests)。 其提供了一個簡便的機制,通過插入自定義代碼來擴展Scrapy功能。
二、Scrapy環境配置
安裝以下程式
- Python 2.7
- Python Package: pip and setuptools. 現在 pip 依賴 setuptools ,如果未安裝,則會自動安裝setuptools 。
- lxml. 大多數Linux發行版自帶了lxml。如果缺失,請查看http://lxml.de/installation.html
- OpenSSL. 除了Windows(請查看 平臺安裝指南)之外的系統都已經提供。
pip install pyopenssl
- Visual C++2008
- 安裝PyWin32
- pip install scrapy
創建工程模板
命令行執行:scrapy startproject 工程名
創建好的工程結構如下圖:
Idea中配置scrapy啟動
二、常用API說明
開發中主要涉及spider,item,Pipeline,settings模塊的開發。需要擴展插件則開發extions模塊。
Spider類
繼承scrapy.Spider類
屬性
name : 爬蟲名字,用於區別spider,唯一。
start_urls : Spider在啟動時進行爬取的url列表。後續的URL則從初始的URL獲取到的數據中提取。
方法
parse(self, response) :每個初始url爬取到的數據將通過response參數傳遞過來。此方法負責解析數據(response), 提取數據(生成Item),生成需要進一步處理的URL請求(request)。
scrapy.Request(url=link, errback=self.errback_http, callback=self.parse_article)
框架會對url=link的地址發起請求,如果請求出現錯誤執行用戶自定義的errback_http方法,如果請求成功則執行用戶自定義的parse_article方法。
Item類
需要繼承scrapy.Item。Item是一個dict(),用於存儲spider中parse()中解析到的數據,在pipeline中調用。
import scrapy class DmozItem(scrapy.Item): title = scrapy.Field() link = scrapy.Field() desc = scrapy.Field()提取Item
Scrapy Selector基於xpath和css提取元素。
xpath()
: 傳入xpath表達式,返回該表達式所對應的所有節點的selector list列表 。css()
: 傳入CSS表達式,返回該表達式所對應的所有節點的selector list列表.extract()
: 序列化該節點為unicode字元串並返回list。re()
: 根據傳入的正則表達式對數據進行提取,返回unicode字元串list列表。
運行爬蟲
在項目目錄下運行以下命令,即可執行爬蟲:
scrapy crawl NAME(爬蟲名字)
配置文件Settings
Settings文件可以可以控制包括核心(core),插件(extension),pipeline及spider組件。這裡只說3.settings模塊。
- 命令行選項(Command line Options)(最高優先順序)
- 每個spider的設定
- 項目設定模塊(Project settings module)
- 命令預設設定模塊(Default settings per-command)
- 全局預設設定(Default global settings) (最低優先順序)
訪問settings
如果需要使用該配置文件中定義的屬性,類(爬蟲,管道,插件)需要增加額外的類方法: from_crawler(cls, crawler)。
設定可以通過Crawler的 scrapy.crawler.Crawler.settings
屬性進行訪問。其由插件及中間件的from_crawler
方法所傳入:
class MyExtension(object): @classmethod def from_crawler(cls, crawler): settings = crawler.settings if settings['LOG_ENABLED']: print "log is enabled!"
也可以通過字典訪問,避免錯誤,建議使用setting API中的規範key值。
管道開發
管道類似過濾處理鏈,根據自定義業務依次處理Spider解析後的數據,例如數據驗證(去重、轉換),計算存儲(DB,NOSQL),發送消息(Kafka,MQ),報表生成。
開發自定義管道類需要兩步驟:
- 在pipelines中定義類並實現 process_item(self, item, spider) 方法, 其中item對象為spider解析後待處理的數據。
- 在settings中開啟管道配置信息,ITEM_PIPELINES 中配置自定義管道類名和執行序列。
說明
自定義管道根據序列號從小到大依次執行請求,如果拋出DropItem異常,後續管道將不會執行,例如數據出現重覆主鍵,可以拋出DropItem異常。
日誌開發
使用以下代碼在管道中定義日誌名稱
logger = logging.getLogger('pipelogger')
同時可以在包初始化文件__init__.py中定義日誌級別 : LOG_LEVEL = 'INFO'
日誌啟用也可以在settings中設置如下屬性
LOG_ENABLED = True #啟用日誌
LOG_ENCODING = 'utf-8' #設置日誌字元集
LOG_FILE = 'e://workspace/log/csdncrawl.log' #指定日誌文件及路徑
LOG_LEVEL = 'INFO' #定義日誌級別
LOG_STDOUT = True #是否將print語句列印內容輸出到日誌
擴展插件
開發者可自定義運行在不同階段的插件,例如打開爬蟲、關閉爬蟲、數據抓取等。
插件只需要關註:在什麼時候做什麼事情,即 狀態-方法。
開發插件只需要2步:
- 開發插件類,可定義在extensions.py文件中,在from_crawler中增加狀態-方法的映射關係,例如在打開爬蟲的時候執行spider_opened方法可這樣配置:
crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)
- 在settings中配置插件類,和管道定義類似, 其KEY為EXTENSIONS
四、代碼示例
Spider示例
import scrapy class DmozSpider(scrapy.Spider): name = "dmoz" allowed_domains = ["dmoz.org"] start_urls = [ "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/" ] def parse(self, response): for sel in response.xpath('//ul/li'): title = sel.xpath('a/text()').extract() link = sel.xpath('a/@href').extract() desc = sel.xpath('text()').extract() print title, link, desc
日誌Logging
import logginglogger = logging.getLogger('mycustomlogger')
logger.warning("This is a warning")
import logging
import scrapy
logger = logging.getLogger('mycustomlogger')
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['http://scrapinghub.com']
def parse(self, response):
logger.info('Parse function called on %s', response.url)
參考資料:
中文版scrapy資料地址:https://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/tutorial.html