Scrapy概述
Scrapy 是一個(gè)基于 Twisted 的異步處理框架,是純 Python 實(shí)現(xiàn)的爬蟲框架,其架構(gòu)清晰, 模塊之間的耦合程度低,可擴(kuò)展性極強(qiáng),可以靈活完成各種需求。 我們只需要定制開發(fā)幾個(gè)模塊就可以輕松實(shí)現(xiàn)一個(gè)爬蟲。它可以用來抓取Web站點(diǎn)并從頁面中提取結(jié)構(gòu)化的數(shù)據(jù),被廣泛的用于數(shù)據(jù)挖掘、數(shù)據(jù)監(jiān)測(cè)和自動(dòng)化測(cè)試等領(lǐng)域。下圖展示了Scrapy的基本架構(gòu),其中包含了主要組件和系統(tǒng)的數(shù)據(jù)處理流程(圖中帶數(shù)字的紅色箭頭)。

組件
- Scrapy引擎(Engine):Scrapy引擎是用來控制整個(gè)系統(tǒng)的數(shù)據(jù)處理流程。(數(shù)據(jù)流處理、觸發(fā)事物、核心)
- 調(diào)度器(Scheduler):調(diào)度器從Scrapy引擎接受請(qǐng)求并排序列入隊(duì)列,并在Scrapy引擎發(fā)出請(qǐng)求后返還給它們。
- 下載器(Downloader):下載器的主要職責(zé)是抓取網(wǎng)頁并將網(wǎng)頁內(nèi)容返還給蜘蛛(Spiders)。
- 蜘蛛(Spiders):蜘蛛是有Scrapy用戶自定義的用來解析網(wǎng)頁并抓取特定URL返回的內(nèi)容的類,每個(gè)蜘蛛都能處理一個(gè)域名或一組域名,簡(jiǎn)單的說就是用來定義特定網(wǎng)站的抓取和解析規(guī)則。(負(fù)責(zé)解析響應(yīng),生成提取結(jié)果和新的請(qǐng)求)
- 條目管道(Item Pipeline):條目管道的主要責(zé)任是負(fù)責(zé)處理有蜘蛛從網(wǎng)頁中抽取的數(shù)據(jù)條目,它的主要任務(wù)是清理、驗(yàn)證和存儲(chǔ)數(shù)據(jù)。當(dāng)頁面被蜘蛛解析后,將被發(fā)送到條目管道,并經(jīng)過幾個(gè)特定的次序處理數(shù)據(jù)。每個(gè)條目管道組件都是一個(gè)Python類,它們獲取了數(shù)據(jù)條目并執(zhí)行對(duì)數(shù)據(jù)條目進(jìn)行處理的方法,同時(shí)還需要確定是否需要在條目管道中繼續(xù)執(zhí)行下一步或是直接丟棄掉不處理。條目管道通常執(zhí)行的任務(wù)有:清理HTML數(shù)據(jù)、驗(yàn)證解析到的數(shù)據(jù)(檢查條目是否包含必要的字段)、檢查是不是重復(fù)數(shù)據(jù)(如果重復(fù)就丟棄)、將解析到的數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)(關(guān)系型數(shù)據(jù)庫(kù)或NoSQL數(shù)據(jù)庫(kù))中。
- 中間件(Middlewares):中間件是介于Scrapy引擎和其他組件之間的一個(gè)鉤子框架,主要是為了提供自定義的代碼來拓展Scrapy的功能,包括下載器中間件和蜘蛛中間件。
數(shù)據(jù)處理流程
Scrapy的整個(gè)數(shù)據(jù)處理流程由Scrapy引擎進(jìn)行控制,通常的運(yùn)轉(zhuǎn)流程包括以下的步驟:
引擎詢問蜘蛛需要處理哪個(gè)網(wǎng)站,并讓蜘蛛將第一個(gè)需要處理的URL交給它。
引擎讓調(diào)度器將需要處理的URL放在隊(duì)列中。
引擎從調(diào)度那獲取接下來進(jìn)行爬取的頁面。
調(diào)度將下一個(gè)爬取的URL返回給引擎,引擎將它通過下載中間件發(fā)送到下載器。
當(dāng)網(wǎng)頁被下載器下載完成以后,響應(yīng)內(nèi)容通過下載中間件被發(fā)送到引擎;如果下載失敗了,引擎會(huì)通知調(diào)度器記錄這個(gè)URL,待會(huì)再重新下載。
引擎收到下載器的響應(yīng)并將它通過蜘蛛中間件發(fā)送到蜘蛛進(jìn)行處理。
蜘蛛處理響應(yīng)并返回爬取到的數(shù)據(jù)條目,此外還要將需要跟進(jìn)的新的URL發(fā)送給引擎。
引擎將抓取到的數(shù)據(jù)條目送入條目管道,把新的URL發(fā)送給調(diào)度器放入隊(duì)列中。
上述操作中的2-8步會(huì)一直重復(fù)直到調(diào)度器中沒有需要請(qǐng)求的URL,爬蟲停止工作。
安裝Scrapy
推薦使用Anacinda安裝:
conda install Scrapy
直接在已有的Python環(huán)境中安裝Scrapy:
a. 安裝lxml
pip install lxml
b.安裝pyOpenSSL
下載wheel文件
使用pip install后接下載文件路徑完成安裝
c.安裝Twisted

