DC-01:爬蟲框架scrapy入門

本主題主要是scrapy入門,包含內容如下:
??1. Scrapy框架環境搭建;
??2. 理解scrapy框架結構;
??3. 理解并能處理簡單的數據流;
??
如果想關注爬蟲的高級技術與應用場景,請關注后繼內容與馬哥教育。這個系列包括數據采集,數據分析與數據可視化。


一、Scrapy安裝

??Scrapy的安裝是比較簡單的,直接使用pip可以完成最新版本的安裝。
??
??目前最新版本是:1.6。

1.官網地址

??Scrapy的官方地址是:https://scrapy.org !

scrapy官網截圖

2. 安裝

??安裝指令


pip install scrapy

??安裝過程
安裝過程截圖

3. 測試安裝

??只需要啟動python交互式編程終端,看看能否import模塊scrapy即可;
安裝測試截圖

4. scrapy幫助

??在交互式編程終端,使用import引入scrapy模塊,并使用help(scrapy)獲取scrapy框架API整體模塊結構(其他更加詳細的幫助可以使用help與dir獲?。?div id="rvzptob" class="image-package">
scrapy幫助使用截圖

5. 教程與參考資料

??最好的教程我個人認為還是官方的教程+API幫助。
官方教程與API截圖

二、Scrapy組件結構與工作流程

1. 核心組件介紹

1.1. 組件01:引擎(Scrapy Engine)

??Scrapy Engine引擎作用有兩個:
????1. 控制Scrapy框架中所有組件之間的數據流;
????2. 并在某些爬取動作發生的時候觸發數據處理事件。

1.2. 組件02:調度器(Scheduler)

??調度器(Scheduler)接收來自引擎的請求,并將它們排隊,以便在引擎請求時向引擎提供這些請求。

1.3. 組件03:下載器(Downloader)

??下載者(Downloader)負責下載網頁并將其發送給引擎,引擎把下載的網頁發送給蜘蛛/爬蟲處理。

1.4. 組件04:蜘蛛/爬蟲(Spiders)

??蜘蛛/爬蟲(Spider)負責解析下載器下載的網頁,并從中提取數據項(ITEM)(也稱為爬取項)或后續的爬取請求。
??蜘蛛/爬蟲(Spider)一般由用戶實現,用來實現用戶的爬取邏輯。一般繼承Spider類來定制實現。

1.5. 組件05:數據項管道(Item Pipeline)

??數據項管道(Item Pipeline)負責處理被蜘蛛/爬蟲提?。ɑ蚺廊。┑臄祿?。典型的任務包括:
????1. 清理;
????2. 驗證;
????3. 持久存儲(如將數據項存儲在數據庫關系數據庫或者NoSQL數據庫中)。

1.6. 組件06:下載器中間件(Downloader middlewares)

??下載器中間件(Downloader middlewares)是位于引擎和下載器之間的特定功能的回調Hook,負責處理從引擎傳遞到下載器時處理請求,以及從下載器傳遞到引擎的響應。
??使用下載器中間件(Downloader middlewares)的幾種情況:
????1. 在將請求發送給下載者之前處理該請求(即在Scrapy將請求發送到網站之前);
????2. 在傳遞給spider之前改變接受到的響應;
????3. 重新發送新的請求,而不是將收到的響應傳遞給spider;
????4. 在沒有爬取到網頁的情況下,發送一個響應給spider;
????5. 需要根據條件放棄一些請求。

1.7. 組件07:蜘蛛/爬蟲中間件(Spider middlewares)

??蜘蛛/爬蟲中間件(Spider middlewares)是位于引擎和蜘蛛之間的特定功能的Hook,負責處理Spider的輸入(響應)和輸出(數據項或者請求)。
??蜘蛛/爬蟲中間件(Spider middlewares)的幾種情況:
????1. spider回調的輸出后的處理:包含:更改/添加/刪除請求或數據項;
????2. 開始請求的后處理;
????3. 處理spider異常;
????4. 對一些基于響應內容的請求調用errback,而不是回調。

2. 核心工作流程

??Scrapy的工作流程是按照爬取的數據設計的流程,并據此設計組件結構。(下圖是來自Scrapy的官方文檔)
scrapy框架核心組件與數據流示意圖

2.1. 流程01-獲取請求

??引擎從蜘蛛獲取需要爬取的初始請求。
????源:Spider
????目標:Engine
????數據:請求

2.2. 流程02-請求調度安排

??引擎調度爬取請求到調度器,并申請下一個需要爬取的爬取請求。
????源:Engine
????目標:Scheduler
????數據:請求

2.3. 流程03-調度爬取請求

??引擎器返回下一個爬取請求給引擎。(為什么不直接爬取,而是需要經過調度器處理呢?調度的好處在于:多任務爬取,還可以處理爬取請求與爬取過程的時間不一致的時間差。)
????源:Scheduler
????目標:Engine
????數據:請求

2.4. 流程04-發送請求給下載器

??引擎將請求發送到下載器,并通過下載器中間軟件傳遞(process_request回調函數可以處理請求數據)。
????源:Engine
????目標:Downloader
????數據:請求

2.5. 流程05-下載器完成下載

??一旦頁面下載器完成頁面下載,下載器將使用下載好的頁面生成一個響應(使用該頁面),并將其發送到引擎,通過下載器中間軟件(process_response回調函數完成下載后的頁面數據處理)。
????源:Downloader
????目標:Engine
????數據:響應

2.6. 流程06-數據項抽取

??引擎從下載器接收響應并將其發送到spider進行處理,并通過spider中間件進行處理(process_spider_input回調函數處理爬取的網頁數據)。
????源:Engine
????目標:Spider
????數據:響應

2.7. 流程07-返回抽取的數據與請求

??Spider處理響應(從爬取的網頁中抽取需要的數據項),并通過spider中間件(process_spider_output回調函數處理Spider處理過的數據)向引擎返回抽取的數據項或者新的附加請求。
????源:Spider
????目標:Engine
????數據:數據項(附加的請求)

2.8. 流程08-存儲抽取的數據項

??引擎將已處理的數據項發送到數據項管道,然后將已附加的請求發送到調度程序,并請求可能的下一個請求進行爬取。
????源:Engine
????目標:Item Pipeline/Scheduler
????數據:數據項/附加請求

2.9. 流程09-結束爬取

??重復01-08,直到調度器中沒有請求調度為止。

三、Scrapy入門

??這個入門是按照官方的教程組織。
??不是上面介紹的每個組件都需要我們開發,實際只需要我們開發業務部分,爬蟲的通用功能部分都封裝到框架中,所以我們需要一個框架的環境,并理解整個工作流程,并關注需要開發的部分,以及開發部分與整個框架組件的關系。

1. 創建一個爬蟲項目

??爬蟲項目使用scrapy框架提供的一個工具創建:scrapy,該工具創建的項目會提供業務部分運行的環境與配置。

1.1. scrapy工具介紹

1.1.1. 獲取scrapy工具幫助

??直接在終端輸入scrapy,可以直接輸出scrapy工具的幫助。
命令:

localhost:~ yangqiang$ scrapy 
scrapy工具幫助獲取截圖

??其中startproject命令項就是我們馬上要使用來創建項目的。

1.1.2. 獲取startproject命令項幫助

??獲取幫助的指令:


localhost:~ yangqiang$ scrapy startproject -h

創建爬蟲項目指令startproject幫助獲取截圖

1.2. 使用scrapy工具創建一個爬蟲項目

??創建爬蟲項目的兩個重要參數:
????1. 項目名稱
????2. 項目存放目錄(可選,默認當前目錄)

1.2.1. 創建項目


localhost:codes yangqiang$ scrapy startproject FirstScrapy

創建項目過程與結果截圖

1.2.2. 創建好的項目文件

??可以查看創建的項目,其中的文件結合上面的組件與工作流程,大致也知道其用途與作用。
創建的爬蟲項目工程

1.3. 使用pycharn打開創建的項目

??可以使用pycharm IDE工具打開創建的爬蟲項目:


使用pycharm打開爬蟲項目工程

2. 實現爬蟲業務

??因為在框架在開發,為了保證框架能順利工作,需要按照設計的結構,繼承scrapy.Spider類,并發起一個爬取請求,并處理。

2.1. 創建爬蟲代碼模塊

??在項目的spiders包路徑下,創建一個python源代碼文件:spiders.home_spider.py。

使用pycharm創建的爬蟲代碼模塊

2.2. 繼承Spider

??由于Spider是抽象類,需要override其中的抽象函數。


   def parse(self, response):
        raise NotImplementedError('{}.parse callback is not defined'.format(self.__class__.__name__))

??繼承Spider類后的子類:

# coding = utf-8
import scrapy


class HomeSpider(scrapy.Spider):

    def parse(self, response):
        pass

2.3. 爬蟲中兩個重要的屬性

2.3.1. name屬性

??name屬性,用來在執行爬蟲的時候指定爬蟲。屬性類型是字符串。

2.3.2. start_urls屬性

??start_urls屬性用來發起一個爬蟲任務請求。屬性類型是列表。

2.3.3. 屬性實現代碼

# coding = utf-8
import scrapy


class HomeSpider(scrapy.Spider):
    name = 'home'
    start_urls = [
        'https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1',
    ]
    
    def parse(self, response):
        pass

3. scrapy工具與運行爬蟲項目

3.1. 在項目目錄下的scrapy工具的幫助

??在scrapy工具創建的爬蟲項目頂層目錄下,執行scrapy工具獲取的幫助會更多。
??命令:


localhost:FirstScrapy yangqiang$ scrapy

??執行效果:

在爬蟲項目目錄下獲取scrapy工具與在其他地方得到的幫助內容存在不同

??與項目相關的命令有(6個):
????list:列出項目中爬蟲列表。
????check:檢查爬蟲。
????crawl:啟動爬蟲任務。
????edit:編輯爬蟲。
????fetch:獲取。
????parse:解析。
??上述命令的使用,使用幫助可以獲取。具體的使用在后面會介紹。

scrapy的edit指令幫助截圖

3.2. list爬蟲

??命令:

localhost:FirstScrapy yangqiang$ scrapy list

??效果:
list指令使用截圖

3.3. edit爬蟲

??命令:

localhost:FirstScrapy yangqiang$ scrapy edit home

??一般不使用這個指令在字符界面下編輯,而是使用IDE工具編輯。不過遠程維護使用字符界面是非常方便的,

??效果:
edit指令使用截圖

3.4. crawl爬蟲-運行爬蟲

??命令:

localhost:FirstScrapy yangqiang$ scrapy crawl home

??使用該命令啟動爬蟲任務,其中home是爬蟲程序中name指定的爬蟲名。
??效果:

crawl指令執行截圖

3.5. check爬蟲

??命令:

localhost:FirstScrapy yangqiang$ scrapy check home

??檢查爬蟲代碼中的錯誤。

??下面是沒有錯誤的例子:
對沒有錯誤的爬蟲check執行的截圖

??下面是有錯誤的例子(隨便在代碼中設計幾個錯誤即可)。
對存在語法錯誤的爬蟲代碼執行check的截圖

3.6. parse爬蟲

??parse命令用來測試爬蟲的parse函數。
??parse命令的幫助:

parse指令的幫助

??命令:

localhost:FirstScrapy yangqiang$ scrapy parse --spider=home https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1

??效果(當沒有指定爬蟲名,這會使用url直接創建一個爬蟲,但是scrapy存在bug,會報錯,在github上已經有人修正這個bug,可以通過百度找到這個帖子):


parse指令執行的截圖

3.7. fetch爬蟲

??直接下載頁面,并顯示在終端。
??命令:

localhost:FirstScrapy yangqiang$ scrapy fetch https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1

??效果:


fetch指令執行截圖

3.8. genspider生成爬蟲

??genspider可以查看爬蟲模板,創建爬蟲,編輯爬蟲等功能。其幫助如下:


genspider指令的幫助

3.8.1. 查看模板

??一般默認的模板是basic。
??命令:

localhost:FirstScrapy yangqiang$ scrapy genspider -l

??效果:


查看已有的爬蟲模板

3.8.2. 創建爬蟲

??命令:

localhost:FirstScrapy yangqiang$ scrapy genspider -t crawl  myspider https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1

??效果:
使用genspide創建爬蟲的過程截圖

??創建后,在項目工程中能看見這個爬蟲代碼文件:!
在pycharm中查看創建的爬蟲代碼模塊

3.8.3. 創建并編輯爬蟲

??命令:

localhost:FirstScrapy yangqiang$ scrapy genspider -e  myspider 'https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1'

??這個命令是先創建,后編輯。注意:編輯中需要項目的模塊導入,否則編輯不會正常。不過一般創建好以后,也不會在終端下編輯。

3.9. view查看爬取頁面

??該命令首先下載頁面,然后使用瀏覽器打開。
??命令:

localhost:FirstScrapy yangqiang$ scrapy  view https://www.baidu.com

??效果:
view指令執行截圖

3.10. shell交互式爬蟲處理

??使用交互式處理爬蟲數據處理。與代碼一樣,只是交互式開發模式。
??命令:

localhost:FirstScrapy yangqiang$ scrapy shell 'https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1'

??效果(綠色的表示代碼輸入):
shell交互式爬蟲處理截圖

??交互式編程示例:
交互式代碼輸入與執行截圖

3.11. settings獲取settings.py中的配置

??settings指令用來獲取與設置settings.py中的配置值。
??命令:

localhost:FirstScrapy yangqiang$ scrapy settings --get=SPIDER_MODULES

??效果:
使用settings指令獲取settings文件中定義的配置

??下面是settings.py文件:
settings.py文件截圖

3.12. runspider運行爬蟲文件

??這個命令是直接執行爬蟲代碼文件,與crawl的區別在于,crawl執行的是爬蟲項目spiders目錄下的有爬蟲名的爬蟲。
??命令:

localhost:FirstScrapy yangqiang$ scrapy runspider ./FirstScrapy/spiders/home_spider.py

??效果:
獨立于爬蟲項目來執行某個爬蟲代碼

四、爬蟲中的數據流與數據處理

1. 創建一個測試項目

??使用scrapy工具創建一個爬蟲數據流與數據處理的測試項目。
??創建命令:

localhost:codes yangqiang$ scrapy  startproject  Scra_DataFlow

??創建過程:
創建一個數據流演示項目工程

??下面主要關注點在數據上,所以其他scarpy工具等使用細節可以參考上面的幫助。
??同時,scrapy爬蟲框架提供了一些快捷實現方式,下面都采用傳統的思路實現,這樣容易理解,快捷方式的介紹不作為重點,甚至不在這里介紹。

2. 爬蟲目標

2.1. 爬取站點

??爬取騰訊課堂上的數據。爬取騰訊課堂基礎課程中的Python付費課程信息。
爬取目標網站截圖

2.2. 爬取數據

??課程名稱,培訓機構,購買人數,課程價格,開課方式等。

2.3. 理解domain與url

??domain:https://ke.qq.com
??urls:https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1

3. 使用命令創建爬蟲

??使用scrapy的genspider指令創建spider代碼模板。
??命令:

localhost:Scra_DataFlow yangqiang$ scrapy genspider -t basic  course  ke.qq.com
使用genspider用basic模板創建一個爬蟲模塊

??創建好的代碼如下:

# -*- coding: utf-8 -*-
import scrapy


class CourseSpider(scrapy.Spider):
    name = 'course'
    allowed_domains = ['ke.qq.com']
    start_urls = ['http://ke.qq.com/']

    def parse(self, response):
        pass


??在Pycharm中,代碼在項目中的截圖:


在pycharm中打開創建的爬蟲代碼

4. 爬取URL

??實際需要爬取的頁面URL為:
????https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1

??這是scrapy框架數據流的第01步。從爬蟲發起一個請求。
??該請求,使用迭代器的方式返回給爬蟲引擎:
????方式一:是引擎調用def start_requests(self)函數,通過返回值得到請求。
????方式二:覆蓋父類的start_urls屬性,用來替代默認的 start_requests函數,返回請求。

??然后爬蟲引擎,把請求發送給調度器(流程02),根據處理資源的情況,引擎從調度器獲取請求(流程03),再發送給下載器(流程04)。

??下載器使用引擎發送過來的請求,完成下載任務,并把下載的響應返回給引擎(流程05)。引擎把響應通過parse函數傳遞給爬蟲程序(流程06),爬蟲通過parse函數參數,得到下載響應。其中想用通過response對象獲取,該響應對象的類型是:<class 'scrapy.http.response.html.HtmlResponse'>。

??注意:流程01,02,03,04,05,06都是框架自動完成,如果不做特別的處理,可以不干預框架的流程,直接在流程06的結束得到一個響應對象。

??scrapy框架的數據流,注意其中的編號,對應這我們這里的一樣的編號。
為了查看方便,再顯示下官方的數據流示意圖

5. 通過parse函數的參數,獲取下載響應

5.1. scrapy.http.response.html.HtmlResponse類

??數據成員:
????|- encoding
????|- selector
????|- text
????|- body
????|- meta
????|- url
??函數成員:
????|- body_as_unicode(self)
??????|- 返回一個unicode的body
????|- css(self, query)
????follow(self, url, callback=None, method='GET', headers=None, body=None, cookies=None, meta=None, encoding=None, priority=0, dont_filter=False, errback=None)
??????|- 返回Request類型的對象。
????|- replace(self, *args, **kwargs)
????|- urljoin(self, url)
????|- xpath(self, query, **kwargs)

??獲取解碼后的文本頁面內容。
????|- text
??數據解析接口:
????|- css(self, query)
????|- xpath(self, query, **kwargs)

5.2. 直接處理(中斷數據流)

5.2.1. 直接保存成文件

??這類直接保存成html文本文件。

# -*- coding: utf-8 -*-
import scrapy


class CourseSpider(scrapy.Spider):
    name = 'course'
    allowed_domains = ['ke.qq.com']
    start_urls = ['https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1']

    def parse(self, response):
        # 2019-02-14 15:00:14 [course] DEBUG: <class 'scrapy.http.response.html.HtmlResponse'>
        # self.log(type(response))
        # utf-8
        # self.log(response.encoding)
        # <Selector xpath=None data='<html lang="zh">\n<head>\n    <meta charse'>
        # self.log(response.selector)
        # self.log(response.text)   # unicode的文本內容
        # self.log(response.body)     # 二進制內容
        #  {'download_timeout': 180.0, 'download_slot': 'ke.qq.com', 'download_latency': 0.592094898223877}
        # self.log(response.meta)
        # https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1
        # self.log(response.url)
        # 保存下載的頁面到文件,護或者到數據庫(可以考慮文檔數據庫或者mysql關系數據庫)
        with open('page.html', 'w') as fd:
            fd.write(response.text)

??下載后保存的文件內容。
直接保存的下載頁面的截圖

5.2.2. 解析保存成csv文件

??從瀏覽器獲取XPATH格式(/html/body/section[1]/div/div[3]/ul):


從瀏覽器獲取xpath數據的截圖

??把瀏覽器中獲取的XPATH按照我們的需求修改:
????| - 瀏覽器XPATH:/html/body/section[1]/div/div[3]/ul
????| - 修改后XPATH://section[1]/div/div[3]/ul/li
??
??因為XPATH是從body文檔開始解析的,同時我們希望獲取頁面上24門課程的內容。
??代碼如下:

# -*- coding: utf-8 -*-
import scrapy


class CourseSpider(scrapy.Spider):
    name = 'course'
    allowed_domains = ['ke.qq.com']
    start_urls = ['https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1']

    def parse(self, response):
        # 解析數據,并保存成csv文件。
        result = response.xpath('//section[1]/div/div[3]/ul/li')
        self.log('XXXX:{}'.format(len(result)))

??運行爬蟲的輸出結果是:
使用xpath獲取到我們需要爬取得24們課程列表截圖

??xpath返回的是一個list列表,其中元素的類型是:<class 'scrapy.selector.unified.Selector'>,該類型的API幫助可以使用help獲取。
??下面我們可以直接解析得到需要的字段(保存到csv的實現,這里就略掉,其中使用了xpath或者css,這個知識點,下面專門講解)。

# -*- coding: utf-8 -*-
import scrapy


class CourseSpider(scrapy.Spider):
    name = 'course'
    allowed_domains = ['ke.qq.com']
    start_urls = ['https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1']

    def parse(self, response):
        # 解析數據,并保存成csv文件。
        result = response.xpath('//section[1]/div/div[3]/ul/li')
        for course_ in result:
            # self.log(type(course_))
            # 課程名稱
            course_name = course_.xpath('h4[@class="item-tt"]/a/text()').get()
            self.log('課程名稱:{}'.format(course_name.strip() if course_name else ''))
            # 培訓機構
            course_organization = course_.xpath(
                'div[@class="item-line item-line--middle"]/span[@class="item-source"]/a/text()').get()
            self.log('培訓機構:{}'.format(course_organization.strip() if course_organization else ''))
            # 課程連接
            course_link = course_.xpath('h4[@class="item-tt"]/a/@href').get()
            self.log('課程連接:{}'.format(course_link.strip() if course_link else ''))
            # 報名人數
            course_number = course_.xpath(
                'div[@class="item-line item-line--middle"]/span[@class="line-cell item-user"]/text()').get()
            self.log('報名人數:{}'.format(course_number.strip()  if course_number else ''))
            # 課程狀態
            course_status = course_.xpath('div[@class="item-status"]/text()').get()
            self.log('課程狀態:{}'.format(course_status.strip() if course_status else ''))
            # 課程價格
            course_price = course_.xpath('div[@class="item-line item-line--bottom"]/span/text()').get()
            self.log('課程價格:{}'.format(course_price.strip() if course_price else ''))

??解析的效果:
每門課程解析的結果輸出截圖

5.3. 返回數據項到管道(流程07與流程08)

??在parse函數中,實際是可以返回數據的:
????| - 返回的數據是Items,則引擎接受到數據后,會發送給管道Pipeline。
????| - 返回Request請求,則把Request發送給調度器,繼續爬取數據。
??
??這里只關注返回Items,返回Request的情路,后面說明。

5.3.1. 定義Items的數據項

??繼承scrapy.Item類,對應需要接續的字段定義數據項。


# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class ScraDataflowItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    # 課程名稱
    course_name = scrapy.Field()
    # 培訓機構
    course_organization = scrapy.Field()
    # 課程連接
    course_link = scrapy.Field()
    # 報名人數
    course_number = scrapy.Field()
    # 課程狀態
    course_status = scrapy.Field()
    # 課程價格
    course_price = scrapy.Field()

5.3.2. 使用數據項,緩存爬取的數據字段

??使用數據項比較模式化,比較容易理解。 下面是實現代碼:

# -*- coding: utf-8 -*-
import scrapy
from  Scra_DataFlow.items import ScraDataflowItem

class CourseSpider(scrapy.Spider):
    name = 'course'
    allowed_domains = ['ke.qq.com']
    start_urls = ['https://ke.qq.com/course/list?mt=1001&st=2002&tt=3019&price_min=1&page=1']

    def parse(self, response):
        result = response.xpath('//section[1]/div/div[3]/ul/li')
        items = []    # 數據項數組列表
        for course_ in result:
            # 數據項
            item_ = ScraDataflowItem()
            course_name = course_.xpath('h4[@class="item-tt"]/a/text()').get()
            item_['course_name'] = '{}'.format(course_name.strip() if course_name else '')
            # 培訓機構
            course_organization = course_.xpath(
                'div[@class="item-line item-line--middle"]/span[@class="item-source"]/a/text()').get()
            item_['course_organization'] = course_organization.strip() if course_organization else ''
            # 課程連接
            course_link = course_.xpath('h4[@class="item-tt"]/a/@href').get()
            item_['course_link'] = course_link.strip() if course_link else ''
            # 報名人數
            course_number = course_.xpath(
                'div[@class="item-line item-line--middle"]/span[@class="line-cell item-user"]/text()').get()
            item_['course_number'] = course_number.strip()  if course_number else ''
            # 課程狀態
            course_status = course_.xpath('div[@class="item-status"]/text()').get()
            item_['course_status'] = course_status.strip() if course_status else ''
            # 課程價格
            course_price = course_.xpath('div[@class="item-line item-line--bottom"]/span/text()').get()
            item_['course_price'] = course_price.strip() if course_price else ''
            items.append(item_)
        # 返回數據項到管道
        return items

5.3.3. 使用管道保存數據

??使用命令:

localhost:Scra_DataFlow yangqiang$ scrapy crawl course  -o course.csv

??執行過程:
輸出csv文件的爬蟲執行過程截圖

??提示:pycharm可以安裝csv的插件,用來顯示csv文件
pycharm的csv插件安裝截圖

??使用管道保存的文件(不使用插件在pycharm顯示):
使用管道保存的文件顯示截圖(pychar無插件文本顯示)

??使用管道保存的文件(使用插件在pycharm顯示)
使用pycharm插件顯示位表格

附錄

??需要掌握爬蟲的高級應用,以及一些經典場景應用,可以關注后繼內容與馬哥教育。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。