小白學 Python 爬蟲(34):爬蟲框架 Scrapy 入門基礎(二)

小白學 Python 爬蟲(34):爬蟲框架 Scrapy 入門基礎(二)

人生苦短,我用 Python


如果我的文章對您有幫助,請關注支持下作者的公眾號:極客挖掘機,您的關注,是對小編堅持原創的最大鼓勵:)

前文傳送門:

小白學 Python 爬蟲(1):開篇

小白學 Python 爬蟲(2):前置準備(一)基本類庫的安裝

小白學 Python 爬蟲(3):前置準備(二)Linux基礎入門

小白學 Python 爬蟲(4):前置準備(三)Docker基礎入門

小白學 Python 爬蟲(5):前置準備(四)數據庫基礎

小白學 Python 爬蟲(6):前置準備(五)爬蟲框架的安裝

小白學 Python 爬蟲(7):HTTP 基礎

小白學 Python 爬蟲(8):網頁基礎

小白學 Python 爬蟲(9):爬蟲基礎

小白學 Python 爬蟲(10):Session 和 Cookies

小白學 Python 爬蟲(11):urllib 基礎使用(一)

小白學 Python 爬蟲(12):urllib 基礎使用(二)

小白學 Python 爬蟲(13):urllib 基礎使用(三)

小白學 Python 爬蟲(14):urllib 基礎使用(四)

小白學 Python 爬蟲(15):urllib 基礎使用(五)

小白學 Python 爬蟲(16):urllib 實戰之爬取妹子圖

小白學 Python 爬蟲(17):Requests 基礎使用

小白學 Python 爬蟲(18):Requests 進階操作

小白學 Python 爬蟲(19):Xpath 基操

小白學 Python 爬蟲(20):Xpath 進階

小白學 Python 爬蟲(21):解析庫 Beautiful Soup(上)

小白學 Python 爬蟲(22):解析庫 Beautiful Soup(下)

小白學 Python 爬蟲(23):解析庫 pyquery 入門

小白學 Python 爬蟲(24):2019 豆瓣電影排行

小白學 Python 爬蟲(25):爬取股票信息

小白學 Python 爬蟲(26):為啥買不起上海二手房你都買不起

小白學 Python 爬蟲(27):自動化測試框架 Selenium 從入門到放棄(上)

小白學 Python 爬蟲(28):自動化測試框架 Selenium 從入門到放棄(下)

小白學 Python 爬蟲(29):Selenium 獲取某大型電商網站商品信息

小白學 Python 爬蟲(30):代理基礎

小白學 Python 爬蟲(31):自己構建一個簡單的代理池

小白學 Python 爬蟲(32):異步請求庫 AIOHTTP 基礎入門

小白學 Python 爬蟲(33):爬蟲框架 Scrapy 入門基礎(一)

引言

在上一篇文章 小白學 Python 爬蟲(33):爬蟲框架 Scrapy 入門基礎(一) 中,我們簡單的使用了 Spider 抓取到了我們需要的信息,我們簡單的將我所需要的信息通過 print() 的方式打印了在了控制檯上。

在我們實際使用爬蟲的過程中,我們更多的是需要將數據保存起來,並不是直接輸出至控制檯,本篇文章接著講我們如何將 Spider 抓取到的信息保存起來。

Item

Item 的主要目的是從非結構化源(通常是網頁)中提取結構化數據。

Scrapy Spider可以將提取的數據作為Python字典返回。Python字典雖然方便且熟悉,但缺乏結構:很容易在字段名稱中輸入錯誤或返回不一致的數據,尤其是在具有許多蜘蛛的大型項目中。

為了定義常見的輸出數據格式, Scrapy 提供了 Item 該類。 Item 對象是用於收集抓取數據的簡單容器。它們提供了類似於字典的 API ,具有方便的語法來聲明其可用字段。

接下來,我們來創建一個 Item 。

創建 Item 需要繼承 scrapy.Item 類,並且定義類型為 scrapy.Field 的字段。

在前面一篇文章中,我們的目的想要獲取的字段有 text 、 author 、 tags 。

那麼,我們定義的 Item 類如下,這裡直接修改 items.py 文件:

