scrapy框架

目錄:

 

一 介紹

        Scrapy一個開源和協做的框架,其最初是爲了頁面抓取 (更確切來講, 網絡抓取 )所設計的,使用它能夠以快速、簡單、可擴展的方式從網站中提取所需的數據。但目前Scrapy的用途十分普遍,可用於如數據挖掘、監測和自動化測試等領域,也能夠應用在獲取API所返回的數據(例如 Amazon Associates Web Services ) 或者通用的網絡爬蟲。html

    Scrapy 是基於twisted框架開發而來,twisted是一個流行的事件驅動的python網絡框架。所以Scrapy使用了一種非阻塞(又名異步)的代碼來實現併發。總體架構大體以下python

框架組件

  1. 引擎(EGINE)
    1. 引擎負責控制系統是由組件之間的數據流,並在某些動做發生時觸發事件
  2. 調度器(SCHEDULER)
    1. 用來接收引擎發送過來的請求,壓入隊列中,並在引擎再次請求的時間返回。能夠想象出一個URLde 優先級隊列,由它來決定下一個要抓取的網址是什麼,同時去除重複的網址
  3. 下載器(DOWNLOADER)
    1. 用於下載網頁內容,並將網頁內容返回給EGINE。下載器是創建在twisted這個高效的異步模型上的。
  4. 爬蟲(SPIDERS)
    1. SPIDERS是開發者自定義的類,用來解析response,而且提取items,或者發送新的請求
  5. 項目管道(ITEMPIPELINES)
    1. 用來處理item,主要包括清理、驗證、持久化(好比存到數據庫)等操做
  6. 下載器中間件(Downloader Middleware)
    1. 位於scrape引擎到下載器之間,主要用來處理從egine到downloader的請求request,和從Downloader到egine的響應response。能夠在中間件作以下操做
      1. 處理一個在發送到downloader之間的請求
      2. 在發送到spider以前改變一個被接收的響應
      3. 直接發送一個新請求,代替發送響應給spider
      4. 若是沒有查詢到web頁面,就不發送響應
      5. 悄悄的刪除一些請求
  7. 爬蟲中間件(Spider MIddleware)
    1. 位於EGINE和SPIDERS之間,主要工做是處理SPIDERS的輸入(即response)和輸出(即requests)

數據流

  1. 引擎首先從spider獲取一個初始請求爬行
  2. 引擎經過SCHEDULER分配這個請求,並開始請求下一個請求去爬行
  3. 調度器返回一個請求給引擎
  4. 引擎經過中間件把請求發送給下載器
  5. 當頁面下載完畢以後,下載器會經過中間件把返回的響應發送給引擎
  6. 引擎接收到響應以後,會經過中間件把響應發給spider去處理
  7. spider會處理響應,並把爬取得items對象和新的請求經過中間件返回給引擎
  8. 引擎則會把接收到的處理的items對象發送給項目管道,在發送被處理的請求給調度器看看有沒有下一個請求過來
  9. 重複過程1,直到調度器沒有請求需求爲止。

 

二 安裝

 1 #Windows平臺
 2     一、pip3 install wheel #安裝後,便支持經過wheel文件安裝軟件,wheel文件官網:https://www.lfd.uci.edu/~gohlke/pythonlibs
 3     3、pip3 install lxml
 4     4、pip3 install pyopenssl
 5     五、下載並安裝pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/
 6     六、下載twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
 7     七、執行pip3 install 下載目錄\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
 8     8、pip3 install scrapy
 9   
10 #Linux平臺
11     一、pip3 install scrapy

 

三 命令集

 1 # 1 幫助命令
 2 scrapy -h
 3 scrapy <command> -h
 4 
 5 # 2 global命令
 6 startproject    # 建立項目
 7 genspider       # 建立爬蟲程序
 8 settings        # 若是是在項目目錄下,則獲得的是該項目的配置,不然是全局的配置
 9 runspider       # 運行一個獨立的python文件,沒必要建立項目
10 shell           # scrapy shell url 地址,在交互調試,如選擇器規則正確與否
11 fetch           # 獨立與線程單純地爬取一個頁面,能夠拿到請求頭
12 view            # 下載完畢後直接彈出瀏覽器,以此能夠分辨出那些數據是ajax請求
13 version         # scrapy vewsion 查看scrapy版本,scrapy version -v查看scrapy依賴庫的版本
14 
15 # 3 項目命令(必須切換到項目文件下才能執行)
16 crawl           # 運行爬蟲,必須建立項目,確保配置文件中ROBOTSTXT_OBEY = Fasle
17 check           # 檢測項目中有無語法錯誤
18 list            # 列出項目中所包含的爬蟲名
19 edit            # 編輯器,用來編輯文件使用,通常不用
20 parse           # scrapy parse url地址 -- callback 回調函數  # 以此能夠驗證咱們的回調函數是否正確
21 bench           # scrapy bentch壓力測試
22 
23 #3 官網連接
24     https://docs.scrapy.org/en/latest/topics/commands.html
 1 #一、執行全局命令:請確保不在某個項目的目錄下,排除受該項目配置的影響
 2 scrapy startproject MyProject
 3 
 4 cd MyProject
 5 scrapy genspider baidu www.baidu.com
 6 
 7 scrapy settings --get XXX #若是切換到項目目錄下,看到的則是該項目的配置
 8 
 9 scrapy runspider baidu.py
10 
11 scrapy shell https://www.baidu.com
12     response
13     response.status
14     response.body
15     view(response)
16     
17 scrapy view https://www.taobao.com #若是頁面顯示內容不全,不全的內容則是ajax請求實現的,以此快速定位問題
18 
19 scrapy fetch --nolog --headers https://www.taobao.com
20 
21 scrapy version #scrapy的版本
22 
23 scrapy version -v #依賴庫的版本
24 
25 
26 #二、執行項目命令:切到項目目錄下
27 scrapy crawl baidu
28 scrapy check
29 scrapy list
30 scrapy parse http://quotes.toscrape.com/ --callback parse
31 scrapy bench
示範用法

 

四 項目結構以及應用

一、結構

1.1 文件說明:

  • scrapy.cfg    項目的主配置信息,用來部署scrapy時使用,爬蟲相關的配置信息在settings.py文件中
  • settings.py    配置文件,如:遞歸的層數、併發數。延遲下載等。變量名必須大寫。
  • pipelines.py    數據處理行爲,如:通常結構化的數據持久化
  • middlewares.py    中間件,用來在請求和響應的過程中作一些操做
  • items.py    設置數據存儲模板,用於結構化數據,如:Django的model
  • spiders    爬蟲目錄,如:建立文件,編寫爬蟲規則,lagou.py便是已經建立的一個爬蟲規則
 
注意:通常建立爬蟲文件時,以網站域名命名

二、 配置在pycharm中能夠直接執行爬蟲程序

