小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

爬蟲框架Scrapy(1)Scrapy基礎1

 印度阿三17 2021-03-23

一. Scrapy框架簡介

Scrapy是一個使用Python語言(基于Twisted框架)編寫的開源網(wǎng)絡爬蟲框架,目前由 Scrapinghub Ltd 維護。Scrapy 簡單易用、靈活易拓展、開發(fā)社區(qū)活躍,并且是跨平臺的。在 Linux、MaxOS 以及 Windows 平臺都可以使用。Scrapy 應用程序也使用 Python 進行開發(fā),目前可以支持 Python 2.7 以及 Python 3.4 版本。

Scrapy 功能非常強大,爬取效率高,相關擴展組件多,可配置和可擴展程度非常高,它幾乎可以應對所有反爬網(wǎng)站,是目前 Python 使用最廣泛的爬蟲框架。

1. Scrapy 框架介紹

首先我們看看 Scrapy 框架的架構:
在這里插入圖片描述

它可以分為如下的幾個部分:

模塊作用
Engine引擎,處理整個系統(tǒng)的數(shù)據(jù)流處理、觸發(fā)事務,是整個框架的核心
Item項目,它定義了爬取結果的數(shù)據(jù)結構,爬取的數(shù)據(jù)會被賦值成該 Item 對象
Scheduler調(diào)度器,接受引擎發(fā)過來的請求并將其加入列中,在引擎再次請求的時候?qū)⒄埱筇峁┙o引擎
Downloader下載器,下載網(wǎng)頁內(nèi)容,并將網(wǎng)頁內(nèi)容返回給蜘蛛
Spiders蜘蛛,其內(nèi)定義了爬取的邏輯和網(wǎng)頁解析規(guī)則,它主要負責解析響應并生成提取結果和新的請求
Item Pipeline項目管道,負責處理由蜘蛛從網(wǎng)頁中抽取的項目,它的主要任務是清洗、驗證和存儲數(shù)據(jù)
Downloader Middlewares下載器中間件,位于引擎和下載器之間的鉤子框架,主要處理引擎與下載器之間的請求及響應
Spide Middlewares蜘蛛中間件,位于引擎和蜘蛛之間的鉤子框架,主要處理蜘蛛輸入的響應和輸出的結果及新的請求

對于用戶來說,Spider 是最核心的組件,Scrapy 爬蟲開發(fā)是圍繞實現(xiàn) Spider 展開的。

2. 數(shù)據(jù)處理流程

Scrapy 中的數(shù)據(jù)流由引擎控制,數(shù)據(jù)流的過程如下:

  • Engine 首先打開一個網(wǎng)站,找到處理該網(wǎng)站的 Spider,并向該 Spider 請求第一個要爬取的 URL;

  • Engine 從 Spider 中獲取到第一個要爬取的 URL,并通過 Scheduler 以 Request 的形式調(diào)度;

  • Engine 向 Scheduler 請求下一個要爬取的 URL;

  • Scheduler 返回下一個要爬取的 URL 給 Engine,Engine 將 URL 通過 Downloader Middlewares 轉發(fā)給 Downloader Middlewares 下載;

  • 一旦頁面下載完畢,Downloader 生成該頁面的 Response,并將其通過 Downloader Middlewares 發(fā)送給 Engine;

  • Engine 從下載器中接收到 Response,并將其通過 Spider Middleware 發(fā)送給 Spider 處理;

  • Spider 處理 Response,并返回爬取到的 Item 及新的 Request 給 Engine;

  • Engine 將 Spider 返回的 Item給 Item Pipeline,將新 Request 給 Scheduler

  • 重復第 (2) 步到第 (8) 步,直到 Scheduler 中沒有更多的 Request,Engine 關閉該網(wǎng)站,爬取結束。

通過多個組件的相互協(xié)作、不同組件完成工作的不同、組件對異步處理的支持,Scrap 最大限度地利用了網(wǎng)絡帶寬,大大提高了數(shù)據(jù)爬取和處理的效率。

如果把框架中的組件比作人體的各個器官,Request 和 Response 對象便是血液,Item 則是代謝產(chǎn)物。

