天天看點

爬蟲基礎 Scrapy架構架構Scrapy架構架構Scrapy快速入門CrawlSpiderScrapy ShellRequest和Response對象

Scrapy架構架構

Scrapy架構介紹:

寫一個爬蟲,需要做很多的事情。比如:發送網絡請求、資料解析、資料存儲、反反爬蟲機制(更換ip代理、設定請求頭等)、異步請求等。這些工作如果每次都要自己從零開始寫的話,比較浪費時間。是以

Scrapy

把一些基礎的東西封裝好了,在他上面寫爬蟲可以變的更加的高效(爬取效率和開發效率)。是以真正在公司裡,一些上了量的爬蟲,都是使用

Scrapy

架構來解決。

Scrapy架構圖:

  1. 流程圖(1):
爬蟲基礎 Scrapy架構架構Scrapy架構架構Scrapy快速入門CrawlSpiderScrapy ShellRequest和Response對象
  1. 流程圖(2):
爬蟲基礎 Scrapy架構架構Scrapy架構架構Scrapy快速入門CrawlSpiderScrapy ShellRequest和Response對象

架構子產品功能:

1.爬蟲發送請求 并不是馬上發出去 而是給引擎

2.引擎發給排程器 排程器接收到url 以後 将url生成requests對象 存儲到隊列中

3.引擎從排程器中取出請求

4.引擎将requests對象 扔給下載下傳器

5.下載下傳器拿到請求從網上下載下傳資料 再将資料 組裝成response對象傳回給引擎

6.引擎拿到response對象 傳回給爬蟲

7.爬蟲對資料再進行分析 留下想要 的 資料 再傳回給 引擎

8.引擎再給管道 存到 redis 或者mysql 或者 mongodb中

引擎和下載下傳器 之間 有中間件 爬蟲和 引擎之間 也有中間件

  1. Scrapy Engine(引擎)

    Scrapy

    架構的核心部分。負責在

    Spider

    ItemPipeline

    Downloader

    Scheduler

    中間通信、傳遞資料等。類似于汽車發動機
  2. Spider(爬蟲)

    :發送需要爬取的連結給引擎,最後引擎把其他子產品請求回來的資料再發送給爬蟲,爬蟲就去解析想要的資料。這個部分是

    我們開發者自己寫

    的,因為要爬取哪些連結,頁面中的哪些資料是我們需要的,都是由程式員自己決定。
  3. Scheduler(排程器)

    :負責接收引擎發送過來的請求,并按照一定的方式進行排列和整理,負責排程請求的順序等。
  4. Downloader(下載下傳器)

    :負責接收引擎傳過來的下載下傳請求,然後去網絡上下載下傳對應的資料再交還給引擎。
  5. Item Pipeline(管道)

    :負責将

    Spider(爬蟲)

    傳遞過來的資料進行儲存。具體儲存在哪裡,應該看開發者自己的需求。
  6. Downloader Middlewares(下載下傳中間件)

    :可以擴充下載下傳器和引擎之間通信功能的中間件。
  7. Spider Middlewares(Spider中間件)

    :可以擴充引擎和爬蟲之間通信功能的中間件。

Scrapy快速入門

安裝和文檔:

  1. 安裝:通過

    pip install scrapy

    即可安裝。 如果出現 pyasn1的錯誤 裝一下 pip install pyasn1-modules
  2. Scrapy官方文檔:http://doc.scrapy.org/en/latest
  3. Scrapy中文文檔:http://scrapy-chs.readthedocs.io/zh_CN/latest/index.html
注意:
  1. 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

    安裝。
  2. 如果在

    windows

    系統下,提示這個錯誤

    ModuleNotFoundError: No module named 'win32api'

    ,那麼使用以下指令可以解決:

    pip install pypiwin32

  3. 下載下傳 Twisted-18.9.0-cp36-cp36m-win_amd64.whl 然後放到指定的目錄下 純英文 沒權限限制 切換到這個目錄 pip install Twisted-18.9.0-cp36-cp36m-win_amd64.whl
下載下傳指定的python版本及系統版本
  1. pip install scrapy

快速入門:

建立項目:

要使用

Scrapy

