
人生苦短,我用 Python
前文傳送門(mén):
小白學(xué) Python 爬蟲(chóng)(1):開(kāi)篇
小白學(xué) Python 爬蟲(chóng)(2):前置準備(一)基本類(lèi)庫的安裝
小白學(xué) Python 爬蟲(chóng)(3):前置準備(二)Linux基礎入門(mén)
小白學(xué) Python 爬蟲(chóng)(4):前置準備(三)Docker基礎入門(mén)
小白學(xué) Python 爬蟲(chóng)(5):前置準備(四)數據庫基礎
小白學(xué) Python 爬蟲(chóng)(6):前置準備(五)爬蟲(chóng)框架的安裝
小白學(xué) Python 爬蟲(chóng)(7):HTTP 基礎
小白學(xué) Python 爬蟲(chóng)(8):網(wǎng)頁(yè)基礎
小白學(xué) Python 爬蟲(chóng)(9):爬蟲(chóng)基礎
小白學(xué) Python 爬蟲(chóng)(10):Session 和 Cookies
小白學(xué) Python 爬蟲(chóng)(11):urllib 基礎使用(一)
小白學(xué) Python 爬蟲(chóng)(12):urllib 基礎使用(二)
小白學(xué) Python 爬蟲(chóng)(13):urllib 基礎使用(三)
小白學(xué) Python 爬蟲(chóng)(14):urllib 基礎使用(四)
小白學(xué) Python 爬蟲(chóng)(15):urllib 基礎使用(五)
小白學(xué) Python 爬蟲(chóng)(16):urllib 實(shí)戰之爬取妹子圖
小白學(xué) Python 爬蟲(chóng)(17):Requests 基礎使用
小白學(xué) Python 爬蟲(chóng)(18):Requests 進(jìn)階操作
小白學(xué) Python 爬蟲(chóng)(19):Xpath 基操
小白學(xué) Python 爬蟲(chóng)(20):Xpath 進(jìn)階
小白學(xué) Python 爬蟲(chóng)(21):解析庫 Beautiful Soup(上)
小白學(xué) Python 爬蟲(chóng)(22):解析庫 Beautiful Soup(下)
小白學(xué) Python 爬蟲(chóng)(23):解析庫 pyquery 入門(mén)
小白學(xué) Python 爬蟲(chóng)(24):2019 豆瓣電影排行
小白學(xué) Python 爬蟲(chóng)(25):爬取股票信息
小白學(xué) Python 爬蟲(chóng)(26):為啥買(mǎi)不起上海二手房你都買(mǎi)不起
小白學(xué) Python 爬蟲(chóng)(27):自動(dòng)化測試框架 Selenium 從入門(mén)到放棄(上)
小白學(xué) Python 爬蟲(chóng)(28):自動(dòng)化測試框架 Selenium 從入門(mén)到放棄(下)
小白學(xué) Python 爬蟲(chóng)(29):Selenium 獲取某大型電商網(wǎng)站商品信息
小白學(xué) Python 爬蟲(chóng)(30):代理基礎
小白學(xué) Python 爬蟲(chóng)(31):自己構建一個(gè)簡(jiǎn)單的代理池
小白學(xué) Python 爬蟲(chóng)(32):異步請求庫 AIOHTTP 基礎入門(mén)
小白學(xué) Python 爬蟲(chóng)(33):爬蟲(chóng)框架 Scrapy 入門(mén)基礎(一)
在上一篇文章 小白學(xué) Python 爬蟲(chóng)(33):爬蟲(chóng)框架 Scrapy 入門(mén)基礎(一) 中,我們簡(jiǎn)單的使用了 Spider 抓取到了我們需要的信息,我們簡(jiǎn)單的將我所需要的信息通過(guò) print() 的方式打印了在了控制臺上。
在我們實(shí)際使用爬蟲(chóng)的過(guò)程中,我們更多的是需要將數據保存起來(lái),并不是直接輸出至控制臺,本篇文章接著(zhù)講我們如何將 Spider 抓取到的信息保存起來(lái)。
Item 的主要目的是從非結構化源(通常是網(wǎng)頁(yè))中提取結構化數據。
Scrapy Spider可以將提取的數據作為Python字典返回。Python字典雖然方便且熟悉,但缺乏結構:很容易在字段名稱(chēng)中輸入錯誤或返回不一致的數據,尤其是在具有許多蜘蛛的大型項目中。
為了定義常見(jiàn)的輸出數據格式, Scrapy 提供了 Item 該類(lèi)。 Item 對象是用于收集抓取數據的簡(jiǎn)單容器。它們提供了類(lèi)似于字典的 API ,具有方便的語(yǔ)法來(lái)聲明其可用字段。
接下來(lái),我們來(lái)創(chuàng )建一個(gè) Item 。
創(chuàng )建 Item 需要繼承 scrapy.Item 類(lèi),并且定義類(lèi)型為 scrapy.Field 的字段。
在前面一篇文章中,我們的目的想要獲取的字段有 text 、 author 、 tags 。
那么,我們定義的 Item 類(lèi)如下,這里直接修改 items.py 文件:
import scrapy class QuoteItem(scrapy.Item): text = scrapy.Field() author = scrapy.Field() tags = scrapy.Field()
接下來(lái)就是我們如何要在 first_scrapy 項目中使用這個(gè) Item 了,修改之前的 QuotesSpider 如下:
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接下來(lái),我們可以通過(guò)最簡(jiǎn)單的命令行將我們剛才獲取到的數據保存為 json 文件,命令如下:
scrapy crawl quotes -o quotes.json
執行后可以看到在當前目錄下生成了一個(gè)名為 quotes.json 的文件,具體內容如下:

