上章回顧
前兩章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
刷新數據庫
如下所示,已經成功插入數據