架構建立項目,需要通過指令來建立。首先進入到你想把這個項目存放的目錄。然後使用以下指令建立:

scrapy startproject [項目名稱]
           

目錄結構介紹:

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-oKD1NWYM-1600142893172)(目錄結構.png)]

以下介紹下主要檔案的作用:

1. items.py:用來存放爬蟲爬取下來資料的模型。
  2. middlewares.py:用來存放各種中間件的檔案。爬蟲中間件  下載下傳中間件  
  3. pipelines.py:用來将`items`的模型存儲到本地磁盤中。
  4. settings.py:本爬蟲的一些配置資訊(比如請求頭、多久發送一次請求、ip代理池等)。
  5. scrapy.cfg:項目的配置檔案。
  6. spiders包:以後所有的爬蟲,都是存放到這個裡面。
           

當引擎将下載下傳組裝的respons對象給 爬蟲的時候

爬蟲對資料進行分析

response.xpath() 詳情 ctrl+滑鼠點選 xpath 檢視 其它的分析方法 傳回的内容是 SelectorList

一下兩個都是将其轉成Unicode編碼 并提取出來

get() 傳回的是Selector 中的第一個文本

getall()傳回的是Selector 中的所有文本 是個清單

使用Scrapy架構爬取糗事百科段子:

使用指令建立一個爬蟲:

scrapy genspider qsbk "qiushibaike.com"
           

建立了一個名字叫做

qsbk

的爬蟲,并且能爬取的網頁隻會限制在

qiushibaike.com

這個域名下。

爬蟲代碼解析:

import scrapy

class QsbkSpider(scrapy.Spider):
    name = 'qsbk'
    allowed_domains = ['qiushibaike.com']
    start_urls = ['http://qiushibaike.com/']

    def parse(self, response):
        pass
           

其實這些代碼我們完全可以自己手動去寫,而不用指令。隻不過是不用指令,自己寫這些代碼比較麻煩。

要建立一個Spider,那麼必須自定義一個類,繼承自

scrapy.Spider

,然後在這個類中定義三個屬性和一個方法。

1. name:這個爬蟲的名字,名字必須是唯一的。
  2. allow_domains:允許的域名。爬蟲隻會爬取這個域名下的網頁,其他不是這個域名下的網頁會被自動忽略。
  3. start_urls:爬蟲從這個變量中的url開始。
  4. parse:引擎會把下載下傳器下載下傳回來的資料扔給爬蟲解析,爬蟲再把資料傳給這個`parse`方法。這個是個固定的寫法。這個方法的作用有兩個,第一個是提取想要的資料。第二個是生成下一個請求的url。
           

修改

settings.py

代碼:

在做一個爬蟲之前,一定要記得修改

setttings.py

中的設定。兩個地方是強烈建議設定的。

1. `ROBOTSTXT_OBEY`設定為False。預設是True。即遵守機器協定,那麼在爬蟲的時候,scrapy首先去找robots.txt檔案,如果沒有找到。則直接停止爬取。
  2. `DEFAULT_REQUEST_HEADERS`添加`User-Agent`。這個也是告訴伺服器,我這個請求是一個正常的請求,不是一個爬蟲。
           

完成的爬蟲代碼:

  1. 爬蟲部分代碼:
    import scrapy
     from abcspider.items import QsbkItem
    
     class QsbkSpider(scrapy.Spider):
         name = 'qsbk'
         allowed_domains = ['qiushibaike.com']
         start_urls = ['https://www.qiushibaike.com/text/']
    
         def parse(self, response):
             outerbox = response.xpath("//div[@id='content-left']/div")
             items = []
             for box in outerbox:
                 author = box.xpath(".//div[contains(@class,'author')]//h2/text()").extract_first().strip()
                 content = box.xpath(".//div[@class='content']/span/text()").extract_first().strip()
                 item = QsbkItem()
                 item["author"] = author
                 item["content"] = content
                 items.append(item)
             return items
               
  2. items.py部分代碼:
    import scrapy
     class QsbkItem(scrapy.Item):
         author = scrapy.Field()
         content = scrapy.Field()
               
  3. pipeline部分代碼:
    import json
    
     class AbcspiderPipeline(object):
         def __init__(self):
    
             self.items = []
    
         def process_item(self, item, spider):
             self.items.append(dict(item))
             print("="*40)
             return item
    
         def close_spider(self,spider):
             with open('qsbk.json','w',encoding='utf-8') as fp:
                 json.dump(self.items,fp,ensure_ascii=False)
               

