前言
前兩關(guān),我們學(xué)習(xí)了能提升爬蟲速度的進(jìn)階知識(shí)——協(xié)程,并且通過(guò)項(xiàng)目實(shí)操,將協(xié)程運(yùn)用于抓取薄荷網(wǎng)的食物數(shù)據(jù)。
可能你在體驗(yàn)開發(fā)一個(gè)爬蟲項(xiàng)目的完整流程時(shí),會(huì)有這樣的感覺:原來(lái)要完成一個(gè)完整的爬蟲程序需要做這么多瑣碎的工作。
比如,要導(dǎo)入不同功能的模塊,還要編寫各種爬取流程的代碼。而且根據(jù)不同的項(xiàng)目,每次要編寫的代碼也不同。
不知道你會(huì)不會(huì)有這樣的想法:能不能有一個(gè)現(xiàn)成的爬蟲模板,讓我們拿來(lái)就能套用,就像PPT模板一樣。我們不需要管爬蟲的全部流程,只要負(fù)責(zé)填充好爬蟲的核心邏輯代碼就好。要是有的話,我們編寫代碼一定會(huì)很方便省事。
其實(shí),在Python中還真的存在這樣的爬蟲模板,只不過(guò)它的名字是叫框架。
一個(gè)爬蟲框架里包含了能實(shí)現(xiàn)爬蟲整個(gè)流程的各種模塊,就像PPT模板一開始就幫你設(shè)置好了主題顏色和排版方式一樣。
這一關(guān),我們要學(xué)習(xí)的就是一個(gè)功能強(qiáng)大的爬蟲框架——Scrapy。
Scrapy是什么
以前我們寫爬蟲,要導(dǎo)入和操作不同的模塊,比如requests模塊、gevent庫(kù)、csv模塊等。而在Scrapy里,你不需要這么做,因?yàn)楹芏嗯老x需要涉及的功能,比如麻煩的異步,在Scrapy框架都自動(dòng)實(shí)現(xiàn)了。
我們之前編寫爬蟲的方式,相當(dāng)于在一個(gè)個(gè)地在拼零件,拼成一輛能跑的車。而Scrapy框架則是已經(jīng)造好的、現(xiàn)成的車,我們只要踩下它的油門,它就能跑起來(lái)。這樣便節(jié)省了我們開發(fā)項(xiàng)目的時(shí)間。
下面,我們來(lái)了解Scrapy的基礎(chǔ)知識(shí),包括Scrapy的結(jié)構(gòu)及其工作原理。
Scrapy的結(jié)構(gòu)
上面的這張圖是Scrapy的整個(gè)結(jié)構(gòu)。你可以把整個(gè)Scrapy框架看成是一家爬蟲公司。最中心位置的Scrapy Engine(引擎)就是這家爬蟲公司的大boss,負(fù)責(zé)統(tǒng)籌公司的4大部門,每個(gè)部門都只聽從它的命令,并只向它匯報(bào)工作。
我會(huì)以爬蟲流程的順序來(lái)依次跟你介紹Scrapy爬蟲公司的4大部門。
Scheduler(調(diào)度器)部門主要負(fù)責(zé)處理引擎發(fā)送過(guò)來(lái)的requests對(duì)象(即網(wǎng)頁(yè)請(qǐng)求的相關(guān)信息集合,包括params,data,cookies,request headers…等),會(huì)把請(qǐng)求的url以有序的方式排列成隊(duì),并等待引擎來(lái)提?。üδ苌项愃朴趃event庫(kù)的queue模塊)。
Downloader(下載器)部門則是負(fù)責(zé)處理引擎發(fā)送過(guò)來(lái)的requests,進(jìn)行網(wǎng)頁(yè)爬取,并將返回的response(爬取到的內(nèi)容)交給引擎。它對(duì)應(yīng)的是爬蟲流程【獲取數(shù)據(jù)】這一步。
Spiders(爬蟲)部門是公司的核心業(yè)務(wù)部門,主要任務(wù)是創(chuàng)建requests對(duì)象和接受引擎發(fā)送過(guò)來(lái)的response(Downloader部門爬取到的內(nèi)容),從中解析并提取出有用的數(shù)據(jù)。它對(duì)應(yīng)的是爬蟲流程【解析數(shù)據(jù)】和【提取數(shù)據(jù)】這兩步。
Item Pipeline(數(shù)據(jù)管道)部門則是公司的數(shù)據(jù)部門,只負(fù)責(zé)存儲(chǔ)和處理Spiders部門提取到的有用數(shù)據(jù)。這個(gè)對(duì)應(yīng)的是爬蟲流程【存儲(chǔ)數(shù)據(jù)】這一步。
Downloader Middlewares(下載中間件)的工作相當(dāng)于下載器部門的秘書,比如會(huì)提前對(duì)引擎大boss發(fā)送的諸多requests做出處理。
Spider Middlewares(爬蟲中間件)的工作則相當(dāng)于爬蟲部門的秘書,比如會(huì)提前接收并處理引擎大boss發(fā)送來(lái)的response,過(guò)濾掉一些重復(fù)無(wú)用的東西。
Scrapy的工作原理
你會(huì)發(fā)現(xiàn),在Scrapy爬蟲公司里,每個(gè)部門都各司其職,形成了很高效的運(yùn)行流程。
這套運(yùn)行流程的邏輯很簡(jiǎn)單,就是:引擎大boss說(shuō)的話就是最高需求。
上圖展現(xiàn)出的也是Scrapy框架的工作原理——引擎是中心,其他組成部分由引擎調(diào)度。
在Scrapy里,整個(gè)爬蟲程序的流程都不需要我們?nèi)ゲ傩?,且Scrapy中的程序全部都是異步模式,所有的請(qǐng)求或返回的響應(yīng)都由引擎自動(dòng)分配去處理。
哪怕有某個(gè)請(qǐng)求出現(xiàn)異常,程序也會(huì)做異常處理,跳過(guò)報(bào)錯(cuò)的請(qǐng)求,繼續(xù)往下運(yùn)行程序。
在一定程度上,Scrapy可以說(shuō)是非常讓人省心的一套爬蟲框架。
Scrapy的用法
現(xiàn)在,你已經(jīng)初步了解Scrapy的結(jié)構(gòu)以及工作原理。接下來(lái),為了讓你熟悉Scrapy的用法,我們使用它來(lái)完成一個(gè)小項(xiàng)目——爬取豆瓣Top250圖書。
明確目標(biāo)與分析過(guò)程
依舊是遵循寫代碼的三個(gè)步驟:明確目標(biāo)、分析過(guò)程、代碼實(shí)現(xiàn)來(lái)完成項(xiàng)目。我會(huì)在代碼實(shí)現(xiàn)的步驟重點(diǎn)講解Scrapy的用法。
首先,要明確目標(biāo)。請(qǐng)你務(wù)必打開以下豆瓣Top250圖書的鏈接。
https://book.douban.com/top250
豆瓣Top250圖書一共有10頁(yè),每頁(yè)有25本書籍。我們的目標(biāo)是:先只爬取前三頁(yè)書籍的信息,也就是爬取前75本書籍的信息(包含書名、出版信息和書籍評(píng)分)。
接著,我們來(lái)分析網(wǎng)頁(yè)。既然我們要爬取書籍信息,我們就得先判斷這些信息被存在了哪里。
判斷的方法你應(yīng)該了然于胸。趕緊右擊打開“檢查”工具,點(diǎn)開Network,刷新頁(yè)面,然后點(diǎn)擊第0個(gè)請(qǐng)求top250,看Response.
我們能在里面翻找到書名、出版信息,說(shuō)明我們想要的書籍信息就藏在這個(gè)網(wǎng)址的HTML里。
確定書籍信息有存在這個(gè)網(wǎng)址的HTML后,我們就來(lái)具體觀察一下這個(gè)網(wǎng)站。
你點(diǎn)擊翻到豆瓣Top250圖書的第2頁(yè)。
你會(huì)觀察到,網(wǎng)址發(fā)生了變化,后面多了?start=25。我們猜想,后面的數(shù)字是代表一頁(yè)的25本書籍。
你可以翻到第3頁(yè),驗(yàn)證一下我們的猜想是不是正確的。
事實(shí)證明,我們猜對(duì)了。每翻一頁(yè),網(wǎng)址后面的數(shù)字都會(huì)增加25,說(shuō)明這個(gè)start的參數(shù)就是代表每頁(yè)的25本書籍。
這么一觀察,我們要爬取的網(wǎng)址的構(gòu)造規(guī)律就出來(lái)了。只要改變?start=后面的數(shù)字(翻一頁(yè)加25),我們就能得到每一頁(yè)的網(wǎng)址。
找到了網(wǎng)址的構(gòu)造規(guī)律,我們可以重點(diǎn)來(lái)分析HTML的結(jié)構(gòu),看看等下怎么才能提取出我們想要的書籍信息。
仍舊是右擊打開“檢查”工具,點(diǎn)擊Elements,再點(diǎn)擊光標(biāo),把鼠標(biāo)依次移到書名、出版信息、評(píng)分處,就能在HTML里找到這些書籍信息。如下圖,《追風(fēng)箏的人》的書籍信息就全部放在<table width="100%">
標(biāo)簽里。
很快,你就會(huì)發(fā)現(xiàn),其實(shí)每一頁(yè)的25本書籍信息都分別藏在了一個(gè)<table width="100%">
標(biāo)簽里。不過(guò)這個(gè)標(biāo)簽沒有class屬性,也沒有id屬性,不方便我們提取信息。
我們得再找一個(gè)既方便我們提取,又能包含所有書籍信息的標(biāo)簽。
在<table width="100%">
標(biāo)簽下的<tr class="item">
元素剛好都能滿足我們的要求,既有class屬性,又包含了書籍的信息。
我們只要取出<tr class="item">
元素下<a>
元素的title屬性的值、<p class="pl">
元素、<span class="rating_nums">
元素,就能得到書名、出版信息和評(píng)分的數(shù)據(jù)。
頁(yè)面分析完畢,接著進(jìn)入代碼實(shí)現(xiàn)的步驟。
代碼實(shí)現(xiàn)——?jiǎng)?chuàng)建項(xiàng)目
從這里開始,我會(huì)帶你使用Scrapy編寫我們的項(xiàng)目爬蟲。其中會(huì)涉及到很多Scrapy的用法,請(qǐng)你一定要認(rèn)真地看!
如果你想在自己本地的電腦使用Scrapy,需要提前安裝好它。(安裝方法:Windows:在終端輸入命令:pip install scrapy;mac:在終端輸入命令:pip3 install scrapy,按下enter鍵)
首先,要在本地電腦打開終端(windows:Win+R,輸入cmd;mac:command+空格,搜索“終端”),然后跳轉(zhuǎn)到你想要保存項(xiàng)目的目錄下。
假設(shè)你想跳轉(zhuǎn)到E盤里名為Python文件夾中的Pythoncode子文件夾。你需要再命令行輸入e:,就會(huì)跳轉(zhuǎn)到e盤,再輸入cd Python,就能跳轉(zhuǎn)到Python文件夾。接著輸入cd Pythoncode,就能跳轉(zhuǎn)到Python文件夾里的Pythoncode子文件夾。
然后,再輸入一行能幫我們創(chuàng)建Scrapy項(xiàng)目的命令:scrapy startproject douban,douban就是Scrapy項(xiàng)目的名字。按下enter鍵,一個(gè)Scrapy項(xiàng)目就創(chuàng)建成功了。
整個(gè)scrapy項(xiàng)目的結(jié)構(gòu),如下圖所示:
Scrapy項(xiàng)目里每個(gè)文件都有特定的功能,比如settings.py 是scrapy里的各種設(shè)置。items.py是用來(lái)定義數(shù)據(jù)的,pipelines.py是用來(lái)處理數(shù)據(jù)的,它們對(duì)應(yīng)的就是Scrapy的結(jié)構(gòu)中的Item Pipeline(數(shù)據(jù)管道)。
現(xiàn)在或許你還看不懂它們,沒關(guān)系,事情將會(huì)一點(diǎn)點(diǎn)變清晰。我們來(lái)講解它們。
代碼實(shí)現(xiàn)——編輯爬蟲
如前所述,spiders是放置爬蟲的目錄。我們可以在spiders這個(gè)文件夾里創(chuàng)建爬蟲文件。我們來(lái)把這個(gè)文件,命名為top250。后面的大部分代碼都需要在這個(gè)top250.py文件里編寫。
先在top250.py文件里導(dǎo)入我們需要的模塊。
import scrapy
import bs4
導(dǎo)入BeautifulSoup用于解析和提取數(shù)據(jù),這個(gè)應(yīng)該不需要我多做解釋。在第2關(guān)、第3關(guān)的時(shí)候你就已經(jīng)對(duì)它非常熟稔。
導(dǎo)入scrapy是待會(huì)我們要用創(chuàng)建類的方式寫這個(gè)爬蟲,我們所創(chuàng)建的類將直接繼承scrapy中的scrapy.Spider類。這樣,有許多好用屬性和方法,就能夠直接使用。
接著我們開始編寫爬蟲的核心代碼。
在Scrapy中,每個(gè)爬蟲的代碼結(jié)構(gòu)基本都如下所示:
class DoubanSpider(scrapy.Spider):
name = 'douban'
allowed_domains = ['book.douban.com']
start_urls = ['https://book.douban.com/top250?start=0']
def parse(self, response):
print(response.text)
第1行代碼:定義一個(gè)爬蟲類DoubanSpider。就像我剛剛講過(guò)的那樣,DoubanSpider類繼承自scrapy.Spider類。
第2行代碼:name是定義爬蟲的名字,這個(gè)名字是爬蟲的唯一標(biāo)識(shí)。name = 'douban’意思是定義爬蟲的名字為douban。等會(huì)我們啟動(dòng)爬蟲的時(shí)候,要用到這個(gè)名字。
第3行代碼:allowed_domains是定義允許爬蟲爬取的網(wǎng)址域名(不需要加https://)。如果網(wǎng)址的域名不在這個(gè)列表里,就會(huì)被過(guò)濾掉。
為什么會(huì)有這個(gè)設(shè)置呢?當(dāng)你在爬取大量數(shù)據(jù)時(shí),經(jīng)常是從一個(gè)URL開始爬取,然后關(guān)聯(lián)爬取更多的網(wǎng)頁(yè)。比如,假設(shè)我們今天的爬蟲目標(biāo)不是爬書籍信息,而是要爬豆瓣圖書top250的書評(píng)。我們會(huì)先爬取書單,再找到每本書的URL,再進(jìn)入每本書的詳情頁(yè)面去抓取評(píng)論。
allowed_domains就限制了,我們這種關(guān)聯(lián)爬取的URL,一定在book.douban.com這個(gè)域名之下,不會(huì)跳轉(zhuǎn)到某個(gè)奇怪的廣告頁(yè)面。
第4行代碼:start_urls是定義起始網(wǎng)址,就是爬蟲從哪個(gè)網(wǎng)址開始抓取。在此,allowed_domains的設(shè)定對(duì)start_urls里的網(wǎng)址不會(huì)有影響。
第6行代碼:parse是Scrapy里默認(rèn)處理response的一個(gè)方法,中文是解析。
你或許會(huì)好奇,這里是不是少了一句類似requests.get()這樣的代碼?的確是,在這里,我們并不需要寫這一句。scrapy框架會(huì)為我們代勞做這件事,寫好你的請(qǐng)求,接下來(lái)你就可以直接寫對(duì)響應(yīng)如何做處理,我會(huì)在后面為你做示例。
了解完爬蟲代碼的基礎(chǔ)結(jié)構(gòu),我們繼續(xù)來(lái)完善爬取豆瓣Top圖書的代碼。
豆瓣Top250圖書一共有10頁(yè),每一頁(yè)的網(wǎng)址我們都知道。我們可以選擇把10頁(yè)網(wǎng)址都塞進(jìn)start_urls的列表里。
但是這樣的方式并不美觀,而且如果要爬取的是上百個(gè)網(wǎng)址,全部塞進(jìn)start_urls的列表里的話,代碼就會(huì)非常長(zhǎng)。
其實(shí),我們可以利用豆瓣Top250圖書的網(wǎng)址規(guī)律,用for循環(huán)構(gòu)造出每個(gè)網(wǎng)址,再把網(wǎng)址添加進(jìn)start_urls的列表里。這樣代碼會(huì)美觀得多。
完善后的代碼如下:
class DoubanSpider(scrapy.Spider):
name = 'douban'
allowed_domains = ['book.douban.com']
start_urls = []
for x in range(3):
url = 'https://book.douban.com/top250?start=' + str(x * 25)
start_urls.append(url)
我們只先爬取豆瓣Top250前3頁(yè)的書籍信息。
接下來(lái),只要再借助parse方法處理response,借助BeautifulSoup來(lái)取出我們想要的書籍信息的數(shù)據(jù),代碼即可完成。
我們前面在分析項(xiàng)目過(guò)程的時(shí)候,已經(jīng)知道書籍信息都藏在了哪些元素里,現(xiàn)在可以利用find_all和find方法提取出來(lái)。比如,書名是元素下元素的title屬性的值;出版信息在
元素里;評(píng)分在
按照過(guò)去的知識(shí),我們可能會(huì)把代碼寫成這個(gè)模樣:
import scrapy
import bs4
from ..items import DoubanItem
class DoubanSpider(scrapy.Spider):
#定義一個(gè)爬蟲類DoubanSpider。
name = 'douban'
#定義爬蟲的名字為douban。
allowed_domains = ['book.douban.com']
#定義爬蟲爬取網(wǎng)址的域名。
start_urls = []
#定義起始網(wǎng)址。
for x in range(3):
url = 'https://book.douban.com/top250?start=' + str(x * 25)
start_urls.append(url)
#把豆瓣Top250圖書的前3頁(yè)網(wǎng)址添加進(jìn)start_urls。
def parse(self, response):
#parse是默認(rèn)處理response的方法。
bs = bs4.BeautifulSoup(response.text,'html.parser')
#用BeautifulSoup解析response。
datas = bs.find_all('tr',class_="item")
#用find_all提取<tr class="item">元素,這個(gè)元素里含有書籍信息。
for data in datas:
#遍歷datas。
title = data.find_all('a')[1]['title']
#提取出書名。
publish = data.find('p',class_='pl').text
#提取出出版信息。
score = data.find('span',class_='rating_nums').text
#提取出評(píng)分。
print([title,publish,score])
#打印上述信息。
按照過(guò)去,我們會(huì)把書名、出版信息、評(píng)分,分別賦值,然后統(tǒng)一做處理——或是打印,或是存儲(chǔ)。但在scrapy這里,事情卻有所不同。
spiders(如top250.py)只干spiders應(yīng)該做的事。對(duì)數(shù)據(jù)的后續(xù)處理,另有人負(fù)責(zé)。
代碼實(shí)現(xiàn)——定義數(shù)據(jù)
在scrapy中,我們會(huì)專門定義一個(gè)用于記錄數(shù)據(jù)的類。
當(dāng)我們每一次,要記錄數(shù)據(jù)的時(shí)候,比如前面在每一個(gè)最小循環(huán)里,都要記錄“書名”,“出版信息”,“評(píng)分”。我們會(huì)實(shí)例化一個(gè)對(duì)象,利用這個(gè)對(duì)象來(lái)記錄數(shù)據(jù)。
每一次,當(dāng)數(shù)據(jù)完成記錄,它會(huì)離開spiders,來(lái)到Scrapy Engine(引擎),引擎將它送入Item Pipeline(數(shù)據(jù)管道)處理。
定義這個(gè)類的py文件,正是items.py。
我們已經(jīng)知道,我們要爬取的數(shù)據(jù)是書名、出版信息和評(píng)分,我們來(lái)看看如何在items.py里定義這些數(shù)據(jù)。代碼如下:
import scrapy
#導(dǎo)入scrapy
class DoubanItem(scrapy.Item):
#定義一個(gè)類DoubanItem,它繼承自scrapy.Item
title = scrapy.Field()
#定義書名的數(shù)據(jù)屬性
publish = scrapy.Field()
#定義出版信息的數(shù)據(jù)屬性
score = scrapy.Field()
#定義評(píng)分的數(shù)據(jù)屬性
第1行代碼,我們導(dǎo)入了scrapy。目的是,我們等會(huì)所創(chuàng)建的類將直接繼承scrapy中的scrapy.Item類。這樣,有許多好用屬性和方法,就能夠直接使用。比如到后面,引擎能將item類的對(duì)象發(fā)給Item Pipeline(數(shù)據(jù)管道)處理。
第3行代碼:我們定義了一個(gè)DoubanItem類。它繼承自scrapy.Item類。
第5、7、9行代碼:我們定義了書名、出版信息和評(píng)分三種數(shù)據(jù)。scrapy.Field()這行代碼實(shí)現(xiàn)的是,讓數(shù)據(jù)能以類似字典的形式記錄。你可能不太明白這句話的含義,沒關(guān)系。我?guī)銇?lái)體驗(yàn)一下,你就能感受到是怎樣一回事:
import scrapy
#導(dǎo)入scrapy
class DoubanItem(scrapy.Item):
#定義一個(gè)類DoubanItem,它繼承自scrapy.Item
title = scrapy.Field()
#定義書名的數(shù)據(jù)屬性
publish = scrapy.Field()
#定義出版信息的數(shù)據(jù)屬性
score = scrapy.Field()
#定義評(píng)分的數(shù)據(jù)屬性
book = DoubanItem()
# 實(shí)例化一個(gè)DoubanItem對(duì)象
book['title'] = '海邊的卡夫卡'
book['publish'] = '[日] 村上春樹 / 林少華 / 上海譯文出版社 / 2003'
book['score'] = '8.1'
print(book)
print(type(book))
運(yùn)行結(jié)果:
{'publish': '[日] 村上春樹 / 林少華 / 上海譯文出版社 / 2003',
'score': '8.1',
'title': '海邊的卡夫卡'}
<class '__main__.DoubanItem'>
你會(huì)看到打印出來(lái)的結(jié)果的確和字典非常相像,但它卻并不是dict,它的數(shù)據(jù)類型是我們定義的DoubanItem,屬于“自定義的Python字典”。我們可以利用類似上述代碼的樣式,去重新寫top250.py。如下所示:
import scrapy
import bs4
from ..items import DoubanItem
# 需要引用DoubanItem,它在items里面。因?yàn)槭莍tems在top250.py的上一級(jí)目錄,所以要用..items,這是一個(gè)固定用法。
class DoubanSpider(scrapy.Spider):
#定義一個(gè)爬蟲類DoubanSpider。
name = 'douban'
#定義爬蟲的名字為douban。
allowed_domains = ['book.douban.com']
#定義爬蟲爬取網(wǎng)址的域名。
start_urls = []
#定義起始網(wǎng)址。
for x in range(3):
url = 'https://book.douban.com/top250?start=' + str(x * 25)
start_urls.append(url)
#把豆瓣Top250圖書的前3頁(yè)網(wǎng)址添加進(jìn)start_urls。
def parse(self, response):
#parse是默認(rèn)處理response的方法。
bs = bs4.BeautifulSoup(response.text,'html.parser')
#用BeautifulSoup解析response。
datas = bs.find_all('tr',class_="item")
#用find_all提取<tr class="item">元素,這個(gè)元素里含有書籍信息。
for data in datas:
#遍歷data。
item = DoubanItem()
#實(shí)例化DoubanItem這個(gè)類。
item['title'] = data.find_all('a')[1]['title']
#提取出書名,并把這個(gè)數(shù)據(jù)放回DoubanItem類的title屬性里。
item['publish'] = data.find('p',class_='pl').text
#提取出出版信息,并把這個(gè)數(shù)據(jù)放回DoubanItem類的publish里。
item['score'] = data.find('span',class_='rating_nums').text
#提取出評(píng)分,并把這個(gè)數(shù)據(jù)放回DoubanItem類的score屬性里。
print(item['title'])
#打印書名。
yield item
#yield item是把獲得的item傳遞給引擎。
在3行,我們需要引用DoubanItem,它在items里面。因?yàn)槭莍tems在top250.py的上一級(jí)目錄,所以要用…items,這是一個(gè)固定用法。
當(dāng)我們每一次,要記錄數(shù)據(jù)的時(shí)候,比如前面在每一個(gè)最小循環(huán)里,都要記錄“書名”,“出版信息”,“評(píng)分”。我們會(huì)實(shí)例化一個(gè)item對(duì)象,利用這個(gè)對(duì)象來(lái)記錄數(shù)據(jù)。
每一次,當(dāng)數(shù)據(jù)完成記錄,它會(huì)離開spiders,來(lái)到Scrapy Engine(引擎),引擎將它送入Item Pipeline(數(shù)據(jù)管道)處理。這里,要用到y(tǒng)ield語(yǔ)句。
yield語(yǔ)句你可能還不太了解,這里你可以簡(jiǎn)單理解為:它有點(diǎn)類似return,不過(guò)它和return不同的點(diǎn)在于,它不會(huì)結(jié)束函數(shù),且能多次返回信息。
如果用可視化的方式來(lái)呈現(xiàn)程序運(yùn)行的過(guò)程,就如同上圖所示:爬蟲(Spiders)會(huì)把豆瓣的10個(gè)網(wǎng)址封裝成requests對(duì)象,引擎會(huì)從爬蟲(Spiders)里提取出requests對(duì)象,再交給調(diào)度器(Scheduler),讓調(diào)度器把這些requests對(duì)象排序處理。
然后引擎再把經(jīng)過(guò)調(diào)度器處理的requests對(duì)象發(fā)給下載器(Downloader),下載器會(huì)立馬按照引擎的命令爬取,并把response返回給引擎。
緊接著引擎就會(huì)把response發(fā)回給爬蟲(Spiders),這時(shí)爬蟲會(huì)啟動(dòng)默認(rèn)的處理response的parse方法,解析和提取出書籍信息的數(shù)據(jù),使用item做記錄,返回給引擎。引擎將它送入Item Pipeline(數(shù)據(jù)管道)處理。
代碼實(shí)操——設(shè)置
到這里,我們就用代碼編寫好了一個(gè)爬蟲。不過(guò),實(shí)際運(yùn)行的話,可能還是會(huì)報(bào)錯(cuò)。
原因在于Scrapy里的默認(rèn)設(shè)置沒被修改。比如我們需要修改請(qǐng)求頭。點(diǎn)擊settings.py文件,你能在里面找到如下的默認(rèn)設(shè)置代碼:
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'douban (+http://www.yourdomain.com)'
# Obey robots.txt rules
ROBOTSTXT_OBEY = True
請(qǐng)你把USER _AGENT的注釋取消(刪除#),然后替換掉user-agent的內(nèi)容,就是修改了請(qǐng)求頭。
又因?yàn)镾crapy是遵守robots協(xié)議的,如果是robots協(xié)議禁止爬取的內(nèi)容,Scrapy也會(huì)默認(rèn)不去爬取,所以我們還得修改Scrapy中的默認(rèn)設(shè)置。
把ROBOTSTXT_OBEY=True改成ROBOTSTXT_OBEY=False,就是把遵守robots協(xié)議換成無(wú)需遵從robots協(xié)議,這樣Scrapy就能不受限制地運(yùn)行。
修改后的代碼應(yīng)該如下所示:
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
現(xiàn)在,我們已經(jīng)編寫好了spider,也修改好了setting。萬(wàn)事俱備,只欠東風(fēng)——運(yùn)行Scrapy。
代碼實(shí)操——運(yùn)行
想要運(yùn)行Scrapy有兩種方法,一種是在本地電腦的終端跳轉(zhuǎn)到scrapy項(xiàng)目的文件夾(跳轉(zhuǎn)方法:cd+文件夾的路徑名),然后輸入命令行:scrapy crawl douban(douban 就是我們爬蟲的名字)。
另一種運(yùn)行方式需要我們?cè)谧钔鈱拥拇笪募A里新建一個(gè)main.py文件(與scrapy.cfg同級(jí))。
我們只需要在這個(gè)main.py文件里,輸入以下代碼,點(diǎn)擊運(yùn)行,Scrapy的程序就會(huì)啟動(dòng)。
from scrapy import cmdline
#導(dǎo)入cmdline模塊,可以實(shí)現(xiàn)控制終端命令行。
cmdline.execute(['scrapy','crawl','douban'])
#用execute()方法,輸入運(yùn)行scrapy的命令。
第1行代碼:在Scrapy中有一個(gè)可以控制終端命令的模塊cmdline。導(dǎo)入了這個(gè)模塊,我們就能操控終端。
第3行代碼:在cmdline模塊中,有一個(gè)execute方法能執(zhí)行終端的命令行,不過(guò)這個(gè)方法需要傳入列表的參數(shù)。我們想輸入運(yùn)行Scrapy的代碼scrapy crawl douban,就需要寫成[‘scrapy’,‘crawl’,‘douban’]這樣。
至此,Scrapy的用法我們學(xué)完啦。
值得一提的是,在本關(guān)卡中為了教學(xué)方便理解,先寫了爬蟲,再定義數(shù)據(jù)。但是,在實(shí)際項(xiàng)目實(shí)戰(zhàn)中,常常順序卻是相反的——先定義數(shù)據(jù),再寫爬蟲。所以,流程圖應(yīng)如下:
細(xì)心的你可能會(huì)發(fā)現(xiàn),這一關(guān)的內(nèi)容沒有涉及到存儲(chǔ)數(shù)據(jù)的步驟。
是的,存儲(chǔ)數(shù)據(jù)需要修改pipelines.py文件。這一關(guān)的內(nèi)容已經(jīng)很充實(shí),所以這個(gè)知識(shí)點(diǎn)我們留到下一關(guān)再講。
復(fù)習(xí)
最后,是這一關(guān)的重點(diǎn)知識(shí)的復(fù)習(xí)。
Scrapy的結(jié)構(gòu)——
Scrapy的工作原理——
Scrapy的用法——
下一關(guān),我們準(zhǔn)備用Scrapy來(lái)實(shí)操一個(gè)大項(xiàng)目——爬取人氣企業(yè)的招聘信息。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-704904.html
下關(guān)見啦~文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-704904.html
到了這里,關(guān)于【python爬蟲】14.Scrapy框架講解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!