輸出格式還支持很多種,例如 csv、xml、pickle、marshal 等,常見(jiàn)的輸出語(yǔ)句如下:
scrapy crawl quotes -o quotes.csv scrapy crawl quotes -o quotes.xml scrapy crawl quotes -o quotes.pickle scrapy crawl quotes -o quotes.marshal
直到這里,我們簡(jiǎn)單的將獲取到的數據導出成了 json 文件,這就結束了么?
當然沒(méi)有,前一篇文章我們只是簡(jiǎn)單的獲取了當前頁(yè)面的內容,如果我們想抓取后續頁(yè)面的內容怎么做呢?
當然,第一步我們需要先觀(guān)察后面一頁(yè)的鏈接:http://quotes.toscrape.com/page/2 。
接下來(lái),我們需要構造一個(gè)訪(fǎng)問(wèn)下一頁(yè)的請求,這時(shí)我們可以使用 scrapy.Request 。
這里我們使用 Request() 先簡(jiǎn)單的傳入兩個(gè)參數,實(shí)際上可以傳入的參數遠不止兩個(gè),這個(gè)我們后面再聊。
url:此請求的URL
callback:它是回調函數。當指定了該回調函數的請求完成之后,獲取到響應,引擎會(huì )將該響應作為參數傳遞給這個(gè)回調函數。
那么接下來(lái)我們要做的就是使用選擇器得到下一頁(yè)鏈接并生成請求,使用 scrapy.Request 訪(fǎng)問(wèn)此鏈接,進(jìn)行新一輪的數據抓取。
添加的代碼如下:
next = response.css('.pager .next a::attr("href")').extract_first()
url = response.urljoin(next)
yield scrapy.Request(url=url, callback=self.parse)現在,改動(dòng)后的 Spider 類(lèi)整體代碼如下:
# -*- coding: utf-8 -*-
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)再次使用命令執行這個(gè) Spider ,得到的結果如下(注意,如果前面生成過(guò) json 文件,記得刪除后再運行,否則會(huì )直接追加寫(xiě)):

