DC-01:爬蟲(chóng)框架scrapy入門(mén)
本主題主要是scrapy入門(mén),包含內(nèi)容如下:
??1. Scrapy框架環(huán)境搭建;
??2. 理解scrapy框架結(jié)構(gòu);
??3. 理解并能處理簡(jiǎn)單的數(shù)據(jù)流;
??
如果想關(guān)注爬蟲(chóng)的高級(jí)技術(shù)與應(yīng)用場(chǎng)景,請(qǐng)關(guān)注后繼內(nèi)容與馬哥教育。這個(gè)系列包括數(shù)據(jù)采集,數(shù)據(jù)分析與數(shù)據(jù)可視化。
一、Scrapy安裝
??Scrapy的安裝是比較簡(jiǎn)單的,直接使用pip可以完成最新版本的安裝。
??
??目前最新版本是:1.6。
1.官網(wǎng)地址
??Scrapy的官方地址是:https://scrapy.org !
2. 安裝
??安裝指令
pip install scrapy
??安裝過(guò)程
3. 測(cè)試安裝
??只需要啟動(dòng)python交互式編程終端,看看能否import模塊scrapy即可;
4. scrapy幫助
??在交互式編程終端,使用import引入scrapy模塊,并使用help(scrapy)獲取scrapy框架API整體模塊結(jié)構(gòu)(其他更加詳細(xì)的幫助可以使用help與dir獲?。?div id="u0z1t8os" class="image-package">
scrapy幫助使用截圖
5. 教程與參考資料
??最好的教程我個(gè)人認(rèn)為還是官方的教程+API幫助。
二、Scrapy組件結(jié)構(gòu)與工作流程
1. 核心組件介紹
1.1. 組件01:引擎(Scrapy Engine)
??Scrapy Engine引擎作用有兩個(gè):
????1. 控制Scrapy框架中所有組件之間的數(shù)據(jù)流;
????2. 并在某些爬取動(dòng)作發(fā)生的時(shí)候觸發(fā)數(shù)據(jù)處理事件。
1.2. 組件02:調(diào)度器(Scheduler)
??調(diào)度器(Scheduler)接收來(lái)自引擎的請(qǐng)求,并將它們排隊(duì),以便在引擎請(qǐng)求時(shí)向引擎提供這些請(qǐng)求。
1.3. 組件03:下載器(Downloader)
??下載者(Downloader)負(fù)責(zé)下載網(wǎng)頁(yè)并將其發(fā)送給引擎,引擎把下載的網(wǎng)頁(yè)發(fā)送給蜘蛛/爬蟲(chóng)處理。
1.4. 組件04:蜘蛛/爬蟲(chóng)(Spiders)
??蜘蛛/爬蟲(chóng)(Spider)負(fù)責(zé)解析下載器下載的網(wǎng)頁(yè),并從中提取數(shù)據(jù)項(xiàng)(ITEM)(也稱為爬取項(xiàng))或后續(xù)的爬取請(qǐng)求。
??蜘蛛/爬蟲(chóng)(Spider)一般由用戶實(shí)現(xiàn),用來(lái)實(shí)現(xiàn)用戶的爬取邏輯。一般繼承Spider類(lèi)來(lái)定制實(shí)現(xiàn)。
1.5. 組件05:數(shù)據(jù)項(xiàng)管道(Item Pipeline)
??數(shù)據(jù)項(xiàng)管道(Item Pipeline)負(fù)責(zé)處理被蜘蛛/爬蟲(chóng)提?。ɑ蚺廊。┑臄?shù)據(jù)項(xiàng)。典型的任務(wù)包括:
????1. 清理;
????2. 驗(yàn)證;
????3. 持久存儲(chǔ)(如將數(shù)據(jù)項(xiàng)存儲(chǔ)在數(shù)據(jù)庫(kù)關(guān)系數(shù)據(jù)庫(kù)或者NoSQL數(shù)據(jù)庫(kù)中)。
1.6. 組件06:下載器中間件(Downloader middlewares)
??下載器中間件(Downloader middlewares)是位于引擎和下載器之間的特定功能的回調(diào)Hook,負(fù)責(zé)處理從引擎?zhèn)鬟f到下載器時(shí)處理請(qǐng)求,以及從下載器傳遞到引擎的響應(yīng)。
??使用下載器中間件(Downloader middlewares)的幾種情況:
????1. 在將請(qǐng)求發(fā)送給下載者之前處理該請(qǐng)求(即在Scrapy將請(qǐng)求發(fā)送到網(wǎng)站之前);
????2. 在傳遞給spider之前改變接受到的響應(yīng);
????3. 重新發(fā)送新的請(qǐng)求,而不是將收到的響應(yīng)傳遞給spider;
????4. 在沒(méi)有爬取到網(wǎng)頁(yè)的情況下,發(fā)送一個(gè)響應(yīng)給spider;
????5. 需要根據(jù)條件放棄一些請(qǐng)求。
1.7. 組件07:蜘蛛/爬蟲(chóng)中間件(Spider middlewares)
??蜘蛛/爬蟲(chóng)中間件(Spider middlewares)是位于引擎和蜘蛛之間的特定功能的Hook,負(fù)責(zé)處理Spider的輸入(響應(yīng))和輸出(數(shù)據(jù)項(xiàng)或者請(qǐng)求)。
??蜘蛛/爬蟲(chóng)中間件(Spider middlewares)的幾種情況:
????1. spider回調(diào)的輸出后的處理:包含:更改/添加/刪除請(qǐng)求或數(shù)據(jù)項(xiàng);
????2. 開(kāi)始請(qǐng)求的后處理;
????3. 處理spider異常;
????4. 對(duì)一些基于響應(yīng)內(nèi)容的請(qǐng)求調(diào)用errback,而不是回調(diào)。
2. 核心工作流程
??Scrapy的工作流程是按照爬取的數(shù)據(jù)設(shè)計(jì)的流程,并據(jù)此設(shè)計(jì)組件結(jié)構(gòu)。(下圖是來(lái)自Scrapy的官方文檔)
scrapy框架核心組件與數(shù)據(jù)流示意圖
2.1. 流程01-獲取請(qǐng)求
??引擎從蜘蛛獲取需要爬取的初始請(qǐng)求。
????源:Spider
????目標(biāo):Engine
????數(shù)據(jù):請(qǐng)求
2.2. 流程02-請(qǐng)求調(diào)度安排
??引擎調(diào)度爬取請(qǐng)求到調(diào)度器,并申請(qǐng)下一個(gè)需要爬取的爬取請(qǐng)求。
????源:Engine
????目標(biāo):Scheduler
????數(shù)據(jù):請(qǐng)求
2.3. 流程03-調(diào)度爬取請(qǐng)求
??引擎器返回下一個(gè)爬取請(qǐng)求給引擎。(為什么不直接爬取,而是需要經(jīng)過(guò)調(diào)度器處理呢?調(diào)度的好處在于:多任務(wù)爬取,還可以處理爬取請(qǐng)求與爬取過(guò)程的時(shí)間不一致的時(shí)間差。)
????源:Scheduler
????目標(biāo):Engine
????數(shù)據(jù):請(qǐng)求
2.4. 流程04-發(fā)送請(qǐng)求給下載器
??引擎將請(qǐng)求發(fā)送到下載器,并通過(guò)下載器中間軟件傳遞(process_request回調(diào)函數(shù)可以處理請(qǐng)求數(shù)據(jù))。
????源:Engine
????目標(biāo):Downloader
????數(shù)據(jù):請(qǐng)求
2.5. 流程05-下載器完成下載
??一旦頁(yè)面下載器完成頁(yè)面下載,下載器將使用下載好的頁(yè)面生成一個(gè)響應(yīng)(使用該頁(yè)面),并將其發(fā)送到引擎,通過(guò)下載器中間軟件(process_response回調(diào)函數(shù)完成下載后的頁(yè)面數(shù)據(jù)處理)。
????源:Downloader
????目標(biāo):Engine
????數(shù)據(jù):響應(yīng)
2.6. 流程06-數(shù)據(jù)項(xiàng)抽取
??引擎從下載器接收響應(yīng)并將其發(fā)送到spider進(jìn)行處理,并通過(guò)spider中間件進(jìn)行處理(process_spider_input回調(diào)函數(shù)處理爬取的網(wǎng)頁(yè)數(shù)據(jù))。
????源:Engine
????目標(biāo):Spider
????數(shù)據(jù):響應(yīng)
2.7. 流程07-返回抽取的數(shù)據(jù)與請(qǐng)求
??Spider處理響應(yīng)(從爬取的網(wǎng)頁(yè)中抽取需要的數(shù)據(jù)項(xiàng)),并通過(guò)spider中間件(process_spider_output回調(diào)函數(shù)處理Spider處理過(guò)的數(shù)據(jù))向引擎返回抽取的數(shù)據(jù)項(xiàng)或者新的附加請(qǐng)求。
????源:Spider
????目標(biāo):Engine
????數(shù)據(jù):數(shù)據(jù)項(xiàng)(附加的請(qǐng)求)
2.8. 流程08-存儲(chǔ)抽取的數(shù)據(jù)項(xiàng)
??引擎將已處理的數(shù)據(jù)項(xiàng)發(fā)送到數(shù)據(jù)項(xiàng)管道,然后將已附加的請(qǐng)求發(fā)送到調(diào)度程序,并請(qǐng)求可能的下一個(gè)請(qǐng)求進(jìn)行爬取。
????源:Engine
????目標(biāo):Item Pipeline/Scheduler
????數(shù)據(jù):數(shù)據(jù)項(xiàng)/附加請(qǐng)求
2.9. 流程09-結(jié)束爬取
??重復(fù)01-08,直到調(diào)度器中沒(méi)有請(qǐng)求調(diào)度為止。
三、Scrapy入門(mén)
??這個(gè)入門(mén)是按照官方的教程組織。
??不是上面介紹的每個(gè)組件都需要我們開(kāi)發(fā),實(shí)際只需要我們開(kāi)發(fā)業(yè)務(wù)部分,爬蟲(chóng)的通用功能部分都封裝到框架中,所以我們需要一個(gè)框架的環(huán)境,并理解整個(gè)工作流程,并關(guān)注需要開(kāi)發(fā)的部分,以及開(kāi)發(fā)部分與整個(gè)框架組件的關(guān)系。
1. 創(chuàng)建一個(gè)爬蟲(chóng)項(xiàng)目
??爬蟲(chóng)項(xiàng)目使用scrapy框架提供的一個(gè)工具創(chuàng)建:scrapy,該工具創(chuàng)建的項(xiàng)目會(huì)提供業(yè)務(wù)部分運(yùn)行的環(huán)境與配置。
1.1. scrapy工具介紹
1.1.1. 獲取scrapy工具幫助
??直接在終端輸入scrapy,可以直接輸出scrapy工具的幫助。
命令:
localhost:~ yangqiang$ scrapy
??其中startproject命令項(xiàng)就是我們馬上要使用來(lái)創(chuàng)建項(xiàng)目的。
1.1.2. 獲取startproject命令項(xiàng)幫助
??獲取幫助的指令:
localhost:~ yangqiang$ scrapy startproject -h
創(chuàng)建爬蟲(chóng)項(xiàng)目指令startproject幫助獲取截圖
1.2. 使用scrapy工具創(chuàng)建一個(gè)爬蟲(chóng)項(xiàng)目
??創(chuàng)建爬蟲(chóng)項(xiàng)目的兩個(gè)重要參數(shù):
????1. 項(xiàng)目名稱
????2. 項(xiàng)目存放目錄(可選,默認(rèn)當(dāng)前目錄)
1.2.1. 創(chuàng)建項(xiàng)目
localhost:codes yangqiang$ scrapy startproject FirstScrapy
創(chuàng)建項(xiàng)目過(guò)程與結(jié)果截圖
1.2.2. 創(chuàng)建好的項(xiàng)目文件
??可以查看創(chuàng)建的項(xiàng)目,其中的文件結(jié)合上面的組件與工作流程,大致也知道其用途與作用。
創(chuàng)建的爬蟲(chóng)項(xiàng)目工程
1.3. 使用pycharn打開(kāi)創(chuàng)建的項(xiàng)目
??可以使用pycharm IDE工具打開(kāi)創(chuàng)建的爬蟲(chóng)項(xiàng)目:
使用pycharm打開(kāi)爬蟲(chóng)項(xiàng)目工程
2. 實(shí)現(xiàn)爬蟲(chóng)業(yè)務(wù)
??因?yàn)樵诳蚣茉陂_(kāi)發(fā),為了保證框架能順利工作,需要按照設(shè)計(jì)的結(jié)構(gòu),繼承scrapy.Spider類(lèi),并發(fā)起一個(gè)爬取請(qǐng)求,并處理。
2.1. 創(chuàng)建爬蟲(chóng)代碼模塊
??在項(xiàng)目的spiders包路徑下,創(chuàng)建一個(gè)python源代碼文件:spiders.home_spider.py。
使用pycharm創(chuàng)建的爬蟲(chóng)代碼模塊
2.2. 繼承Spider
??由于Spider是抽象類(lèi),需要override其中的抽象函數(shù)。
def parse(self, response):
raise NotImplementedError('{}.parse callback is not defined'.format(self.__class__.__name__))
??繼承Spider類(lèi)后的子類(lèi):
# coding = utf-8
import scrapy
class HomeSpider(scrapy.Spider):
def parse(self, response):
pass
2.3. 爬蟲(chóng)中兩個(gè)重要的屬性
2.3.1. name屬性
??name屬性,用來(lái)在執(zhí)行爬蟲(chóng)的時(shí)候指定爬蟲(chóng)。屬性類(lèi)型是字符串。
2.3.2. start_urls屬性
??start_urls屬性用來(lái)發(fā)起一個(gè)爬蟲(chóng)任務(wù)請(qǐng)求。屬性類(lèi)型是列表。
2.3.3. 屬性實(shí)現(xiàn)代碼
# coding = utf-8
import scrapy
class HomeSpider(scrapy.Spider):
name = 'home'
start_urls = [
'https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1',
]
def parse(self, response):
pass
3. scrapy工具與運(yùn)行爬蟲(chóng)項(xiàng)目
3.1. 在項(xiàng)目目錄下的scrapy工具的幫助
??在scrapy工具創(chuàng)建的爬蟲(chóng)項(xiàng)目頂層目錄下,執(zhí)行scrapy工具獲取的幫助會(huì)更多。
??命令:
localhost:FirstScrapy yangqiang$ scrapy
??執(zhí)行效果:
在爬蟲(chóng)項(xiàng)目目錄下獲取scrapy工具與在其他地方得到的幫助內(nèi)容存在不同
??與項(xiàng)目相關(guān)的命令有(6個(gè)):
????list:列出項(xiàng)目中爬蟲(chóng)列表。
????check:檢查爬蟲(chóng)。
????crawl:?jiǎn)?dòng)爬蟲(chóng)任務(wù)。
????edit:編輯爬蟲(chóng)。
????fetch:獲取。
????parse:解析。
??上述命令的使用,使用幫助可以獲取。具體的使用在后面會(huì)介紹。
3.2. list爬蟲(chóng)
??命令:
localhost:FirstScrapy yangqiang$ scrapy list
??效果:
3.3. edit爬蟲(chóng)
??命令:
localhost:FirstScrapy yangqiang$ scrapy edit home
??一般不使用這個(gè)指令在字符界面下編輯,而是使用IDE工具編輯。不過(guò)遠(yuǎn)程維護(hù)使用字符界面是非常方便的,
??效果:
3.4. crawl爬蟲(chóng)-運(yùn)行爬蟲(chóng)
??命令:
localhost:FirstScrapy yangqiang$ scrapy crawl home
??使用該命令啟動(dòng)爬蟲(chóng)任務(wù),其中home是爬蟲(chóng)程序中name指定的爬蟲(chóng)名。
??效果:
3.5. check爬蟲(chóng)
??命令:
localhost:FirstScrapy yangqiang$ scrapy check home
??檢查爬蟲(chóng)代碼中的錯(cuò)誤。
??下面是沒(méi)有錯(cuò)誤的例子:
對(duì)沒(méi)有錯(cuò)誤的爬蟲(chóng)check執(zhí)行的截圖
??下面是有錯(cuò)誤的例子(隨便在代碼中設(shè)計(jì)幾個(gè)錯(cuò)誤即可)。
對(duì)存在語(yǔ)法錯(cuò)誤的爬蟲(chóng)代碼執(zhí)行check的截圖
3.6. parse爬蟲(chóng)
??parse命令用來(lái)測(cè)試爬蟲(chóng)的parse函數(shù)。
??parse命令的幫助:
??命令:
localhost:FirstScrapy yangqiang$ scrapy parse --spider=home https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1
??效果(當(dāng)沒(méi)有指定爬蟲(chóng)名,這會(huì)使用url直接創(chuàng)建一個(gè)爬蟲(chóng),但是scrapy存在bug,會(huì)報(bào)錯(cuò),在github上已經(jīng)有人修正這個(gè)bug,可以通過(guò)百度找到這個(gè)帖子):
3.7. fetch爬蟲(chóng)
??直接下載頁(yè)面,并顯示在終端。
??命令:
localhost:FirstScrapy yangqiang$ scrapy fetch https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1
??效果:
3.8. genspider生成爬蟲(chóng)
??genspider可以查看爬蟲(chóng)模板,創(chuàng)建爬蟲(chóng),編輯爬蟲(chóng)等功能。其幫助如下:
3.8.1. 查看模板
??一般默認(rèn)的模板是basic。
??命令:
localhost:FirstScrapy yangqiang$ scrapy genspider -l
??效果:
3.8.2. 創(chuàng)建爬蟲(chóng)
??命令:
localhost:FirstScrapy yangqiang$ scrapy genspider -t crawl myspider https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1
??效果:
使用genspide創(chuàng)建爬蟲(chóng)的過(guò)程截圖
??創(chuàng)建后,在項(xiàng)目工程中能看見(jiàn)這個(gè)爬蟲(chóng)代碼文件:!
在pycharm中查看創(chuàng)建的爬蟲(chóng)代碼模塊
3.8.3. 創(chuàng)建并編輯爬蟲(chóng)
??命令:
localhost:FirstScrapy yangqiang$ scrapy genspider -e myspider 'https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1'
??這個(gè)命令是先創(chuàng)建,后編輯。注意:編輯中需要項(xiàng)目的模塊導(dǎo)入,否則編輯不會(huì)正常。不過(guò)一般創(chuàng)建好以后,也不會(huì)在終端下編輯。
3.9. view查看爬取頁(yè)面
??該命令首先下載頁(yè)面,然后使用瀏覽器打開(kāi)。
??命令:
localhost:FirstScrapy yangqiang$ scrapy view https://www.baidu.com
??效果:
3.10. shell交互式爬蟲(chóng)處理
??使用交互式處理爬蟲(chóng)數(shù)據(jù)處理。與代碼一樣,只是交互式開(kāi)發(fā)模式。
??命令:
localhost:FirstScrapy yangqiang$ scrapy shell 'https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1'
??效果(綠色的表示代碼輸入):
??交互式編程示例:
3.11. settings獲取settings.py中的配置
??settings指令用來(lái)獲取與設(shè)置settings.py中的配置值。
??命令:
localhost:FirstScrapy yangqiang$ scrapy settings --get=SPIDER_MODULES
??效果:
使用settings指令獲取settings文件中定義的配置
??下面是settings.py文件:
3.12. runspider運(yùn)行爬蟲(chóng)文件
??這個(gè)命令是直接執(zhí)行爬蟲(chóng)代碼文件,與crawl的區(qū)別在于,crawl執(zhí)行的是爬蟲(chóng)項(xiàng)目spiders目錄下的有爬蟲(chóng)名的爬蟲(chóng)。
??命令:
localhost:FirstScrapy yangqiang$ scrapy runspider ./FirstScrapy/spiders/home_spider.py
??效果:
獨(dú)立于爬蟲(chóng)項(xiàng)目來(lái)執(zhí)行某個(gè)爬蟲(chóng)代碼
四、爬蟲(chóng)中的數(shù)據(jù)流與數(shù)據(jù)處理
1. 創(chuàng)建一個(gè)測(cè)試項(xiàng)目
??使用scrapy工具創(chuàng)建一個(gè)爬蟲(chóng)數(shù)據(jù)流與數(shù)據(jù)處理的測(cè)試項(xiàng)目。
??創(chuàng)建命令:
localhost:codes yangqiang$ scrapy startproject Scra_DataFlow
??創(chuàng)建過(guò)程:
創(chuàng)建一個(gè)數(shù)據(jù)流演示項(xiàng)目工程
??下面主要關(guān)注點(diǎn)在數(shù)據(jù)上,所以其他scarpy工具等使用細(xì)節(jié)可以參考上面的幫助。
??同時(shí),scrapy爬蟲(chóng)框架提供了一些快捷實(shí)現(xiàn)方式,下面都采用傳統(tǒng)的思路實(shí)現(xiàn),這樣容易理解,快捷方式的介紹不作為重點(diǎn),甚至不在這里介紹。
2. 爬蟲(chóng)目標(biāo)
2.1. 爬取站點(diǎn)
??爬取騰訊課堂上的數(shù)據(jù)。爬取騰訊課堂基礎(chǔ)課程中的Python付費(fèi)課程信息。
2.2. 爬取數(shù)據(jù)
??課程名稱,培訓(xùn)機(jī)構(gòu),購(gòu)買(mǎi)人數(shù),課程價(jià)格,開(kāi)課方式等。
2.3. 理解domain與url
??domain:https://ke.qq.com
??urls:https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1
3. 使用命令創(chuàng)建爬蟲(chóng)
??使用scrapy的genspider指令創(chuàng)建spider代碼模板。
??命令:
localhost:Scra_DataFlow yangqiang$ scrapy genspider -t basic course ke.qq.com
使用genspider用basic模板創(chuàng)建一個(gè)爬蟲(chóng)模塊
??創(chuàng)建好的代碼如下:
# -*- coding: utf-8 -*-
import scrapy
class CourseSpider(scrapy.Spider):
name = 'course'
allowed_domains = ['ke.qq.com']
start_urls = ['http://ke.qq.com/']
def parse(self, response):
pass
??在Pycharm中,代碼在項(xiàng)目中的截圖:
在pycharm中打開(kāi)創(chuàng)建的爬蟲(chóng)代碼
4. 爬取URL
??實(shí)際需要爬取的頁(yè)面URL為:
????https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1
??這是scrapy框架數(shù)據(jù)流的第01步。從爬蟲(chóng)發(fā)起一個(gè)請(qǐng)求。
??該請(qǐng)求,使用迭代器的方式返回給爬蟲(chóng)引擎:
????方式一:是引擎調(diào)用def start_requests(self)函數(shù),通過(guò)返回值得到請(qǐng)求。
????方式二:覆蓋父類(lèi)的start_urls屬性,用來(lái)替代默認(rèn)的 start_requests函數(shù),返回請(qǐng)求。
??然后爬蟲(chóng)引擎,把請(qǐng)求發(fā)送給調(diào)度器(流程02),根據(jù)處理資源的情況,引擎從調(diào)度器獲取請(qǐng)求(流程03),再發(fā)送給下載器(流程04)。
??下載器使用引擎發(fā)送過(guò)來(lái)的請(qǐng)求,完成下載任務(wù),并把下載的響應(yīng)返回給引擎(流程05)。引擎把響應(yīng)通過(guò)parse函數(shù)傳遞給爬蟲(chóng)程序(流程06),爬蟲(chóng)通過(guò)parse函數(shù)參數(shù),得到下載響應(yīng)。其中想用通過(guò)response對(duì)象獲取,該響應(yīng)對(duì)象的類(lèi)型是:<class 'scrapy.http.response.html.HtmlResponse'>。
??注意:流程01,02,03,04,05,06都是框架自動(dòng)完成,如果不做特別的處理,可以不干預(yù)框架的流程,直接在流程06的結(jié)束得到一個(gè)響應(yīng)對(duì)象。
??scrapy框架的數(shù)據(jù)流,注意其中的編號(hào),對(duì)應(yīng)這我們這里的一樣的編號(hào)。
為了查看方便,再顯示下官方的數(shù)據(jù)流示意圖
5. 通過(guò)parse函數(shù)的參數(shù),獲取下載響應(yīng)
5.1. scrapy.http.response.html.HtmlResponse類(lèi)
??數(shù)據(jù)成員:
????|- encoding
????|- selector
????|- text
????|- body
????|- meta
????|- url
??函數(shù)成員:
????|- body_as_unicode(self)
??????|- 返回一個(gè)unicode的body
????|- css(self, query)
????follow(self, url, callback=None, method='GET', headers=None, body=None, cookies=None, meta=None, encoding=None, priority=0, dont_filter=False, errback=None)
??????|- 返回Request類(lèi)型的對(duì)象。
????|- replace(self, *args, **kwargs)
????|- urljoin(self, url)
????|- xpath(self, query, **kwargs)
??獲取解碼后的文本頁(yè)面內(nèi)容。
????|- text
??數(shù)據(jù)解析接口:
????|- css(self, query)
????|- xpath(self, query, **kwargs)
5.2. 直接處理(中斷數(shù)據(jù)流)
5.2.1. 直接保存成文件
??這類(lèi)直接保存成html文本文件。
# -*- coding: utf-8 -*-
import scrapy
class CourseSpider(scrapy.Spider):
name = 'course'
allowed_domains = ['ke.qq.com']
start_urls = ['https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1']
def parse(self, response):
# 2019-02-14 15:00:14 [course] DEBUG: <class 'scrapy.http.response.html.HtmlResponse'>
# self.log(type(response))
# utf-8
# self.log(response.encoding)
# <Selector xpath=None data='<html lang="zh">\n<head>\n <meta charse'>
# self.log(response.selector)
# self.log(response.text) # unicode的文本內(nèi)容
# self.log(response.body) # 二進(jìn)制內(nèi)容
# {'download_timeout': 180.0, 'download_slot': 'ke.qq.com', 'download_latency': 0.592094898223877}
# self.log(response.meta)
# https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1
# self.log(response.url)
# 保存下載的頁(yè)面到文件,護(hù)或者到數(shù)據(jù)庫(kù)(可以考慮文檔數(shù)據(jù)庫(kù)或者mysql關(guān)系數(shù)據(jù)庫(kù))
with open('page.html', 'w') as fd:
fd.write(response.text)
??下載后保存的文件內(nèi)容。
5.2.2. 解析保存成csv文件
??從瀏覽器獲取XPATH格式(/html/body/section[1]/div/div[3]/ul):
從瀏覽器獲取xpath數(shù)據(jù)的截圖
??把瀏覽器中獲取的XPATH按照我們的需求修改:
????| - 瀏覽器XPATH:/html/body/section[1]/div/div[3]/ul
????| - 修改后XPATH://section[1]/div/div[3]/ul/li
??
??因?yàn)閄PATH是從body文檔開(kāi)始解析的,同時(shí)我們希望獲取頁(yè)面上24門(mén)課程的內(nèi)容。
??代碼如下:
# -*- coding: utf-8 -*-
import scrapy
class CourseSpider(scrapy.Spider):
name = 'course'
allowed_domains = ['ke.qq.com']
start_urls = ['https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1']
def parse(self, response):
# 解析數(shù)據(jù),并保存成csv文件。
result = response.xpath('//section[1]/div/div[3]/ul/li')
self.log('XXXX:{}'.format(len(result)))
??運(yùn)行爬蟲(chóng)的輸出結(jié)果是:
使用xpath獲取到我們需要爬取得24們課程列表截圖
??xpath返回的是一個(gè)list列表,其中元素的類(lèi)型是:<class 'scrapy.selector.unified.Selector'>,該類(lèi)型的API幫助可以使用help獲取。
??下面我們可以直接解析得到需要的字段(保存到csv的實(shí)現(xiàn),這里就略掉,其中使用了xpath或者css,這個(gè)知識(shí)點(diǎn),下面專(zhuān)門(mén)講解)。
# -*- coding: utf-8 -*-
import scrapy
class CourseSpider(scrapy.Spider):
name = 'course'
allowed_domains = ['ke.qq.com']
start_urls = ['https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1']
def parse(self, response):
# 解析數(shù)據(jù),并保存成csv文件。
result = response.xpath('//section[1]/div/div[3]/ul/li')
for course_ in result:
# self.log(type(course_))
# 課程名稱
course_name = course_.xpath('h4[@class="item-tt"]/a/text()').get()
self.log('課程名稱:{}'.format(course_name.strip() if course_name else ''))
# 培訓(xùn)機(jī)構(gòu)
course_organization = course_.xpath(
'div[@class="item-line item-line--middle"]/span[@class="item-source"]/a/text()').get()
self.log('培訓(xùn)機(jī)構(gòu):{}'.format(course_organization.strip() if course_organization else ''))
# 課程連接
course_link = course_.xpath('h4[@class="item-tt"]/a/@href').get()
self.log('課程連接:{}'.format(course_link.strip() if course_link else ''))
# 報(bào)名人數(shù)
course_number = course_.xpath(
'div[@class="item-line item-line--middle"]/span[@class="line-cell item-user"]/text()').get()
self.log('報(bào)名人數(shù):{}'.format(course_number.strip() if course_number else ''))
# 課程狀態(tài)
course_status = course_.xpath('div[@class="item-status"]/text()').get()
self.log('課程狀態(tài):{}'.format(course_status.strip() if course_status else ''))
# 課程價(jià)格
course_price = course_.xpath('div[@class="item-line item-line--bottom"]/span/text()').get()
self.log('課程價(jià)格:{}'.format(course_price.strip() if course_price else ''))
??解析的效果:
5.3. 返回?cái)?shù)據(jù)項(xiàng)到管道(流程07與流程08)
??在parse函數(shù)中,實(shí)際是可以返回?cái)?shù)據(jù)的:
????| - 返回的數(shù)據(jù)是Items,則引擎接受到數(shù)據(jù)后,會(huì)發(fā)送給管道Pipeline。
????| - 返回Request請(qǐng)求,則把Request發(fā)送給調(diào)度器,繼續(xù)爬取數(shù)據(jù)。
??
??這里只關(guān)注返回Items,返回Request的情路,后面說(shuō)明。
5.3.1. 定義Items的數(shù)據(jù)項(xiàng)
??繼承scrapy.Item類(lèi),對(duì)應(yīng)需要接續(xù)的字段定義數(shù)據(jù)項(xiàng)。
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class ScraDataflowItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 課程名稱
course_name = scrapy.Field()
# 培訓(xùn)機(jī)構(gòu)
course_organization = scrapy.Field()
# 課程連接
course_link = scrapy.Field()
# 報(bào)名人數(shù)
course_number = scrapy.Field()
# 課程狀態(tài)
course_status = scrapy.Field()
# 課程價(jià)格
course_price = scrapy.Field()
5.3.2. 使用數(shù)據(jù)項(xiàng),緩存爬取的數(shù)據(jù)字段
??使用數(shù)據(jù)項(xiàng)比較模式化,比較容易理解。 下面是實(shí)現(xiàn)代碼:
# -*- coding: utf-8 -*-
import scrapy
from Scra_DataFlow.items import ScraDataflowItem
class CourseSpider(scrapy.Spider):
name = 'course'
allowed_domains = ['ke.qq.com']
start_urls = ['https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1']
def parse(self, response):
result = response.xpath('//section[1]/div/div[3]/ul/li')
items = [] # 數(shù)據(jù)項(xiàng)數(shù)組列表
for course_ in result:
# 數(shù)據(jù)項(xiàng)
item_ = ScraDataflowItem()
course_name = course_.xpath('h4[@class="item-tt"]/a/text()').get()
item_['course_name'] = '{}'.format(course_name.strip() if course_name else '')
# 培訓(xùn)機(jī)構(gòu)
course_organization = course_.xpath(
'div[@class="item-line item-line--middle"]/span[@class="item-source"]/a/text()').get()
item_['course_organization'] = course_organization.strip() if course_organization else ''
# 課程連接
course_link = course_.xpath('h4[@class="item-tt"]/a/@href').get()
item_['course_link'] = course_link.strip() if course_link else ''
# 報(bào)名人數(shù)
course_number = course_.xpath(
'div[@class="item-line item-line--middle"]/span[@class="line-cell item-user"]/text()').get()
item_['course_number'] = course_number.strip() if course_number else ''
# 課程狀態(tài)
course_status = course_.xpath('div[@class="item-status"]/text()').get()
item_['course_status'] = course_status.strip() if course_status else ''
# 課程價(jià)格
course_price = course_.xpath('div[@class="item-line item-line--bottom"]/span/text()').get()
item_['course_price'] = course_price.strip() if course_price else ''
items.append(item_)
# 返回?cái)?shù)據(jù)項(xiàng)到管道
return items
5.3.3. 使用管道保存數(shù)據(jù)
??使用命令:
localhost:Scra_DataFlow yangqiang$ scrapy crawl course -o course.csv
??執(zhí)行過(guò)程:
輸出csv文件的爬蟲(chóng)執(zhí)行過(guò)程截圖
??提示:pycharm可以安裝csv的插件,用來(lái)顯示csv文件
??使用管道保存的文件(不使用插件在pycharm顯示):
使用管道保存的文件顯示截圖(pychar無(wú)插件文本顯示)
??使用管道保存的文件(使用插件在pycharm顯示)
附錄
??需要掌握爬蟲(chóng)的高級(jí)應(yīng)用,以及一些經(jīng)典場(chǎng)景應(yīng)用,可以關(guān)注后繼內(nèi)容與馬哥教育。
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。