<code>

import

scrapy

class

QuoteItem(scrapy.Item):

text

=

scrapy.Field()

author

=

scrapy.Field()

tags

=

scrapy.Field()

/<code>

接下來就是我們如何要在 first_scrapy 項目中使用這個 Item 了,修改之前的 QuotesSpider 如下:

<code>

import

scrapy

from

first_scrapy.items

import

QuoteItem

class

QuotesSpider

(scrapy.Spider)

:

name =

'quotes'

allowed_domains = [

'quotes.toscrape.com'

] start_urls = [

'http://quotes.toscrape.com/'

]

def

parse

(self, response)

:

quotes = response.css(

'.quote'

)

for

quote

in

quotes: item = QuoteItem() 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 /<code>

接下來,我們可以通過最簡單的命令行將我們剛才獲取到的數據保存為 json 文件,命令如下:

<code>scrapy crawl 

quotes

-o

quotes

.json

/<code>

執行後可以看到在當前目錄下生成了一個名為 quotes.json 的文件,具體內容如下:

小白學 Python 爬蟲(34):爬蟲框架 Scrapy 入門基礎(二)

輸出格式還支持很多種,例如 csv、xml、pickle、marshal 等,常見的輸出語句如下:

<code>scrapy crawl 

quotes

-o

quotes

.csv

scrapy crawl

quotes

-o

quotes

.xml

scrapy crawl

quotes

-o

quotes

.pickle

scrapy crawl

quotes

-o

quotes

.marshal

/<code>

直到這裡,我們簡單的將獲取到的數據導出成了 json 文件,這就結束了麼?

當然沒有,前一篇文章我們只是簡單的獲取了當前頁面的內容,如果我們想抓取後續頁面的內容怎麼做呢?

當然,第一步我們需要先觀察後面一頁的鏈接:http://quotes.toscrape.com/page/2 。

接下來,我們需要構造一個訪問下一頁的請求,這時我們可以使用 scrapy.Request 。

這裡我們使用 Request() 先簡單的傳入兩個參數,實際上可以傳入的參數遠不止兩個,這個我們後面再聊。

  • url:此請求的URL
  • callback:它是回調函數。當指定了該回調函數的請求完成之後,獲取到響應,引擎會將該響應作為參數傳遞給這個回調函數。

那麼接下來我們要做的就是使用選擇器得到下一頁鏈接並生成請求,使用 scrapy.Request 訪問此鏈接,進行新一輪的數據抓取。

添加的代碼如下:

<code>

next

= response.css(

'.pager .next a::attr("href")'

).extract_first() url = response.urljoin(

next

)

yield

scrapy.Request(url=url, callback=

self

.parse) /<code>

現在,改動後的 Spider 類整體代碼如下:

<code> 

import

scrapy

from

first_scrapy.items

import

QuoteItem

class

QuotesSpider

(scrapy.Spider)

:

name =

'quotes'

allowed_domains = [

'quotes.toscrape.com'

] start_urls = [

'http://quotes.toscrape.com/'

]

def

parse

(self, response)

:

quotes = response.css(

'.quote'

)

for

quote

in

quotes: item = QuoteItem() 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) /<code>

再次使用命令執行這個 Spider ,得到的結果如下(注意,如果前面生成過 json 文件,記得刪除後再運行,否則會直接追加寫):

小白學 Python 爬蟲(34):爬蟲框架 Scrapy 入門基礎(二)

可以看到,數據增加了許多,說明我們抓取後續頁面的數據成功。

到這裡就結束了麼?怎麼可能,我們這裡只是簡單的將數據保存在了 json 文件中,並不方便我們的取用,這裡我們可以將數據保存在我們所需要的數據庫中。

Item Pipeline

當我們想將數據保存在數據庫中時,可以使用 Item Pipeline ,Item Pipeline 為項目管道。

這個管道的典型用途有:

  • 清洗 HTML 數據
  • 驗證爬取數據,檢查爬取字段
  • 查重並丟棄重複內容
  • 將爬取結果儲存到數據庫

本示例選擇保存的數據為 MongoDB ,接下來,我們會將前面查詢出來的數據保存在 MongoDB 中。