可以看到,數據增加了許多,說(shuō)明我們抓取后續頁(yè)面的數據成功。
到這里就結束了么?怎么可能,我們這里只是簡(jiǎn)單的將數據保存在了 json 文件中,并不方便我們的取用,這里我們可以將數據保存在我們所需要的數據庫中。
當我們想將數據保存在數據庫中時(shí),可以使用 Item Pipeline ,Item Pipeline 為項目管道。
這個(gè)管道的典型用途有:
清洗 HTML 數據
驗證爬取數據,檢查爬取字段
查重并丟棄重復內容
將爬取結果儲存到數據庫
本示例選擇保存的數據為 MongoDB ,接下來(lái),我們會(huì )將前面查詢(xún)出來(lái)的數據保存在 MongoDB 中。
emmmmmmmmmm,如果要問(wèn)小編 MongoDB 怎么安裝的話(huà),簡(jiǎn)單來(lái)講,直接使用 Docker 進(jìn)行安裝,只需幾個(gè)簡(jiǎn)單的命令即可:
docker pull mongo (拉取鏡像 默認最新版本) docker images (查看鏡像) docker run -p 27017:27017 -td mongo (啟動(dòng)鏡像) docker ps (查看啟動(dòng)的鏡像)
如果不出意外,以上這幾句話(huà)執行一下就可以了。連接工具可以使用 Navicat 。
這里我們直接修改 pipelines.py 文件,之前使用命令自動(dòng)生成的內容可以全都刪掉,寫(xiě)入以下內容:
# -*- coding: utf-8 -*-
from scrapy.exceptions import DropItem
class TextPipeline(object):
def process_item(self, item, spider):
if item['text']:
return item
else:
return DropItem('Missing Text')這里我們實(shí)現了 process_item() 方法,其參數是 item 和 spider。
這里簡(jiǎn)單判斷了當前的 text 是否存在,如果不存在則直接拋出 DropItem 異常,如果存在則直接返回 item 。
接下來(lái),我們將處理后的 item 存入 MongoDB,定義另外一個(gè) Pipeline。同樣在 pipelines.py 中,我們實(shí)現另一個(gè)類(lèi) MongoPipeline,內容如下所示:
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()MongoPipeline 類(lèi)實(shí)現了 API 定義的另外幾個(gè)方法。
from_crawler,這是一個(gè)類(lèi)方法,用 @classmethod 標識,是一種依賴(lài)注入的方式,方法的參數就是 crawler,通過(guò) crawler 這個(gè)我們可以拿到全局配置的每個(gè)配置信息,在全局配置 settings.py 中我們可以定義 MONGO_URI 和 MONGO_DB 來(lái)指定 MongoDB 連接需要的地址和數據庫名稱(chēng),拿到配置信息之后返回類(lèi)對象即可。所以這個(gè)方法的定義主要是用來(lái)獲取 settings.py 中的配置的。
open_spider,當 Spider 被開(kāi)啟時(shí),這個(gè)方法被調用。在這里主要進(jìn)行了一些初始化操作。
close_spider,當 Spider 被關(guān)閉時(shí),這個(gè)方法會(huì )調用,在這里將數據庫連接關(guān)閉。
最主要的 process_item() 方法則執行了數據插入操作。
定義好 TextPipeline 和 MongoPipeline 這兩個(gè)類(lèi)后,我們需要在 settings.py 中使用它們。MongoDB 的連接信息還需要定義。
在 settings.py 中加入如下內容:
ITEM_PIPELINES = {
'first_scrapy.pipelines.TextPipeline': 300,
'first_scrapy.pipelines.MongoPipeline': 400,
}
MONGO_URI='localhost'
MONGO_DB='first_scrapy'再次執行爬取命令:
scrapy crawl quotes
執行結果如下:

可以看到,在 MongoDB 中創(chuàng )建了一個(gè) QuoteItem 的表,表中保存了我們剛才抓取到的數據。
本系列的所有代碼小編都會(huì )放在代碼管理倉庫 Github 和 Gitee 上,方便大家取用。
https://docs.scrapy.org/en/latest/topics/request-response.html
聯(lián)系客服