Scrapy一個開源和協做的框架,其最初是爲了頁面抓取 (更確切來講, 網絡抓取 )所設計的,使用它能夠以快速、簡單、可擴展的方式從網站中提取所需的數據。但目前Scrapy的用途十分普遍,可用於如數據挖掘、監測和自動化測試等領域,也能夠應用在獲取API所返回的數據(例如 Amazon Associates Web Services ) 或者通用的網絡爬蟲。css
Scrapy 是基於twisted框架開發而來,twisted是一個流行的事件驅動的python網絡框架。所以Scrapy使用了一種非阻塞(又名異步)的代碼來實現併發。總體架構大體以下html
一、scrapy的工做流程python
第一步:爬蟲從spiders爬行器中發送request請求給engine引擎。web
第二部:引擎發送request請求給scheduler調度器,調度器從中調度請求,並要求下一個請求進來。ajax
第三部:調度程序將第一個請求返回給引擎。正則表達式
第四部:引擎將請求發送給下行加載程序downloader,經過下行加載中間件,而且準備下載網頁。shell
第五步:一旦頁面完成下載後,Downloader會生成一個響應(使用該頁面)並將其發送到引擎,經過Downloader中間件到達downloader下載器數據庫
第六步:引擎接收來自Downloader的響應,並將其發送給爬行器進行處理,經過爬行器中間件,到達爬行器瀏覽器
第七步:爬行器處理響應信息,並將處理後的結果經過爬行器中間件返回到引擎。網絡
第八步:引擎將處理過的數據發送到項目管道,而後將處理過的請求發送到調度程序,並請求可能的下一個請求進行爬行。
總結:
一、引擎負責控制系統全部組件之間的數據流,並在某些動做發生時觸發事件
二、調度器用來接受引擎發過來的請求, 壓入隊列中, 並在引擎再次請求的時候返回. 能夠想像成一個URL的優先級隊列, 由它來決定下一個要抓取的網址是什麼, 同時去除重複的網址
三、下載器用於下載網頁內容, 並將網頁內容返回給EGINE,下載器是創建在twisted這個高效的異步模型上的
四、爬蟲器SPIDERS是開發人員自定義的類,用來解析responses,而且提取items,或者發送新的請求
五、項目管道在items被提取後負責處理它們,主要包括清理、驗證、持久化(好比存到數據庫)等操做
六、下載器中間件位於Scrapy引擎和下載器之間,主要用來處理從EGINE傳到DOWLOADER的請求request,已經從DOWNLOADER傳到EGINE的響應response,你可用該中間件作如下幾件事情
一、在發送到下載程序以前處理一個請求(即在剪貼簿發送請求到網站以前);
二、在將其傳遞給蜘蛛以前,更改接收到響應;
三、發送一個新的請求,而不是傳遞接收到的響應;
四、在不獲取web頁面的狀況下對爬行器進行響應;
五、悄悄地放棄一些請求。
七、爬蟲中間件
位於EGINE和SPIDERS之間,主要工做是處理SPIDERS的輸入(即responses)和輸出(即requests)
官網連接:https://docs.scrapy.org/en/latest/topics/architecture.html
#Windows平臺 一、pip3 install wheel #安裝後,便支持經過wheel文件安裝軟件,wheel文件官網:https://www.lfd.uci.edu/~gohlke/pythonlibs 3、pip3 install lxml 4、pip3 install pyopenssl 五、下載並安裝pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/ 六、下載twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 七、執行pip3 install 下載目錄\Twisted-17.9.0-cp36-cp36m-win_amd64.whl 8、pip3 install scrapy #Linux平臺 一、pip3 install scrapy
#1 查看幫助 scrapy -h 或者是scrapy -l scrapy <command> -h #2 有兩種命令:其中Project-only必須切到項目文件夾下才能執行這種命令是局部命令,而Global的命令則不須要,是屬於全局命令 Global commands:全局命令 一、startproject #建立一個爬蟲項目,至關於建立了個爬蟲的總體框架,
scrapy startproject 項目名稱 二、genspider #建立一個爬蟲程序,能夠在配置文件中將網址域名註釋調,該網址域名的做用就是在網站的html中只容許爬該網址的數據
scrapy genspider 爬蟲名稱 須要爬的網址域名 三、settings #若是是在項目目錄下,則獲得的是該項目中settings的配置,不然不是,
scrapy settings --get=settings文件中的配置變量 四、runspider #運行一個獨立的python文件,沒必要建立項目,這個python文件能夠是一個爬蟲程序
scrapy runspider 爬蟲文件的絕對路徑 五、shell # 在交互式調試,如選擇器規則正確與否都是在該交互式環境下測試的,至關於get下來數據後將數據封裝到了個response對象內。
scrapy shell url地址
view(response);response.text;response.body; 六、fetch #獨立於程單純地爬取一個頁面,能夠拿到請求頭
scrapy fetch url地址
scrapy fetch --header url地址 七、 view #下載完畢後直接彈出瀏覽器,以此能夠分辨出哪些數據是ajax請求
scrapy view rul路徑 #若是頁面顯示內容不全,不全的內容則是ajax請求實現的,以此快速定位問題 八、version #
scrapy version 查看scrapy的版本
scrapy version -v 查看scrapy所依賴的庫版本
Project-only commands:局部命令,必須在項目目錄下才能執行 一、crawl #運行爬蟲,必須建立項目程序才行,確保配置文件settings中ROBOTSTXT_OBEY = False,機器人策略,關閉該策略後就不會受機器人策略的影響
scrapy crawl 爬蟲項目文件名 #和以前的runspider方法相比該方法必須在項目目錄下運行且受機器人策略的影響
scrapy crawl 爬蟲項目文件名 --nolog #運行爬蟲項目不打印日誌
scrapy crawl 爬蟲項目文件名 -a 參數名=參數值 #給爬蟲項目傳參,可是項目內部必須從新__int__方法來接受外部參數
scrapy crawl 爬蟲項目文件名 -a 參數名=參數值 --nolog #運行爬蟲項目不打印日誌而且傳參數給爬蟲項目 二、check #檢測項目(全部的爬蟲程序)中有無語法錯誤
scrapy check 三、list #列出項目中所包含的爬蟲名
scrapy list 四、edit #編輯器,通常不用 五、 parse # #以此能夠驗證咱們的回調函數是否正確,回調函數通常寫在爬蟲程序文件下
scrapy parse url地址 --callback 回調函數 六、bench #壓力測試
scrapy bench #3 官網連接 https://docs.scrapy.org/en/latest/topics/commands.html
總結:在命令行的命令或者是參數都是不用加引號的,
爬蟲項目的settings配置文件添加配置時都變量名必需要大寫,不然不識別
project_name/
scrapy.cfg
project_name/
__init__.py items.py pipelines.py settings.py spiders/ __init__.py 爬蟲1.py 爬蟲2.py 爬蟲3.py
文件說明:
注意:通常建立爬蟲文件時,以網站域名命名
import scrapy class XiaoHuarSpider(scrapy.spiders.Spider): name = "xiaohuar" # 爬蟲名稱 ***** allowed_domains = ["xiaohuar.com"] # 容許爬取的域名 start_urls = [ "http://www.xiaohuar.com/hua/", # 其實URL地址,該url地址是程序默認建立的,若是須要爬取該地址外的其餘地址數據就須要本身處理請求參數,從新請求方法 ] def parse(self, response): # 訪問起始URL並獲取結果後的回調函數
import sys,os sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')
#在項目目錄下新建:entrypoint.py from scrapy.cmdline import execute execute(['scrapy', 'crawl', 'xiaohua'])
強調:配置文件的選項必須是大寫,如X='1'
# -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule class BaiduSpider(CrawlSpider): name = 'xiaohua' allowed_domains = ['www.xiaohuar.com'] start_urls = ['http://www.xiaohuar.com/v/'] # download_delay = 1 rules = ( Rule(LinkExtractor(allow=r'p\-\d\-\d+\.html$'), callback='parse_item',follow=True,), ) def parse_item(self, response): if url: print('======下載視頻==============================', url) yield scrapy.Request(url,callback=self.save) def save(self,response): print('======保存視頻==============================',response.url,len(response.body)) import time import hashlib m=hashlib.md5() m.update(str(time.time()).encode('utf-8')) m.update(response.url.encode('utf-8')) filename=r'E:\\mv\\%s.mp4' %m.hexdigest() with open(filename,'wb') as f: f.write(response.body)
https://docs.scrapy.org/en/latest/topics/spiders.html
response.selector.css()
response.selector.xpath()
可簡寫爲
response.css()
response.xpath()
一、查找標籤
response.css('div a ')#經過標籤名查找標籤的內容 response.xpath('//body/a') #開頭的//表明從整篇文檔中尋找,body以後的/表明body的兒子 response.xpath('//body//a') #開頭的//表明從整篇文檔中尋找,body以後的//表明body的子子孫孫
總結://與/的區別:兒子和後代的區別,可是獲得的都是一個列表
二、查找標籤下的內容(text方法)
response.css('div a::text')#先定位標籤而後經過::的方式查找標籤的內容
response.xpath('//body//a/text()') 三、查找標籤下的內容
extract與extract_first:從selector對象中解出內容 response.xpath('//div/a/text()').extract() #獲得的是個解析後的內容,是個列表形式 response.xpath('//div/a/text()').extract_first()#獲得的是個解析後的內容,是個字符串形式
四、查找標籤下的屬性: response.xpath('//div/a/@href').extract_first() #獲得的是標籤的href屬性,能夠跟標籤的任意屬性xpath的屬性加前綴@ response.css('div a::attr(href)').extract_first() 5、嵌套查找加混合查找 response.xpath('//div').css('a').xpath('@href').extract_first() 6、設置查找默認值 response.xpath('//div[@id="xxx"]').extract_first(default="not found")#爲了防止查找不到匹配的標籤而設置默認值 七、按照標籤屬性查找 response.xpath('//div[@id="images"]/a[@href="image3.html"]/text()').extract() #若是按照屬性查找標籤就必須加上中括號,再寫匹配規則 response.css('#images a[@href="image3.html"]/text()').extract() 八、按照標籤屬性模糊查找 response.xpath('//a[contains(@href,"image")]/@href').extract()#若是按照標籤屬性模糊查找就必須加上contains()方法,而後再在裏面寫匹配規則,匹配規則用逗號隔開 response.css('a[href*="image"]::attr(href)').extract() response.xpath('//a[contains(@href,"image")]/img/@src').extract() response.css('a[href*="imag"] img::attr(src)').extract() response.xpath('//*[@href="image1.html"]') response.css('*[href="image1.html"]') 9、正則表達式查找 response.xpath('//a/text()').re(r'Name: (.*)') response.xpath('//a/text()').re_first(r'Name: (.*)') 十、xpath相對路徑 >>> res=response.xpath('//a[contains(@href,"3")]')[0] >>> res.xpath('img') [<Selector xpath='img' data='<img src="image3_thumb.jpg">'>] >>> res.xpath('./img') [<Selector xpath='./img' data='<img src="image3_thumb.jpg">'>] >>> res.xpath('.//img') [<Selector xpath='.//img' data='<img src="image3_thumb.jpg">'>] >>> res.xpath('//img') #這就是從頭開始掃描 十一、、帶變量的xpath response.xpath('//div[@id=$xxx]/a/text()',xxx='images').extract_first()#帶變量查找 response.xpath('//div[count(a)=$yyy]/@id',yyy=5).extract_first() #求有5個a標籤的div的id