Scrapy快速入門,爬取糗事百科段子
Scrapy快速入門
安裝和文檔:
安裝:通過pip install scrapy即可安裝。 Scrapy官方文檔:http://doc.scrapy.org/en/latest Scrapy中文文檔:http://scrapy-chs.readthedocs.io/zh_CN/latest/index.html
注意:
在ubuntu上安裝scrapy之前,需要先安裝以下依賴:sudo apt-get install python3-dev build-essential python3-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev,然后再通過pip install scrapy安裝。 如果在windows系統(tǒng)下,提示這個(gè)錯(cuò)誤ModuleNotFoundError: No module named 'win32api',那么使用以下命令可以解決:pip install pypiwin32。
快速入門:
創(chuàng)建項(xiàng)目:
要使用Scrapy框架創(chuàng)建項(xiàng)目,需要通過命令來創(chuàng)建。首先進(jìn)入到你想把這個(gè)項(xiàng)目存放的目錄。然后使用以下命令創(chuàng)建:
scrapy?startproject?[項(xiàng)目名稱]
目錄結(jié)構(gòu)介紹:
以下介紹下主要文件的作用:
items.py:用來存放爬蟲爬取下來數(shù)據(jù)的模型。
middlewares.py:用來存放各種中間件的文件。
pipelines.py:用來將items的模型存儲(chǔ)到本地磁盤中。
settings.py:本爬蟲的一些配置信息(比如請(qǐng)求頭、多久發(fā)送一次請(qǐng)求、ip代理池等)。
scrapy.cfg:項(xiàng)目的配置文件。
spiders包:以后所有的爬蟲,都是存放到這個(gè)里面。
Scrapy框架架構(gòu)
Scrapy框架介紹:
寫一個(gè)爬蟲,需要做很多的事情。比如:發(fā)送網(wǎng)絡(luò)請(qǐng)求(urllib庫(kù)、requests庫(kù))、數(shù)據(jù)解析(BeautifulSoup庫(kù)、xpath解析、正則表達(dá)式、css選擇器)、數(shù)據(jù)存儲(chǔ)(excel表格、csv文件、json文件、MySQL數(shù)據(jù)庫(kù)、MongoDB數(shù)據(jù)庫(kù))、反反爬蟲機(jī)制(更換ip代理、設(shè)置請(qǐng)求頭等)、異步請(qǐng)求等。
這些工作如果每次都要自己從零開始寫的話,比較浪費(fèi)時(shí)間。因此Scrapy把一些基礎(chǔ)的東西封裝好了,在他上面寫爬蟲可以變的更加的高效(爬取效率和開發(fā)效率)。
因此真正在公司里,一些上了量的爬蟲,都是使用Scrapy框架來解決。