二. Scrapy 及其依賴庫的安裝

在任意操作系統(tǒng)下,都可以使用 pip 安裝 Scrapy,包括在虛擬機中。下面我們在遠程終端進入相應的 env 通過如下命令下載 Scrapy 框架:

(pyspider) pyvip@VIP:~$ pip3 install scrapy
Looking in indexes: https://pypi.douban.com/simple
...
Installing collected packages: scrapy
Successfully installed scrapy-2.4.1

為確認 Scrapy 已安裝成功,在 shell 中測試能否執(zhí)行 Scrapy 這條命令:

(pyspider) pyvip@VIP:~$ scrapy
Scrapy 2.4.1 - no active project

Usage:
  scrapy <command> [options] [args]

Available commands:
  bench         Run quick benchmark test
  commands      
  fetch         Fetch a URL using the Scrapy downloader
  genspider     Generate new spider using pre-defined templates
  runspider     Run a self-contained spider (without creating a project)
  settings      Get settings values
  shell         Interactive scraping console
  startproject  Create new project
  version       Print Scrapy version
  view          Open URL in browser, as seen by Scrapy

  [ more ]      More commands available when run from project directory

Use "scrapy <command> -h" to see more info about a command

通過以上檢測,說明 Scrapy 安裝成功了。如上所示,我們安裝的是當前最新版本2.4.1。

除了上述 Scrapy 庫,我們還需要安裝其依賴的其他幾個第三方庫,例如 'lxml'、'Twisted'、'pyOpenSSL' 等。這些第三方庫的安裝方式可以參考 Scrapy 的安裝方式。

除了上述的安裝方式,我們可以直接在 Pycharm 的設置里面下載。

三. Scrapy 項目開發(fā)流程

首先我們來看看爬蟲框架 Scrapy 的常用命令。

1. 常用命令

命令作用
scrapy startproject <project_name>在當前目錄下創(chuàng)建一個名為<project_name>的項目
scrapy settings [options]該命令將會輸出 Scrapy 默認設定;如果你在項目中運行這個命令將會輸出項目的設定值
scrapy runspider <spider_file.py>在未創(chuàng)建項目的情況下,運行一個編寫在 python 文件中的 spider
scrapy shell [url]以給定的URL(如果給出)或者空(沒有給出URL)啟動 Scrapy shell
scrapy fetch <url>使用 Scrapy 下載器 (downloader) 下載給定的URL,并將獲取到的內(nèi)容送到標準輸出
scrapy view <url>在你的默認瀏覽器中打開給定的 URL,并以Scrapy spider 獲取到的形式展現(xiàn)
scrapy version [-v]輸出Scrapy版本
scrapy –help查看幫助信息
scrapy benchscrapy 基準測試,用于檢測 scrapy 安裝環(huán)境是否完整
scrapy crawl <spider_name>使用你項目中的 spider 進行爬取,即啟動你的項目
crapy check [-l] <spider>運行 contract 檢查,檢查你項目中的錯誤之處
scrapy list列出當前項目中所有可用的 spider,每行輸出一個 spider
scrapy genspider [-t template] <name> <domain>在當前項目中創(chuàng)建 spider

2. 創(chuàng)建 Scrapy 項目

在安裝完成 Scrapy框架之后,我們開始創(chuàng)建第一個 Scrapy 項目,通過這個示例,我們了解一下 Scrapy 框架的開發(fā)流程。

創(chuàng)建 Scrapy 框架的過程與 Django 框架中創(chuàng)建項目文件有些相似。初步流程如下:

  • Step1:創(chuàng)建虛擬環(huán)境,并創(chuàng)建項目工程文件

  • Step2:安裝 Scrapy 框架

  • Step3:在本地文件夾中創(chuàng)建相應的工程文件,然后在 Pycharm 中連接遠程工程文件

然后從Ubuntu 或者 Pycharm 中進入到終端,然后在對應的虛擬環(huán)境下進入到爬蟲項目工程文件夾,然后運行下面的命令:

