Python實戰演練之數據導出

上章回顧

前兩章Python實戰演練之scrapy初體驗Python實戰演練之跨頁爬取中講到了scrapy項目的創建,爬蟲的創建,數據的爬取以及跨頁爬取。

數據導出

通過shell命令爬取的數據往往需要我們存放在某處

例如:執行如下命令來啓用數據爬取

$ scrapy crawl crouses

將結果保存到文件中:格式:json、csv、xml、pickle、marshal等

$ scrapy crawl crouses -o fangs.json
$ scrapy crawl crouses -o fangs.csv
$ scrapy crawl crouses -o fangs.xml
$ scrapy crawl crouses -o fangs.pickle
$ scrapy crawl crouses -o fangs.marshal

除此之外,更多的時候我們需要將其存入數據庫中。

存入數據庫

我這裏使用的mysql數據庫,數據庫管理工具使用的是Navicat Premium
mysql的安裝以及Navicat如何連接mysql我空的時候再寫出來跟大家分享吧。

ItemPipeline的介紹

  • 當Item在Spider中被收集之後,它將會被傳遞到Item Pipeline,一些組件會按照一定的順序執行對Item的處理
  • 每個item pipeline組件(有時稱之爲”Item Pipeline“)是實現了簡單方法的Python類。他們接收到Item並通過它執行一些行爲,同時也決定此Item是否繼續通過pipeline,或是被丟棄而不再進行處理
  • 以下是item pipeline的一些典型應用:
    清理HTML數據
    驗證爬取的數據(檢查item包含某些字段)
    查重(並丟棄)
    將爬取結果保存到數據庫中

如何自定義ItemPipeline

  • 編寫自己的item pipeline很簡單,每個item pipelines組件是一個獨立的Python類,同時必須實現以下方法:
    process_item(item,spider) 必須
    open_spider(spider) 可選
    close_spider(spider) 可選
process_item(item,spider)

每個item pipeline組件都需要調用該方法,這個方法必須返回一個Item(或任何繼承類)對象,或是拋出DropItem異常,被丟棄的item將不會被之後的pipeline組件所處理(可用於做數據過濾)
參數:

  • item(Item 對象)-被爬取的item
  • spider(Spider對象)-爬取該item的spider

此外,他們也可實現以下方法。

open_spider(spider)

當spider被開啓時,這個方法被調用。
參數:

  • spider(Spider 對象)- 被開啓的spider
close_spider(spider)

當spider被關閉時,這個方法被調用
參數:

  • spider(Spider 對象)- 被關閉的spider

這裏pipelins.py代碼如下:

import pymysql

class EducsdnPipeline(object):
    def process_item(self, item, spider):
        return item

class MysqlPipeline(object):
    def open_spider(self, spider):
        '''負責連接數據庫'''
        self.db = pymysql.connect()
        # 獲取遊標對象
        self.cursor = self.db.cursor()

    def process_item(self, item, spider):
        '''執行數據表的寫入操作'''
        sql = "insert into courses(title,url,pic,teacher,time,price) values('%s','%s','%s','%s','%s','%s')"%(item['title'],item['url'],item['pic'],item['teacher'],str(item['time']),str(item['price']))
        self.cursor.execute(sql)
        self.db.commit()
        return item


    def close_spider(self, spider):
        '''關閉連接數據庫'''
        self.db.close()
注意:

這裏的操作是插入數據,前提是我已經在Navicat建好一個csdndb的數據庫,並新建一個叫courses的表,如圖所示:
在這裏插入圖片描述

一般數據庫的連接中會傳入數據庫的名稱,用戶,密碼,端口之類的參數,但是爲了後面方便更改,將其放在settings裏面處理。

在settings裏面添加:

ITEM_PIPELINES = {
   # 'educsdn.pipelines.EducsdnPipeline': 300,
     'educsdn.pipelines.MysqlPipeline': 301,
}
MYSQL_HOST = "localhost"
MYSQL_DATABASE = "csdndb"
MYSQL_USER = "root"
MYSQL_PASS = "xxxxxx" #沒有也可以留空
MYSQL_PORT = 3306

回到pipelines.py,改爲:

import pymysql

class EducsdnPipeline(object):
    def process_item(self, item, spider):
        return item

class MysqlPipeline(object):
    def __init__(self, host, user, password, database, port):
        self.host = host
        self.user = user
        self.password = password
        self.database = database
        self.port = port

    @classmethod
    def from_crawler(cls, crawler):
        # 自動調用;爲了實例化當前類對象;cls就是當前這個類
        return cls(
            host = crawler.settings.get("MYSQL_HOST"),
            user = crawler.settings.get("MYSQL_USER"),
            password = crawler.settings.get("MYSQL_PASS"),
            database = crawler.settings.get("MYSQL_DATABASE"),
            port = crawler.settings.get("MYSQL_PORT")

        )

    def open_spider(self, spider):
        '''負責連接數據庫'''
        self.db = pymysql.connect(self.host, self.user, self.password, self.database, charset="utf8", port=self.port)
        # 獲取遊標對象
        self.cursor = self.db.cursor()

    def process_item(self, item, spider):
        '''執行數據表的寫入操作'''
        sql = "insert into courses(title,url,pic,teacher,time,price) values('%s','%s','%s','%s','%s','%s')"%(item['title'],item['url'],item['pic'],item['teacher'],str(item['time']),str(item['price']))
        self.cursor.execute(sql)
        self.db.commit()
        return item


    def close_spider(self, spider):
        '''關閉連接數據庫'''
        self.db.close()

除此之外,還要在courses.py中將item傳入pipelines中
courses.py完整代碼如下:

import scrapy
from educsdn.items import CoursesItem

class CoursesSpider(scrapy.Spider):
    name = 'courses'
    allowed_domains = ['edu.csdn.net']
    start_urls = ['https://edu.csdn.net/courses/o280/p1']

    #第一頁
    p = 1
    
    def parse(self, response):
        # 解析課程信息
        # 獲取當前請求頁面下的所有課程信息
        print(dd.xpath("./div[@class='titleInfor'/text()]").extract())
        dl = response.selector.css("div.course_item")
        # 遍歷課程信息並封裝到item
        for dd in dl:
            item = CoursesItem()
            item['title'] = dd.css("span.title::text").extract_first()
            item['url'] = dd.css("a::attr(href)").extract_first()
            item['pic'] = dd.css("img::attr(src)").extract_first()
            item['teacher'] = dd.css("span.lecname::text").extract_first()
            item['time'] = dd.css("span.course_lessons::text").extract_first()
            item['price'] = dd.css("p.priceinfo i::text").extract_first()
            # print(item)
            # 將數據送入pipelines
            yield item
        # 跨頁提取信息
        self.p += 1
        if self.p < 4:
            next_url = 'https://edu.csdn.net/courses/o280/p'+ str(self.p)
            url = response.urljoin(next_url)
            yield scrapy.Request(url=url,callback=self.parse)

其實就是將print(item)改爲yield item

其他代碼在前兩章有寫,這裏就不多說了,項目代碼後期我會上傳到Github上,敬請期待。

回到控制檯

educsdn $ scrapy crawl courses

刷新數據庫
如下所示,已經成功插入數據
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章