Scrapy框架模塊功能:
Scrapy Engine(引擎):Scrapy框架的核心部分。負(fù)責(zé)在Spider和ItemPipeline、Downloader、Scheduler中間通信、傳遞數(shù)據(jù)等。 Spider(爬蟲):發(fā)送需要爬取的鏈接給引擎,最后引擎把其他模塊請(qǐng)求回來的數(shù)據(jù)再發(fā)送給爬蟲,爬蟲就去解析想要的數(shù)據(jù)。這個(gè)部分是我們開發(fā)者自己寫 ?的,因?yàn)橐廊∧男╂溄?,頁面中的哪些?shù)據(jù)是我們需要的,都是由程序員自己決定。 Scheduler(調(diào)度器):負(fù)責(zé)接收引擎發(fā)送過來的請(qǐng)求,并按照一定的方式進(jìn)行排列和整理,負(fù)責(zé)調(diào)度請(qǐng)求的順序等。 Downloader(下載器):負(fù)責(zé)接收引擎?zhèn)鬟^來的下載請(qǐng)求,然后去網(wǎng)絡(luò)上下載對(duì)應(yīng)的數(shù)據(jù)再交還給引擎。 Item Pipeline(管道):負(fù)責(zé)將Spider(爬蟲)傳遞過來的數(shù)據(jù)進(jìn)行保存。具體保存在哪里,應(yīng)該看開發(fā)者自己的需求。 Downloader Middlewares(下載中間件):可以擴(kuò)展下載器和引擎之間通信功能的中間件。 Spider Middlewares(Spider中間件):可以擴(kuò)展引擎和爬蟲之間通信功能的中間件。
Scrapy Shell
我們想要在爬蟲中使用xpath、beautifulsoup、正則表達(dá)式、css選擇器等來提取想要的數(shù)據(jù)。但是因?yàn)閟crapy是一個(gè)比較重的框架。每次運(yùn)行起來都要等待一段時(shí)間。因此要去驗(yàn)證我們寫的提取規(guī)則是否正確,是一個(gè)比較麻煩的事情。因此Scrapy提供了一個(gè)shell,用來方便的測(cè)試規(guī)則。當(dāng)然也不僅僅局限于這一個(gè)功能。
打開Scrapy Shell:
打開cmd終端,進(jìn)入到Scrapy項(xiàng)目所在的目錄,然后進(jìn)入到scrapy框架所在的虛擬環(huán)境中,輸入命令scrapy shell [鏈接]。就會(huì)進(jìn)入到scrapy的shell環(huán)境中。在這個(gè)環(huán)境中,你可以跟在爬蟲的parse方法中一樣使用了。
使用Scrapy框架爬取糗事百科段子:
使用命令創(chuàng)建一個(gè)爬蟲:
scrapy?startproject?qsbk
scrapy?gensipder?qsbk?"qiushibaike.com"???
創(chuàng)建了一個(gè)名字叫做qsbk的爬蟲,并且能爬取的網(wǎng)頁只會(huì)限制在qiushibaike.com這個(gè)域名下。
爬蟲代碼如下:
import?scrapy
class?QsbkSpider(scrapy.Spider):
????name?=?'qsbk'
????allowed_domains?=?['qiushibaike.com']
????start_urls?=?['http://qiushibaike.com/']
????def?parse(self,?response):
????????pass
爬蟲代碼解析:
其實(shí)這些代碼我們完全可以自己手動(dòng)去寫,而不用命令。只不過是不用命令,自己寫這些代碼比較麻煩。
要?jiǎng)?chuàng)建一個(gè)Spider,那么必須自定義一個(gè)類,繼承自scrapy.Spider,然后在這個(gè)類中定義三個(gè)屬性和一個(gè)方法。
name:這個(gè)爬蟲的名字,名字必須是唯一的。 allow_domains:允許的域名。爬蟲只會(huì)爬取這個(gè)域名下的網(wǎng)頁,其他不是這個(gè)域名下的網(wǎng)頁會(huì)被自動(dòng)忽略。 start_urls:爬蟲從這個(gè)變量中的url開始。 parse:引擎會(huì)把下載器下載回來的數(shù)據(jù)扔給爬蟲解析,爬蟲再把數(shù)據(jù)傳給這個(gè)parse方法。這個(gè)是個(gè)固定的寫法。這個(gè)方法的作用有兩個(gè),第一個(gè)是提取想要的數(shù)據(jù)。第二個(gè)是生成下一個(gè)請(qǐng)求的url。
修改settings.py代碼:
在做一個(gè)爬蟲之前,一定要記得修改setttings.py中的設(shè)置。兩個(gè)地方是強(qiáng)烈建議設(shè)置的。
ROBOTSTXT_OBEY設(shè)置為False。默認(rèn)是True。即遵守機(jī)器協(xié)議,那么在爬蟲的時(shí)候,scrapy首先去找robots.txt文件,如果沒有找到。則直接停止爬取。 DEFAULT_REQUEST_HEADERS添加User-Agent。這個(gè)也是告訴服務(wù)器,我這個(gè)請(qǐng)求是一個(gè)正常的請(qǐng)求,不是一個(gè)爬蟲。
完成的爬蟲代碼:
項(xiàng)目結(jié)構(gòu)
1.爬蟲部分代碼:
# 1.爬蟲部分代碼:
import?scrapy
from?qsbk.items?import?QsbkItem
from?scrapy.http.response.html?import?HtmlResponse
from?scrapy.selector.unified?import?SelectorList
class?QsbkSpiderSpider(scrapy.Spider):
????#name:這個(gè)爬蟲的名字,名字必須唯一
????name?=?'qsbk_spider'
????#allowed_domains:允許的域名范圍
????allowed_domains?=?['qiushibaike.com']
????#start_urls:爬蟲從這個(gè)變量中的url開始
????start_urls?=?['https://www.qiushibaike.com/text/page/1/']
????base_domain?=?"https://www.qiushibaike.com"
????def?parse(self,?response):
?????????duanzidivs?=?response.xpath("http://div[@class='col1?old-style-col1']/div")
????????for?duanzidiv?in?duanzidivs:
????????????#?Selector
????????????author?=?duanzidiv.xpath(".//h2/text()").get().strip()????#strip()是去除前后空白
????????????content?=?duanzidiv.xpath(".//div[@class='content']//text()").getall()
????????????content?=?"".join(content).strip()????#content就變成字符串str了
????????????#?print(content)
????????????item?=?QsbkItem(author=author,?content=content)
????????????#?duanzi?=?{"author":author,?"content":content}????#定義一個(gè)字典存放
????????????yield?item
????????next_url?=?response.xpath("http://ul[@class='pagination']/li[last()]/a/@href").get()
????????if?not?next_url:
????????????return
????????else:
????????????yield?scrapy.Request(self.base_domain+next_url,callback=self.parse)
下面是scrapy shell 測(cè)試的代碼