運作scrapy項目:

運作scrapy項目。需要在終端,進入項目所在的路徑,然後

scrapy crawl [爬蟲名字]

即可運作指定的爬蟲。如果不想每次都在指令行中運作,那麼可以把這個指令寫在一個檔案中。以後就在pycharm中執行運作這個檔案就可以了。比如現在新建立一個檔案叫做

start.py

,然後在這個檔案中填入以下代碼:

from scrapy import cmdline

cmdline.execute("scrapy crawl qsbk".split())
           

pipline 管道 用來将資料存儲在檔案或者資料庫中 有三個方法是常用的

  1. open_spider(self,spider) #當爬蟲被打開的時候執行
  2. process_item(self, item, spider)當爬蟲 有item 傳遞過來的時候 調用  
               
  3. close_spider(self,spider) #當爬蟲關閉的時候調用

scrapy 導出器 JsonItemExporter 、JsonLinesItemExporter

1.JsonItemExporter

每次把資料添加到記憶體中 最後統一寫到磁盤中 好處存儲的是一個滿足json規則的資料 缺點:資料量大 耗記憶體
from  scrapy.exporters import JsonItemExporter,JsonLinesItemExporter
class QsbkPipeline(object):
    def __init__(self):
        self.fp = open("qsbk.json",'wb')
        self.exporter = JsonItemExporter(self.fp,ensure_ascii=False,encoding='utf-8')
        self.exporter.start_exporting()
    def open_spider(self,spider):
        print("爬蟲開始了......")
    def process_item(self, item, spider):
        self.exporter.export_item(item)
        return item

    def close_spider(self,spider):
        self.fp.close()
        print("爬蟲結束了......")
           

2.JsonLinesItemExporter

每次調用export_item 存到磁盤中 好處 不耗記憶體 直接持久化 安全 壞處 是每個字典是一行 整個檔案不滿足json規則
from  scrapy.exporters import JsonLinesItemExporter
class QsbkPipeline(object):
    def __init__(self):
        self.fp = open("duanzi.json",'wb')
        self.exporter = JsonLinesItemExporter(self.fp,ensure_ascii=False,encoding='utf-8')
    def open_spider(self,spider):
        print("爬蟲開始了......")
    def process_item(self, item, spider):
        self.exporter.export_item(item)
        return item

    def close_spider(self,spider):
        self.fp.close()
        print("爬蟲結束了......")
           

糗事百科 分頁