emmmmmmmmmm,如果要問小編 MongoDB 怎麼安裝的話,簡單來講,直接使用 Docker 進行安裝,只需幾個簡單的命令即可:

<code>

docker

pull mongo (拉取鏡像 默認最新版本)

docker

images (查看鏡像)

docker

run -p 27017:27017 -td mongo (啟動鏡像)

docker

ps (查看啟動的鏡像)

/<code>

如果不出意外,以上這幾句話執行一下就可以了。連接工具可以使用 Navicat 。

這裡我們直接修改 pipelines.py 文件,之前使用命令自動生成的內容可以全都刪掉,寫入以下內容:

<code> 

from

scrapy.exceptions

import

DropItem

class

TextPipeline

(object)

:

def

process_item

(self, item, spider)

:

if

item[

'text'

]:

return

item

else

:

return

DropItem(

'Missing Text'

) /<code>

這裡我們實現了 process_item() 方法,其參數是 item 和 spider。

這裡簡單判斷了當前的 text 是否存在,如果不存在則直接拋出 DropItem 異常,如果存在則直接返回 item 。

接下來,我們將處理後的 item 存入 MongoDB,定義另外一個 Pipeline。同樣在 pipelines.py 中,我們實現另一個類 MongoPipeline,內容如下所示:

<code>import pymongo

class

MongoPipeline

(

object

):

def

__init__

(

self

, mongo_uri, mongo_db)

:

self

.mongo_uri = mongo_uri

self

.mongo_db = mongo_db @classmethod

def

from_crawler

(cls, crawler)

:

return

cls(mongo_uri=crawler.settings.get(

'MONGO_URI'

), mongo_db=crawler.settings.get(

'MONGO_DB'

) )

def

open_spider

(

self

, spider)

:

self

.client = pymongo.MongoClient(

self

.mongo_uri)

self

.db =

self

.client[

self

.mongo_db]

def

process_item

(

self

, item, spider)

: name = item.__class_

_

.__name_

_

self

.db[name].insert(dict(item))

return

item

def

close_spider

(

self

, spider)

:

self

.client.close() /<code>

MongoPipeline 類實現了 API 定義的另外幾個方法。

  • from_crawler,這是一個類方法,用 @classmethod 標識,是一種依賴注入的方式,方法的參數就是 crawler,通過 crawler 這個我們可以拿到全局配置的每個配置信息,在全局配置 settings.py 中我們可以定義 MONGO_URI 和 MONGO_DB 來指定 MongoDB 連接需要的地址和數據庫名稱,拿到配置信息之後返回類對象即可。所以這個方法的定義主要是用來獲取 settings.py 中的配置的。
  • open_spider,當 Spider 被開啟時,這個方法被調用。在這裡主要進行了一些初始化操作。
  • close_spider,當 Spider 被關閉時,這個方法會調用,在這裡將數據庫連接關閉。 最主要的 process_item() 方法則執行了數據插入操作。

定義好 TextPipeline 和 MongoPipeline 這兩個類後,我們需要在 settings.py 中使用它們。MongoDB 的連接信息還需要定義。

在 settings.py 中加入如下內容:

<code>ITEM_PIPELINES = {
    

'first_scrapy.pipelines.TextPipeline'

: 300,

'first_scrapy.pipelines.MongoPipeline'

: 400, } MONGO_URI=

'localhost'

MONGO_DB=

'first_scrapy'

/<code>

再次執行爬取命令:

<code>

scrapy

crawl quotes /<code>

執行結果如下:

小白學 Python 爬蟲(34):爬蟲框架 Scrapy 入門基礎(二)

可以看到,在 MongoDB 中創建了一個 QuoteItem 的表,表中保存了我們剛才抓取到的數據。

示例代碼

本系列的所有代碼小編都會放在代碼管理倉庫 Github 和 Gitee 上,方便大家取用。

示例代碼-Github

示例代碼-Gitee

參考

https://docs.scrapy.org/en/latest/topics/request-response.html

https://docs.scrapy.org/en/latest/topics/items.html

https://cuiqingcai.com/8337.html


分享到:


相關文章: