Scrapy框架

一 、介紹

    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

文件說明:

  • scrapy.cfg  整個項目的主配置信息,用來部署scrapy時使用,爬蟲相關的配置信息在settings.py文件中。
  • items.py    設置數據存儲模板,用於結構化數據,如:Django的Model
  • pipelines    數據處理行爲,如:通常結構化的數據持久化
  • settings.py 配置文件,如:遞歸的層數、併發數,延遲下載等。強調:配置文件的選項必須大寫不然視爲無效,正確寫法USER_AGENT='xxxx'
  • spiders      爬蟲目錄,如:建立文件,編寫爬蟲規則

注意:通常建立爬蟲文件時,以網站域名命名

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')

五 Spiders

#在項目目錄下新建: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

六 Selectors

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
複製代碼
相關文章
相關標籤/搜索