next_url = response.xpath("//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)
           

CrawlSpider

在上一個糗事百科的爬蟲案例中。我們是自己在解析完整個頁面後擷取下一頁的url,然後重新發送一個請求。有時候我們想要這樣做,隻要滿足某個條件的url,都給我進行爬取。那麼這時候我們就可以通過

CrawlSpider

來幫我們完成了。

CrawlSpider

繼承自

Spider

,隻不過是在之前的基礎之上增加了新的功能,可以定義爬取的url的規則,以後scrapy碰到滿足條件的url都進行爬取,而不用手動的

yield Request

CrawlSpider爬蟲:

建立CrawlSpider爬蟲:

之前建立爬蟲的方式是通過

scrapy genspider [爬蟲名字] [域名]

的方式建立的。如果想要建立

CrawlSpider

爬蟲,那麼應該通過以下指令建立:

scrapy genspider -t crawl [爬蟲名字] [域名]
           

LinkExtractors連結提取器:

使用

LinkExtractors

可以不用程式員自己提取想要的url,然後發送請求。這些工作都可以交給

LinkExtractors

,他會在所有爬的頁面中找到滿足規則的

url

,實作自動的爬取。以下對

LinkExtractors

類做一個簡單的介紹:

class scrapy.linkextractors.LinkExtractor(
    allow = (),
    deny = (),
    allow_domains = (),
    deny_domains = (),
    deny_extensions = None,
    restrict_xpaths = (),
    tags = ('a','area'),
    attrs = ('href'),
    canonicalize = True,
    unique = True,
    process_value = None
)
           

主要參數講解:

  • allow:允許的url。所有滿足這個正規表達式的url都會被提取。
  • deny:禁止的url。所有滿足這個正規表達式的url都不會被提取。
  • allow_domains:允許的域名。隻有在這個裡面指定的域名的url才會被提取。
  • deny_domains:禁止的域名。所有在這個裡面指定的域名的url都不會被提取。
  • restrict_xpaths:嚴格的xpath。和allow共同過濾連結。

Rule規則類:

定義爬蟲的規則類。以下對這個類做一個簡單的介紹:

class scrapy.spiders.Rule(
    link_extractor, 
    callback = None, 
    cb_kwargs = None, 
    follow = None, 
    process_links = None, 
    process_request = None
)
           

主要參數講解:

  • link_extractor:一個

    LinkExtractor

    對象,用于定義爬取規則。
  • callback:滿足這個規則的url,應該要執行哪個回調函數。因為

    CrawlSpider

    使用了

    parse

    作為回調函數,是以不要覆寫

    parse

    作為回調函數自己的回調函數。
  • follow:指定根據該規則從response中提取的連結是否需要跟進。
  • process_links:從link_extractor中擷取到連結後會傳遞給這個函數,用來過濾不需要爬取的連結。

Scrapy Shell

我們想要在爬蟲中使用xpath、beautifulsoup、正規表達式、css選擇器等來提取想要的資料。但是因為

scrapy

是一個比較重的架構。每次運作起來都要等待一段時間。是以要去驗證我們寫的提取規則是否正确,是一個比較麻煩的事情。是以

Scrapy

提供了一個shell,用來友善的測試規則。當然也不僅僅局限于這一個功能。

打開Scrapy Shell:

打開cmd終端,進入到

Scrapy

項目所在的目錄,然後進入到

scrapy

架構所在的虛拟環境中,輸入指令

scrapy shell [連結]

。就會進入到scrapy的shell環境中。在這個環境中,你可以跟在爬蟲的

parse

方法中一樣使用了。

scrapy shell https://www.qiushibaike.com/text/page/1/

>>> title = response.xpath("//div[@class='col1 old-style-col1']/div//h2/text()").get().strip()
>>> print(title)
石頭,剪刀,破布 #代表成功了 
           

Request和Response對象

Request對象:

Request對象在我們寫爬蟲,爬取一頁的資料需要重新發送一個請求的時候調用。這個類需要傳遞一些參數,其中比較常用的參數有:

  1. url

    :這個request對象發送請求的url。
  2. callback

    :在下載下傳器下載下傳完相應的資料後執行的回調函數。
  3. method

    :請求的方法。預設為

    GET

    方法,可以設定為其他方法。
  4. headers

    :請求頭,對于一些固定的設定,放在

    settings.py

    中指定就可以了。對于那些非固定的,可以在發送請求的時候指定。
  5. meta

    :比較常用。用于在不同的請求之間傳遞資料用的。
  6. encoding

    :編碼。預設的為

    utf-8

    ,使用預設的就可以了。
  7. dont_filter

    :表示不由排程器過濾。在執行多次重複的請求的時候用得比較多。
  8. errback

    :在發生錯誤的時候執行的函數。

Response對象:

Response對象一般是由

Scrapy

給你自動建構的。是以開發者不需要關心如何建立

Response

對象,而是如何使用他。

Response

對象有很多屬性,可以用來提取資料的。主要有以下屬性:

  1. meta:從其他請求傳過來的

    meta

    屬性,可以用來保持多個請求之間的資料連接配接。
  2. encoding:傳回目前字元串編碼和解碼的格式。
  3. text:将傳回來的資料作為

    unicode

    字元串傳回。
  4. body:将傳回來的資料作為

    bytes

    字元串傳回。
  5. xpath:xapth選擇器。
  6. css:css選擇器。

發送POST請求:

有時候我們想要在請求資料的時候發送post請求,那麼這時候需要使用

Request

的子類

FormRequest

來實作。如果想要在爬蟲一開始的時候就發送

POST

請求,那麼需要在爬蟲類中重寫

start_requests(self)

方法,并且不再調用

start_urls

裡的url。