使用pip install后接下載文件路徑完成安裝
d.安裝PyWin32
下載wheel文件
使用pip install后接下載文件路徑完成安裝
也可以嘗試直接使用pip install pywin32命令嘗試,如果能夠成功便無須下載wheel文件
e.執(zhí)行pip install scrapy
簡(jiǎn)單使用
創(chuàng)建項(xiàng)目
scrapy startproject book

創(chuàng)建爬蟲
scrapy genspider douban book.douban.com
genspider后的兩個(gè)參數(shù):第一個(gè)表示爬蟲的名稱,第二個(gè)表示網(wǎng)站的域名

使用編譯器打開創(chuàng)建的項(xiàng)目

添加爬蟲內(nèi)容
爬取目標(biāo):編程類圖書
分析網(wǎng)絡(luò)請(qǐng)求:https://book.douban.com/tag/%E7%BC%96%E7%A8%8B?start=0&type=T(get請(qǐng)求、start后面的數(shù)字表示當(dāng)前頁數(shù)的20倍。通過循環(huán)生成頁數(shù)即可模擬翻頁發(fā)出的請(qǐng)求。因?yàn)閮?nèi)容比較多,本次只爬取前三十頁作為演示)
分析網(wǎng)頁結(jié)構(gòu):每一頁有二十本圖書的信息,每本圖書信息保存在一個(gè)li標(biāo)簽中,所以首先拿到li標(biāo)簽,在進(jìn)行下一步操作。繼續(xù)獲取圖書鏈接,書籍名稱,基本信息及簡(jiǎn)介。
爬取內(nèi)容:圖書鏈接,書籍名稱,基本信息及簡(jiǎn)介。
def start_requests(self):
headers = {
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)',
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4,zh-TW;q=0.2,mt;q=0.2',
'Connection': 'keep-alive',
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
}
for i in range(33):
yield scrapy.Request(url='https://book.douban.com/tag/%E7%BC%96%E7%A8%8B?start={}&type=T'.format(i),
headers=headers,
method='GET',
callback=self.parse,
)
創(chuàng)建對(duì)象
class BookItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
book_link = scrapy.Field()
book_name = scrapy.Field()
book_info = scrapy.Field()
book_explain = scrapy.Field()
解析對(duì)象
def parse(self, response):
book_all = response.xpath('//*[@id="subject_list"]/ul/li')
for book_one in book_all:
book = BookItem()
book['book_link'] = book_one.xpath('./div[@class="info"]/h2/a/@href').extract_first().strip()
book['book_name'] = book_one.xpath('./div[@class="info"]/h2/a/@title').extract_first().strip()
book['book_info'] = book_one.xpath('./div[@class="info"]/div[@class="pub"]/text()').extract_first().strip()
book['book_explain'] = book_one.xpath('./div[@class="info"]/p/text()').extract_first().strip()
yield book
修改配置文件
ROBOTSTXT_OBEY = False
SPIDER_MIDDLEWARES = {
'book.middlewares.BookSpiderMiddleware': 543,
}
FEED_EXPORT_ENCODING = 'utf-8'
執(zhí)行啟動(dòng)爬蟲的命令,并保存爬取內(nèi)容
scrapy crawl douban -o result.json
爬取內(nèi)容部分展示