2.items.py部分代碼:
# 2.items.py部分代碼:
import?scrapy
class?QsbkItem(scrapy.Item):
????author?=?scrapy.Field()
????content?=?scrapy.Field()
3.pipeline部分代碼:
import?json
##########?方法一?##########
#?class?QsbkPipeline(object):
#?????def?__init__(self):
#?????????self.fp?=?open("duanzi.json",?"w",?encoding='utf-8')
#
#?????def?open_spider(self,?spider):
#?????????print('爬蟲開始了……')
#
#?????def?process_item(self,?item,?spider):
#?????????item_json?=?json.dumps(dict(item),?ensure_ascii=False)
#?????????self.fp.write(item_json+'\n')
#?????????return?item
#
#?????def?close_spider(self,?spider):
#?????????self.fp.close()
#?????????print('爬蟲結(jié)束了…')
##########?方法二?##########
####?數(shù)據(jù)量比較少的時(shí)候?可以用JsonItemExporter
from?scrapy.exporters?import?JsonItemExporter
#?class?QsbkPipeline(object):
#?????def?__init__(self):
#?????????self.fp?=?open("duanzi.json",?"wb")???#以二進(jìn)制的方式寫入
#?????????self.exportr?=?JsonItemExporter(self.fp,?ensure_ascii=False,?encoding='utf-8')
#?????????self.exportr.start_exporting()
#
#?????def?open_spider(self,?spider):
#?????????print('爬蟲開始了……')
#
#?????def?process_item(self,?item,?spider):
#?????????#?item_json?=?json.dumps(dict(item),?ensure_ascii=False)
#?????????#?self.fp.write(item_json+'\n')
#?????????self.exportr.export_item(item)
#?????????return?item
#
#?????def?close_spider(self,?spider):
#?????????self.exportr.finish_exporting()
#?????????self.fp.close()
#?????????print('爬蟲結(jié)束了…')
##########?方法三?##########
####?數(shù)據(jù)量比較多的時(shí)候,需要用JsonLinesItemExporter
from?scrapy.exporters?import?JsonLinesItemExporter
class?QsbkPipeline(object):
????def?__init__(self):
????????self.fp?=?open("duanzi.json",?"wb")???#以二進(jìn)制的方式寫入
????????self.exportr?=?JsonLinesItemExporter(self.fp,?ensure_ascii=False,?encoding='utf-8')
????def?open_spider(self,?spider):
????????print('爬蟲開始了……')
????def?process_item(self,?item,?spider):
????????self.exportr.export_item(item)
????????return?item
????def?close_spider(self,?spider):
????????self.fp.close()
????????print('爬蟲結(jié)束了…')
4、setting部分代碼
BOT_NAME?=?'qsbk'
SPIDER_MODULES?=?['qsbk.spiders']
NEWSPIDER_MODULE?=?'qsbk.spiders'
ROBOTSTXT_OBEY?=?False
DEFAULT_REQUEST_HEADERS?=?{
??'Accept':?'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
??'Accept-Language':?'en',
??'User-Agent':'Mozilla/5.0?(Windows?NT?6.1;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/71.0.3578.80?Safari/537.36'
}
ITEM_PIPELINES?=?{
???'qsbk.pipelines.QsbkPipeline':?300,
}
DOWNLOADER_MIDDLEWARES?=?{
???'qsbk.middlewares.RandomUserAgentMiddleware':?543,
}
MY_USER_AGENT?=?[
????"Mozilla/4.0?(compatible;?MSIE?6.0;?Windows?NT?5.1;?SV1;?AcooBrowser;?.NET?CLR?1.1.4322;?.NET?CLR?2.0.50727)",
????"Mozilla/4.0?(compatible;?MSIE?7.0;?Windows?NT?6.0;?Acoo?Browser;?SLCC1;?.NET?CLR?2.0.50727;?Media?Center?PC?5.0;?.NET?CLR?3.0.04506)",
????"Mozilla/4.0?(compatible;?MSIE?7.0;?AOL?9.5;?AOLBuild?4337.35;?Windows?NT?5.1;?.NET?CLR?1.1.4322;?.NET?CLR?2.0.50727)",
]
5、middlewares部分代碼
import?random
class?RandomUserAgentMiddleware(object):
????def?__init__(self,?user_agents):
????????self.user_agents?=?user_agents
????@classmethod
????def?from_crawler(cls,?crawler):
????????#?從settings.py中導(dǎo)入MY_USER_AGENT
????????s?=?cls(user_agents=crawler.settings.get('MY_USER_AGENT'))
????????return?s
????def?process_request(self,?request,?spider):
????????agent?=?random.choice(self.user_agents)
????????request.headers['User-Agent']?=?agent
????????return?None
運(yùn)行scrapy項(xiàng)目:
運(yùn)行scrapy項(xiàng)目。需要在終端,進(jìn)入項(xiàng)目所在的路徑,然后scrapy crawl [爬蟲名字]即可運(yùn)行指定的爬蟲。如果不想每次都在命令行中運(yùn)行,那么可以把這個(gè)命令寫在一個(gè)文件中。以后就在pycharm中執(zhí)行運(yùn)行這個(gè)文件就可以了。比如現(xiàn)在新創(chuàng)建一個(gè)文件叫做start.py,然后在這個(gè)文件中填入以下代碼:
from?scrapy?import?cmdline
cmdline.execute("scrapy?crawl?qsbk".split())
爬取結(jié)果