1 # 在項目目錄下新建:entrypoint.py
2 from scrapy.cmdline import execute
3 
4 execute(['scrapy, 'crawl', 'xiaohuar'])

三、 關於windows編碼問題

1 import sys, os
2 
3 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb18030')

 

五 Spiders

一、介紹

        Spider是由一系列類(定義了一個網站或一組網址將被爬取)組成,具體包括如何執行爬去任務而且若是從頁面中提取結構化數據
也就是說,Spiders是咱們爲了一個特定的網址或一組網址自定義爬取和解析頁面行爲的地方。
 

二、Spiders任務

  1. 生成初始的requests來爬取第一個urls,而且標識一個回調函數
        第一個請求定義在start_requests()方法內,默認從start_urls列表中獲取url來生成request請求,默認的回調函數是parse方法,回調函數在下載完成返回response時自動觸發
    2. 在回調函數中,解析response而且返回值
        返回值能夠有4種:
                                    -> 包含解析數據的字典
                                    -> Item對象
                                    -> 新的Request對象(新的Requests也須要指定一個回調函數)
                                    -> 可迭代對象(包含Items或Request)
    3. 在回調函數中解析頁面內容
        一般使用Scrapy自帶的Seletors,但很明顯你也可使用Beautifulsoup, lxml或其餘的模塊去解析
    4. 最後,針對返回的items對象將會被持久化到數據庫
        經過Item Pipeline組件存到數據庫:
            https://docs.scrapy.org/en/latest/topics/item-pipeline.html#topics-item-pipeline
        或處處到不一樣的文件:
            (經過Feed exports:https://docs.scrapy.org/en/latest/topics/feed-exports.html#topics-feed-exports)

三、Spiders提供的五種類

1 # 1  scrapy.spiders.Spider  # scrapy.Spider等同於scrapy.spiders.Spider
2 # 2  scrapy.spiders.CrawSpider
3 # 3  scrapy.spiders.XMLFeedSpider
4 # 4  scrapy.spiders.CSVFeedSpider
5 # 5  scrapy.spiders.SitemapSpider

四、導入使用以及基本配置

 1 from scrapy
 2 from scrapy.spiders import Spider, CrawSpider, XMLFeedSpider, CSVFeedSpider, SitemapSpider
 3 
 4 class AmazonSpider(scrapy.Spider):  # 自定義類,繼承Spider提供的基類
 5     # class scrapy.spiders.Spider
 6     # 這是最簡單的spider類,任何其餘的spider類都須要繼承它(包含你本身定義的)
 7     # 該類不提供任何特殊的功能,它僅提供了一個默認的start_requests方法,默認從start_urls中讀取url地址發送requests請求,而且默認parse做爲回調函數
 8     name = 'amazon'
 9     allowed_domains = ['www.amazon.cn']
10     start_urls = ['http://www.amazon.cn/']
11     
12     # 自定製配置文件,會首先讀取這個配置文件
13     custom_settings = {
14          'BOT_NAME' : 'Egon_Spider_Amazon',
15         'REQUEST_HEADERS' : {
16           'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
17           'Accept-Language': 'en',
18         }
19     }
20     
21     def parse(self, response):
22         pass
 1 # 一、name='amazon'
 2 定義爬蟲名,scrapy會根據該值定位爬蟲程序
 3 因此它必需要有且必須惟一(In Python 2 this must be ASCII only)
 4 
 5 # 二、allowed_domains = ['www.amazon.cn']
 6 定義容許爬取得域名,若是offsiteMiddleware啓動(默認就啓動),
 7 那麼不屬於該列表的域名及子域名都不容許爬取
 8 若是爬去的網址爲:https://www.example.com/1.html,那麼就添加"example.com"到列表
 9     
10 # 三、start_urls = ['http://www.amazon.cn']
11 若是沒有指定url,就從該列表中讀取url來生成第一個請求
12 
13 # 四、custom_settings
14 值爲一個字典,定義一些配置信息,在運行爬蟲程序時,這些配置覆蓋項目級別的配置
15 因此custom_settings必須被定義成一個類屬性,因爲settings會在類實例化前被加載
16 
17 # 五、settings
18 經過self.settings['配置項的名字']能夠訪問settings.py中的配置,若是定義了custom_settings仍是以本身的爲準
19 
20 # 六、logger
21 日誌名默認爲spider的內容
22 self.logger.debug('==>%s' %self.settings['BOT_NAME'])
23 
24 # 七、crawler
25 該屬性必須被定義到類方法from_crawler中
26 
27 # 八、from_crawler(crealer, *args, **kwargs)
28 You probably won’t need to override this directly  because the default implementation acts as a proxy to the __init__() method, calling it with the given arguments args and named arguments kwargs.
29 
30 # 九、start_requests()
31 該方法用來發起第一個Requests請求,且必須返回一個可迭代的對象。它在爬蟲程序打開時就被Scrapy調用,Scrapy只調用它一次。
32 默認從start_urls裏取出每一個url來生成Rquest(url, dont_filter=True)
33 若是你想要改變起始爬取得Requests,你就須要覆蓋整個方法,例如你想要起始發送一個POST請求,以下:
34 class MySpider(scrapy.Spider):
35     name = 'myspider'
36     
37     def start_requests(self):
38         return [scrapy.FormRequest("http://www.example.com/login", formdata={"user": "join", "pass": "secret"}, callback=self.logged_in)]
39     
40     def logged_in(self, response):
41         # here you would extract links to follow and return Requests for each of them, with another callback
42         pass
43     
44 # 十、parse(reqponse)
45 這個是默認的回調函數,全部的回調函數必須返回an iteranle of Request and/or dicts or Item objects.
46 
47 # 十一、log(message[, level, component])
48 Wrapper that sends a log message through the Spider's logger,  kept for backwards compatibility.
49 For more information see Logging from Spiders
50 
51 # 十二、closed(reason)
52 爬蟲程序結束時自動觸發
定製scrapy.spider屬性與方法詳解
 1 去重規則應該多個爬蟲共享,但凡一個爬蟲爬取了,其餘都不要爬了
 2 
 3 # 方法一:
 4 1、新增類屬性
 5 visited = set()  # 類屬性
 6 
 7 2、回調函數parse方法內
 8 def parse(self, response):
 9     if rsponse.url in self.visited:
10         return None
11     ...
12     self.visited.add(response.url)
13     
14 # 方法一改進:針對url可能過長,因此咱們存放url的hash值
15 def parse(self, response):
16     url = md5(response.request.url)
17     if url in self.visited:
18         return None
19     ...
20     self.visited.add(url)
21     
22  
23 # 方法二:Scrapy自帶去重功能
24 配置文件:
25 DUPEFILTER_CLASS = 'scrapy.dupefilter.RFPDupeFilter'  # 默認的去重規則,組重規則在內存中
26 DUPEFILTER_DEBUG = False
27 JOBDIR = '保存範文記錄的日誌路徑,如:/root/'  # 最終路徑爲/root/requests.seen,去重規則放文件中
28 
29 scrapy自帶去重規則默認爲RFPDupeFilter,只須要咱們指定
30 Request(..., dont_filter=False), 若是dont_filter=True則告訴scrapy這個rul不參與去重
31 
32 
33 # 方法三:咱們能夠仿照RFPDupeFilter自定義去重規則
34 from scrapy.dupefilter import RFPDupeFilter  # 看源碼,仿照BaseDupeFilter
35 # 步驟1:在項目目錄下自定義去重文件dup.py
36 class UrlFilter(object):
37     def __init__(self):
38         self.visited = set()  # 或者放到數據庫
39         
40     @classmethod
41     def from_settings(cls, settings):
42         return cls()
43     def request_seen(self, request):
44         if request.url in self.visited:
45             return True
46         self.visited.add(request.url)
47         
48     def open(self): # can return deferred
49         pass
50     
51     def close(self, reason):  # can return a deferred
52         pass
53     
54     def log(self, request, spider):  # log that a request has been filtered
55         pass
56     
57 # 步驟二:配置文件settings.py
58 DUPEFILTER_CLASS = "項目名.dup.UrlFilter"
59 
60 # 源碼分析
61 from scrapy.core.scheduler import Scheduler
62 # 見Scheduler下的enqueue_request方法:self.df.request_seen(request)
去重複規則:去除重複的url
 1 import scrapy
 2 
 3 class MySpider(scrapy.Spider):
 4     name = 'example.com'
 5     allowed_domains = ['example.com']
 6     start_urls = [
 7         ‘http://www.example.com/1.html',
 8         'http://www.example.com/2.html',
 9     ]
10     
11     def parse(self, response):
12         self.logger.info('A response from %s just arrived!', response.url)
13         
14 # 實例二
15 import scrapy
16 
17 class MySpider(scrapy.Spider):
18     name = 'example.com'
19     allowed_domains = ['example.com']
20     start_urls = [
21         ‘http://www.example.com/1.html',
22         'http://www.example.com/2.html',
23     ]
24     
25     def parse(self, response):
26         for h2 in response.xpath('//h2').extract():
27             yield {'title':h2}
28             
29         for url in response.xpath('//a/@href').extract():
30             yield scrapy.Request(url, callback=self.parse)
31             
32             
33 # 例三:在start_requests()內直接指定起始爬取得urls,start_urls就沒有用了
34 import scrapy
35 from myproject.items import MyItem
36 
37 class MySpider(scrapy.Spider):
38     name = 'example.com'
39     allowed_domains = ['example.com']
40     
41     def start_requests(self):
42         yield scrapy.Request('http://www.example.com/1.html', self.parse)
43         yield scrapy.Request('http://www.example.com/2.html', self.parse)
44         yield scrapy.Request('httl://www.example.com/3.html', self.parse)
45         
46     def parse(self, response):
47         for h3 in response.xpath('//h3').extract():
48             yield MyItem(title=h3)
49             
50         for url in response.xpath('//a/@href').extract():
51             yield scrapy.Request(url, callback=self.parse)
例子
 1 # 咱們可能須要在命令行尾爬蟲程序傳遞參數,好比傳遞初始的url
 2 # 執行命令行
 3 scrapy crawl myspider -a category=electronics
 4 
 5 # 在__init__方法中能夠接收外部傳進來的參數
 6 import scrapy
 7 
 8 class MySpider(scrapy.Spider):
 9     name = 'myspider'
10     
11     def __init__(self, category=None, *args, **kwargs):
12         super(MySpider, self).__init__(*args, **kwargs)
13         self.start_urls = ['http://www.example.com/categories/%s' % category]
14 # 主要接收的參數全都是字符串,若是想要結構化數據,你須要用相似json.loads的方法
參數傳遞

 

相關文章
相關標籤/搜索