(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Quote_Spider$ scrapy startproject tutorial
New Scrapy project 'tutorial', using template directory '/home/pyvip/.virtualenvs/pyspider/lib/python3.6/site-packages/scrapy/templates/project', created in:
    /home/pyvip/project/Python_Spider/Spider_Project/Quote_Spider/tutorial

You can start your first spider with:
    cd tutorial
    scrapy genspider example example.com

創(chuàng)建好一個名為 first_scrapy 的項目后,可使用tree命令查看項目目錄下的文件,顯示如下:

tutorial
├── tutorial
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       └── __init__.py
└── scrapy.cfg

這里各個文件的功能描述如下:

  • scrapy.cfg:它是 Scrapy 項目的配置文件,其內(nèi)定義了項目的配置文件路徑、部署相關信息等內(nèi)容;

  • items.py:它定義 Item 數(shù)據(jù)結構,所有的 Item 的定義都可以放這里;

  • pipelines.py:它定義 Item Pipeline 的實現(xiàn),所有的 Item Pipeline 的實現(xiàn)都可以放這里;

  • settings.py:它定義項目的全局配置;

  • middlewares.py:它定義 Spider Middlewares 和 Downloader Middlewares 的實現(xiàn)

  • spiders:其內(nèi)包含一個個 Spider 的實現(xiàn),每個 Spider 都有一個文件。

3. 創(chuàng)建 Spider

Spider 是需要自己定義的類, Scrapy 用它來從網(wǎng)頁里抓取內(nèi)容,并解析抓取的結果。不過這個類必須繼承 Scrapy 提供的 Spider 類 scrapy.Spider,還要定義 Spider 的名稱和起始請求,以及怎樣處理爬取的結果的方法。spider 模塊我們可以使用命令行來創(chuàng)建,例如我們要生成 Quotes 這個 Spider,可以執(zhí)行如下命令:

(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Quote_Spider$ cd tutorial/tutorial
(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Quote_Spider/tutorial/tutorial$ ls
__init__.py  items.py  middlewares.py  pipelines.py  __pycache__  settings.py  spiders
(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Quote_Spider/tutorial/tutorial$ scrapy genspider quotes quotes.
Created spider 'quotes' using template 'basic' in module:
  tutorial.spiders.quotes

執(zhí)行完畢之后,spiders 文件夾中多了一個 quotes.py,它就是剛剛創(chuàng)建的 Spider,內(nèi)容如下所示:

import scrapy

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.']
    start_urls = ['http://quotes./']

    def parse(self, response):
        pass

這里有三個屬性——'name'、'allowed_domains'、' start_urls' ,還有一個方法 parse

  • name:它是每個項目唯一的名字,用來區(qū)分不同的 Spider;

  • allowed domains:它是允許爬取的域名,如果初始或后續(xù)的請求鏈接不是這個域名下的,則請求鏈接會被過濾掉;

  • start_urls:它包含了 Spider 在啟動時爬取的 url 列表,初始請求是由它來定義的,即 start_urls 屬性用來設置一個爬蟲的起始爬取點;

  • parse:它是 Spider 的一個方法。默認情況下,被調(diào)用時 start_urls 里面的鏈接構成的請求完成下載執(zhí)行后,返回的響應就會作為唯一的參數(shù)傳遞給這個函數(shù)。該方法負責解析返回的響應、提取數(shù)據(jù)或者進一步生成要處理的請求。

4. 創(chuàng)建 Item

Item 是保存爬取數(shù)據(jù)的容器,它的使用方法和字典類似。不過,相比字典 Item 多了額外的保護機制,可以避免拼寫錯誤或者定義字段錯誤。

創(chuàng)建 Item 需要繼承 scrapy.Item 類,并且定義類型為 scrapy.Field 的字段。觀察目標網(wǎng)站,我們可以獲取到的內(nèi)容有 'text'、'author'、'tags' 。定義 Item ,將 items.py 的內(nèi)容修改如下:

import scrapy

class FirstScrapyItem(scrapy.Item):
    text = scrapy . Field() 
    author = scrapy. Field() 
    tags = scrapy . Field()

5. 解析 Response

parse () 方法的參數(shù) resposne 是 start_urls 里面的鏈接爬取后的結果,所以在 parse() 方法中,我們可以直接對 response 變量包含的內(nèi)容進行解析,比如瀏覽請求結果的網(wǎng)頁源代碼,或者進一步分析源代碼內(nèi)容,或者找出結果中的鏈接而得到下一個請求。

在這里,我們使用 CSS 選擇器進行選擇,parse() 方法的改寫內(nèi)容如下:

def parse(self, response):
    quotes = response.css('.quote')
    for quote in quotes:
        text = quote.css('.text::text').extract_first()
        author = quote.css('.author::text').extract_first()
        tags = quote.css('.tags .tag::text').extract()

6. 使用 Item

Item 可以理解為字典,不過在聲明的時候需要實例化,然后依次用剛才解析的結果賦值 Item 的每一個字段, 最后將 Item 返回即可。QuotesSpider 的改寫如下所示:

import scrapy
from ..items import TutorialItem

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.']
    start_urls = ['http://quotes./']

    def parse(self, response):
        quotes = response.css('.quote')
        for quote in quotes:
            item = TutorialItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item

如此一來,首頁的所有內(nèi)容被解析出來,并被賦值成了一個個 QuoteItem

7. 后續(xù) Request

上面的操作實現(xiàn)了從初始頁面抓取內(nèi)容。那么,下一頁的內(nèi)容該如何抓取?這就需要我們從當前頁面中找到信息來生成下一個請求,然后在下一個請求的頁面里找到信息再構造再下一個請求。這樣循環(huán)往復迭代,從而實現(xiàn)整站的爬取。

由于 parse() 就是解析 'text'、'author'、'tags' 的方法,而下一頁的結構和剛才已經(jīng)解析的頁面結構是一樣的,所以我們可以再次使用 parse() 方法來做頁面解析。接下來我們要做的就是利用選擇器得到下一頁鏈接并生成請求,在 parse() 方法后追加如下的代碼:

import scrapy
from ..items import TutorialItem

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.']
    start_urls = ['http://quotes./']

    def parse(self, response):
        quotes = response.css('.quote')
        for quote in quotes:
            item = TutorialItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item

        next = response.css('.pager .next a::attr(href)').extract_first()
        url = response.urljoin(next)
        yield scrapy.Request(url=url, callback=self.parse)

在上述代碼中,有四個關鍵步驟是爬蟲的關鍵:

  • 01 繼承scrapy.Spider;

  • 02 為Spider取名;

  • 03 設定起始爬取點;

  • 04 實現(xiàn)頁面解析函數(shù)。

(1)繼承 Scrapy.spider

Scrapy 框架提供了一個 Spider 基類,我們編寫的 Spider 需要繼承它:

import scrapy

class QuotesSpider(scrapy.Spider):

這個 Spider 基類實現(xiàn)了以下內(nèi)容:

  • 供 Scrapy 引擎調(diào)用的接口,例如用來創(chuàng)建 Spider 實例的類方法 from_crawler;

  • 供用戶使用的實用工具函數(shù),例如可以調(diào)用 log 方法將調(diào)試信息輸出到日志;

  • 供用戶訪問的屬性,例如可以通過 settings 屬性訪問配置文件中的配置。

(2)為 Spider 命名

在一個 Scrapy 項目中可以實現(xiàn)多個 Spider,每個 Spider 需要有一個能夠區(qū)分彼此的唯一標識,Spider 的類屬性 name 便是這個唯一標識。例如,上述示例項目中的 Spider 名稱是 quotes。執(zhí)行 scrapy crawl XXX 命令時就用到了這個標識,告訴 Scrapy 使用哪個 Spider 進行爬取。

(3)設定起始爬取點

Spider 必然要從某個或某些頁面開始爬取,我們稱這些頁面為起始爬取點,可以通過類屬性 start_urls 來設定起始爬取點。start_urls 通常被實現(xiàn)成一個列表,其中放入所有起始爬取點的 url??吹竭@里,大家可能會產(chǎn)生疑問:我們僅定義了url列表,是誰暗中構造并提交了相應的Request對象呢?通過閱讀 Spider 基類的源碼可以找到答案,相關代碼如下:

class Spider(object_ref):
...
def start_requests(self):
for url in self.start_urls:
yield self.make_requests_from_url(url)

def make_requests_from_url(self, url):
    return Request(url, dont_filter=True) 
    
    def parse(self, response): 
    raise NotImplementedError 
    ...

從代碼中可以看出,Spider 基類的 start_requests 方法幫助我們構造并提交了 Request 對象,對其中的原理做如下解釋:

  • 實際上,對于起始爬取點的下載請求是由 Scrapy 引擎調(diào)用 Spider 對象的 start_requests 方法提交的,由于 BooksSpider 類沒有實現(xiàn)start_requests 方法,因此引擎會調(diào)用 Spider 基類的 start_requests 方法;

  • 在start_requests 方法中,self.start_urls 便是我們定義的起始爬取點列表(通過實例訪問類屬性),對其進行迭代,用迭代出的每個 url 作為參數(shù)調(diào)用 make_requests_from_url 方法;

  • 在 make_requests_from_url 方法中,我們找到了真正構造 Reqeust 對象的代碼,僅使用 url 和 dont_filter 參數(shù)構造 Request 對象;

  • 由于構造 Request 對象時并沒有傳遞 callback 參數(shù)來指定頁面解析函數(shù),因此默認將 parse 方法作為頁面解析函數(shù)。此時 BooksSpider 必須實現(xiàn) parse 方法,否則就會調(diào)用 Spider 基類的 parse 方法,從而拋出 NotImplementedError 異常(可以看作基類定義了一個抽象接口);

  • 起始爬取點可能有多個,start_requests 方法需要返回一個可迭代對象(列表、生成器等),其中每一個元素是一個 Request 對象。這里,start_requests 方法被實現(xiàn)成一個生成器函數(shù)(生成器對象是可迭代的),每次由 yield 語句返回一個 Request 對象。

由于起始爬取點的下載請求是由引擎調(diào)用 Spider 對象的 start_requests 方法產(chǎn)生的,因此我們也可以在 BooksSpider 中實現(xiàn) start_requests 方法(覆蓋基類 Spider 的 start_requests 方法),直接構造并提交起始爬取點的 Request 對象。在某些場景下使用這種方式更加靈活,例如有時想為 Request 添加特定的 HTTP 請求頭部,或想為 Request 指定特定的頁面解析函數(shù)。

以下是通過實現(xiàn) start_requests 方法定義起始爬取點的示例代碼(改寫QuotesSpider):

import scrapy
from ..items import TutorialItem

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.']
    def start_requests(self):
        yield scrapy.Request('http://quotes./',
                             callback=self.parse_quote,
                             headers={'User-Agent': 'Mozilla/5.0'},
                             dont_filter=True)

    def parse_quote(self, response):
        quotes = response.css('.quote')
        for quote in quotes:
            item = TutorialItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item

        next = response.css('.pager .next a::attr(href)').extract_first()
        url = response.urljoin(next)
        yield scrapy.Request(url=url, callback=self.parse)

到此,我們介紹完了為爬蟲設定起始爬取點的兩種方式: 一、定義 start_urls 屬性;二、實現(xiàn) start_requests 方法。

(4)實現(xiàn)頁面解析函數(shù)

頁面解析函數(shù)也就是構造 Request 對象時通過 callback 參數(shù)指定的回調(diào)函數(shù)(或默認的 parse 方法)。頁面解析函數(shù)是實現(xiàn) Spider 中最核心的部分,它需要完成以下兩項工作:

  • 使用選擇器提取頁面中的數(shù)據(jù),將數(shù)據(jù)封裝后(Item 或字典)提交給 Scrapy 引擎;

  • 使用選擇器或 LinkExtractor 提取頁面中的鏈接,用其構造 新的 Request 對象并提交給 Scrapy 引擎(下載鏈接頁面)。

一個頁面中可能包含多項數(shù)據(jù)以及多個鏈接,因此頁面解析函數(shù)被要求返回一個可迭代對象(通常被實現(xiàn)成一個生成器函數(shù)),每次迭代返回一項數(shù)據(jù)(Item或字典)或一個 Request 對象。

8. 運行

接下來,進入目錄,運行如下命令:

scrapy crawl quotes

Scrapy 運行結果如下所示:

(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Quote_Spider$ cd tutorial
(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Quote_Spider/tutorial$ ls
scrapy.cfg  tutorial
(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Quote_Spider/tutorial$ scrapy crawl quotes
2021-03-15 11:51:18 [scrapy.utils.log] INFO: Scrapy 2.4.1 started (bot: tutorial)
2021-03-15 11:51:18 [scrapy.utils.log] INFO: Versions: lxml 4.5.2.0, libxml2 2.9.10, cssselect 1.1.0, parsel 1.6.0, w3lib 1.22.0, Twisted 21.2.0, Python 3.6.9 (default, Jul 17 2020, 12:50:27) - [GCC 8.4.0], pyOpenSSL 20.0.1 (OpenSSL 1.1.1j  16 Feb 2021), cryptography 3.4.6, Platform Linux-4.15.0-136-generic-x86_64-with-Ubuntu-18.04-bionic
2021-03-15 11:51:18 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.epollreactor.EPollReactor
2021-03-15 11:51:18 [scrapy.crawler] INFO: Overridden settings:
{'BOT_NAME': 'tutorial',
 'NEWSPIDER_MODULE': 'tutorial.spiders',
 'ROBOTSTXT_OBEY': True,
 'SPIDER_MODULES': ['tutorial.spiders']}
2021-03-15 11:51:18 [scrapy.extensions.telnet] INFO: Telnet Password: fdef5e4b01ff9fce
2021-03-15 11:51:18 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.memusage.MemoryUsage',
 'scrapy.extensions.logstats.LogStats']
2021-03-15 11:51:18 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2021-03-15 11:51:29 [scrapy.dupefilters] DEBUG: Filtered duplicate request: <GET http://quotes./page/10/> - no more duplicates will be shown (see DUPEFILTER_DEBUG to show all duplicates)
2021-03-15 11:51:29 [scrapy.core.engine] INFO: Closing spider (finished)
2021-03-15 11:51:29 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 2881,
 'downloader/request_count': 11,
 'downloader/request_method_count/GET': 11,
 'downloader/response_bytes': 23388,
 'downloader/response_count': 11,
 'downloader/response_status_count/200': 10,
 'downloader/response_status_count/404': 1,
 'dupefilter/filtered': 1,
 'elapsed_time_seconds': 10.21772,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2021, 3, 15, 3, 51, 29, 96046),
 'item_scraped_count': 100,
 'log_count/DEBUG': 112,
 'log_count/INFO': 10,
 'memusage/max': 56266752,
 'memusage/startup': 56266752,
 'request_depth_max': 10,
 'response_received_count': 11,
 'robotstxt/request_count': 1,
 'robotstxt/response_count': 1,
 'robotstxt/response_status_count/404': 1,
 'scheduler/dequeued': 10,
 'scheduler/dequeued/memory': 10,
 'scheduler/enqueued': 10,
 'scheduler/enqueued/memory': 10,
 'start_time': datetime.datetime(2021, 3, 15, 3, 51, 18, 878326)}
2021-03-15 11:51:29 [scrapy.core.engine] INFO: Spider closed (finished)

這里只是部分運行結果 ,中間一些抓取結果已省略。

首先,Scrapy 輸出了當前的版本號以及正在啟動的項目名稱。接著輸出了當前 settings.py 中一些重寫后的配置。然后輸出了當前所應用的 Middlewares 和 Pipelines 。Middlewares 默認是啟用的 ,可以在 settings.py 中修改。Pipelines 默認是空 ,同樣也可以在 settings py 中配置。

接下來就是輸出各個頁面的抓取結果了,可以看到爬蟲一邊解析,一邊翻頁,直至將所有內(nèi)容抓取完畢,然后終止。

最后, Scrapy 輸出了整個抓取過程的統(tǒng)計信息,如請求的字節(jié)數(shù)、請求次數(shù)、響應次數(shù)、完成原因等。

9. 保存到文件

運行完 Scrapy 后,我們只在控制臺看到了輸出結果,那如何保存輸出結果呢?要完成這個任務其實不需要任何額外的代碼,Scrapy 提供的 Feed Exports 可以輕松將抓取結果輸出。例如,我們想將上面的結果保存成 JSON 文件,可以執(zhí)行如下命令:

scrapy crawl quotes -o quotes.json

命令運行后,項目內(nèi)多了一個 quotes.json 文件,文件包含了剛才抓取的所有內(nèi)容,內(nèi)容是 JSON 格式。如下圖所示:
在這里插入圖片描述

另外我們還可以每一個 Item 輸出一行 JSON ,輸出后綴為 jl,為 jsonline 的縮寫,命令如下所示:

scrapy crawl quotes -o quotes.jl
# 或者
scrapy crawl quotes -o quotes.jsonlines

輸出格式還支持很多種,例如:'csv'、'xml'、'pickle'、'marshal' 等,還支持 'ftp'、's3' 等遠程輸出,另外還可以通過自定義 ItemExporter來實現(xiàn)其他的輸出。

通過 Scrapy 提供的 Feed Exports,我們可以輕松地輸出抓取結果到文件。對于一些小型項目來說,這應該足夠了。如果想要更復雜的輸出,如輸出到數(shù)據(jù)庫等,我們可以使用 Item Pileline 來完成。

四. 實例——爬取書籍信息

1. 創(chuàng)建項目

在本地和遠程服務器的相應文件夾中創(chuàng)建爬蟲項目的文件夾,然后在 Pycharm 中打開本地文件夾,連接遠程文件。
在這里插入圖片描述

從Ubuntu 或者 Pycharm 中進入終端,然后在對應的虛擬環(huán)境下進入到爬蟲項目工程文件夾,再運行下面的命令:

(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Scrapy_Book$ scrapy startproject toscrapy
New Scrapy project 'toscrapy', using template directory '/home/pyvip/.virtualenvs/pyspider/lib/python3.6/site-packages/scrapy/templates/project', created in:
    /home/pyvip/project/Python_Spider/Spider_Project/Scrapy_Book/toscrapy

You can start your first spider with:
    cd toscrapy
    scrapy genspider example example.com

2. 創(chuàng)建爬蟲

從終端進入項目工程文件,運行如下命令:

(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Scrapy_Book/toscrapy$ cd toscrapy
(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Scrapy_Book/toscrapy/toscrapy$ ls
__init__.py  items.py  middlewares.py  pipelines.py  settings.py  spiders
(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Scrapy_Book/toscrapy/toscrapy$ scrapy genspider books books.
Created spider 'books' using template 'basic' in module:
  toscrapy.spiders.books

3. 解析 Response

books.py 文件中修改 parse 函數(shù),修改內(nèi)容如下:

import scrapy

class BooksSpider(scrapy.Spider):
    name = 'books'
    allowed_domains = ['books.']
    start_urls = ['http://books./']

    def parse(self, response):
        # 提取數(shù)據(jù)
        for book in response.css('article.product_pod'):
            name = book.xpath('./h3/a/@title').extract_first()
            price = book.css('p.price_color::text').extract_first()
            yield {'name': name,
                'price': price,
            }

        # 提取鏈接
        next_url = response.css('ul.pager li.next a::attr(href)').extract_first()
        if next_url:
            next_url = response.urljoin(next_url)
            yield scrapy.Request(next_url, callback=self.parse)

4. 運行爬蟲并保存數(shù)據(jù)

從終端進入項目工程文件,運行如下命令:

(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Scrapy_Book/toscrapy/toscrapy$ scrapy crawl books
2021-03-15 18:09:09 [scrapy.utils.log] INFO: Scrapy 2.4.1 started (bot: toscrapy)
2021-03-15 18:09:09 [scrapy.utils.log] INFO: Versions: lxml 4.5.2.0, libxml2 2.9.10, cssselect 1.1.0, parsel 1.6.0, w3lib 1.22.0, Twisted 21.2.0, Python 3.6.9 (default, Jul 17 2020, 12:50:27) - [GCC 8.4.0], pyOpenSSL 20.0.1 (OpenSSL 1.1.1j  16 Feb 2021), cryptography 3.4.6, Platform Linux-4.15.0-136-generic-x86_64-with-Ubuntu-18.04-bionic
2021-03-15 18:09:09 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.epollreactor.EPollReactor
2021-03-15 18:09:09 [scrapy.crawler] INFO: Overridden settings:
{'BOT_NAME': 'toscrapy',
 'NEWSPIDER_MODULE': 'toscrapy.spiders',
 'ROBOTSTXT_OBEY': True,
 'SPIDER_MODULES': ['toscrapy.spiders']}
2021-03-15 18:09:09 [scrapy.extensions.telnet] INFO: Telnet Password: ee928a9f1bd414d4
2021-03-15 18:09:09 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.memusage.MemoryUsage',
 'scrapy.extensions.logstats.LogStats']
2021-03-15 18:09:09 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
......
......
2021-03-15 18:11:54 [scrapy.core.scraper] DEBUG: Scraped from <200 http://books./catalogue/page-50.html>
{'name': "A Spy's Devotion (The Regency Spies of London #1)", 'price': '£16.97'}
2021-03-15 18:11:54 [scrapy.core.scraper] DEBUG: Scraped from <200 http://books./catalogue/page-50.html>
{'name': "1st to Die (Women's Murder Club #1)", 'price': '£53.98'}
2021-03-15 18:11:54 [scrapy.core.scraper] DEBUG: Scraped from <200 http://books./catalogue/page-50.html>
{'name': '1,000 Places to See Before You Die', 'price': '£26.08'}
2021-03-15 18:11:54 [scrapy.core.engine] INFO: Closing spider (finished)
2021-03-15 18:11:54 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/exception_count': 3,
 'downloader/exception_type_count/twisted.internet.error.DNSLookupError': 3,
 'downloader/request_bytes': 15515,
 'downloader/request_count': 53,
 'downloader/request_method_count/GET': 53,
 'downloader/response_bytes': 291473,
 'downloader/response_count': 50,
 'downloader/response_status_count/200': 50,
 'elapsed_time_seconds': 164.723678,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2021, 3, 15, 10, 11, 54, 716833),
 'item_scraped_count': 1000,
 'log_count/DEBUG': 1052,
 'log_count/ERROR': 2,
 'log_count/INFO': 12,
 'memusage/max': 62898176,
 'memusage/startup': 56143872,
 'request_depth_max': 49,
 'response_received_count': 50,
 'retry/count': 2,
 'retry/max_reached': 1,
 'retry/reason_count/twisted.internet.error.DNSLookupError': 2,
 "robotstxt/exception_count/<class 'twisted.internet.error.DNSLookupError'>": 1,
 'robotstxt/request_count': 1,
 'scheduler/dequeued': 50,
 'scheduler/dequeued/memory': 50,
 'scheduler/enqueued': 50,
 'scheduler/enqueued/memory': 50,
 'start_time': datetime.datetime(2021, 3, 15, 10, 9, 9, 993155)}
2021-03-15 18:11:54 [scrapy.core.engine] INFO: Spider closed (finished)

如果要將上述爬取的數(shù)據(jù)保存到文件,則需要運行如下命令:

scrapy crawl books -o books.csv

然后在項目工程文件夾下生成文件 books.csv ,在終端查看該文件內(nèi)容如下:

(pyspider) pyvip@VIP:~/project/Python_Spider/Spider_Project/Scrapy_Book/toscrapy/toscrapy$ sed -n '2,$p' books.csv | cat -n
 1 A Light in the Attic,£51.77 
 2 Tipping the Velvet,£53.74 
 3 Soumission,£50.10 
 4 Sharp Objects,£47.82 
 5 Sapiens: A Brief History of Humankind,£54.23 
 6 The Requiem Red,£22.65 
     7  The Dirty Little Secrets of Getting Your Dream Job,£33.34
     8  "The Coming Woman: A Novel Based on the Life of the Infamous Feminist, Victoria Woodhull",£17.93
     9  The Boys in the Boat: Nine Americans and Their Epic Quest for Gold at the 1936 Berlin Olympics,£22.60
    10  The Black Maria,£52.15
......

上述文章內(nèi)容如有錯誤,歡迎各位朋友在評論區(qū)留言!

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多