Scrapy將數據保存到Excel和MySQL中的方法實現
Scrapy是一個用Python實現的為瞭爬取網站數據、提取數據的應用框架。我們對於爬取到的數據存儲到本地或數據庫是經常要用到的操作。主要講解兩種保存方式:
- Excel
- MySQL
說明一下爬取到的數據:
爬取豆瓣讀書top250網頁的相關信息:
書名title、鏈接link、國傢country、作者author、翻譯者translator、出版社publisher、出版時間time、價格price、星級star、評分score、評分人數people、簡介comment
1. Excel
主要講解兩種方式:openpyxl
和pandas
1.1 openpyxl
class ExcelPipeline: def __init__(self): # 創建Excel文件 self.wb = Workbook() # 選取第一個工作表 self.ws = self.wb.active # 寫入表頭 self.ws.append(['title', 'link', 'country', 'author', 'translator', 'publisher', 'time', 'price', 'star', 'score', 'people', 'comment' ]) def process_item(self, item, spider): self.ws.append([ item.get('title', ''), item.get('link', ''), item.get('country', ''), item.get('author', ''), item.get('translator', ''), item.get('publisher', ''), item.get('time', ''), item.get('price', ''), item.get('star', ''), item.get('score', ''), item.get('people', ''), item.get('comment', '') ]) return item def close_spider(self, spider): self.wb.save('result.xlsx')
1.1.1 代碼說明
ExcelPipeline 繼承自 Scrapy 的 Pipeline 類,並重寫瞭三個方法:__init__()
、process_item()
和 close_spider()
。
在 __init__()
方法中:
- 創建瞭一個 Excel 文件,並選取瞭第一個工作表。然後,我們寫入瞭表頭。
- 當然你也可以將這部分代碼寫在
open_spider
方法中
在 process_item()
方法中,我們將每一行的數據寫入到工作表中。
process_item
方法:
- 不會覆蓋之前已經寫入的數據,它會在數據末尾追加新的行。
- 你調用多次
process_item
方法,每次都會在表格的末尾追加一行新數據。
在 close_spider()
方法中,我們保存 Excel 文件。
1.1.2 註意
可以發現我在process_item()
方法中使用瞭item.get(key, default)
:
考慮可能存在某些 item 中沒有某些鍵值的情況,這可能會導致程序出錯。
當然如果你已經進行過數據處理也可以直接用item[key]
。
使用瞭 item.get(key, default)
方法來獲取 item
中的鍵值,如果某個鍵不存在,則返回一個空字符串 ''
在 Scrapy 中,
item
是一個字典類型,它由一系列鍵值對組成,每個鍵值對表示一個字段。在處理item
時,我們通常需要從中獲取某個字段的值。使用字典的get
方法可以方便地實現這個功能。
get
方法有兩個參數:key
表示要獲取的鍵,default
表示鍵不存在時的默認值。例如:
1.2 pandas
class ExcelPipeline: def __init__(self): # 創建一個空的數據框 self.df = pd.DataFrame(columns=['title', 'link', 'country', 'author', 'translator', 'publisher', 'time', 'price', 'star', 'score', 'people', 'comment' ]) def process_item(self, item, spider): # 將數據添加到數據框中 item['title'] = item.get('title', '') item['link'] = item.get('link', '') item['country'] = item.get('country', '') item['author'] = item.get('author', '') item['translator'] = item.get('translator', '') item['publisher'] = item.get('publisher', '') item['time'] = item.get('time', '') item['price'] = item.get('price', '') item['star'] = item.get('star', '') item['score'] = item.get('score', '') item['people'] = item.get('people', '') item['comment'] = item.get('comment', '') series = pd.Series(item) self.df = self.df.append(series, ignore_index=True) return item def close_spider(self, spider): # 將數據框保存到 Excel 文件中 self.df.to_excel('result.xlsx', index=False)
1.2.1 代碼說明
定義瞭一個 ExcelPipeline
類,它包含瞭三個方法:__init__
、process_item
和 close_spider
。
__init__
方法用於初始化類實例process_item
方法用於處理每個爬取到的 item,將其添加到items
列表中close_spider
方法用於在爬蟲關閉時將items
列表中的數據保存到 Excel 文件中。
1.2.2 常見錯誤
在代碼中有大量的item['title'] = item.get('title', '')
類似代碼
你可以選擇不寫,但如果item中有一些字段的值為None,而pandas不支持將None類型的值添加到DataFrame中,會導致程序錯誤。這一點比openpyxl要嚴格的多。
字典對象轉換為Series對象
self.df
是一個DataFrame對象,而item
是一個字典對象。因此,需要將字典對象轉換為Series對象,然後再將其添加到DataFrame中。
series = pd.Series(item) self.df = self.df.append(series, ignore_index=True)
only Series and DataFrame objs are valid
這個錯誤一般就是發生在使用Pandas將數據轉換成DataFrame時,傳入的參數不是Series或DataFrame類型。
上面的代碼就是用來避免這個問題的。
1.3 openpyxl和pandas對比
pandas和openpyxl都是非常強大的Python數據處理庫,兩者在不同的場景下可以發揮出各自的優勢。
- 如果需要處理大量的Excel文件,需要對文件進行復雜的操作,比如格式化、圖表等,那麼openpyxl可能更適合,因為它專註於Excel文件的讀寫和操作,具有更高的靈活性和控制力。
- 如果數據已經在Python中,且需要進行各種統計分析和處理,如數據聚合、數據透視表、數據分組、數據清洗、數據可視化等,那麼pandas可能更適合,因為它提供瞭豐富的數據處理工具和函數。
總的來說,兩者都是很好的工具,具體使用哪一個取決於具體需求和場景。
2. MYSQL
可以使用Python的MySQL驅動程序,例如 mysql-connector-python
或 pymysql
。主要將pymysql。
class MySQLPipeline: def __init__(self): # 連接 MySQL 數據庫 self.conn = pymysql.connect( host='localhost', port=3306, user='root', password='your_password', database='your_database', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor ) # 創建一個遊標對象 self.cursor = self.conn.cursor() # 創建表 self.create_table() def create_table(self): # SQL 語句:創建數據表 sql = '''CREATE TABLE IF NOT EXISTS `book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `link` varchar(255) NOT NULL, `country` varchar(255) NOT NULL, `author` varchar(255) NOT NULL, `translator` varchar(255) NOT NULL, `publisher` varchar(255) NOT NULL, `time` varchar(255) NOT NULL, `price` varchar(255) NOT NULL, `star` varchar(255) NOT NULL, `score` varchar(255) NOT NULL, `people` varchar(255) NOT NULL, `comment` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci''' # 執行 SQL 語句 self.cursor.execute(sql) # 提交事務 self.conn.commit() def process_item(self, item, spider): # SQL 語句:插入數據 sql = '''INSERT INTO `book` ( `title`, `link`, `country`, `author`, `translator`, `publisher`, `time`, `price`, `star`, `score`, `people`, `comment` ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)''' # 執行 SQL 語句 self.cursor.execute(sql, ( item['title'], item['link'], item['country'], item['author'], item['translator'], item['publisher'], item['time'], item['price'], item['star'], item['score'], item['people'], item['comment'] )) # 提交事務 self.conn.commit() return item def close_spider(self, spider): # 關閉遊標對象 self.cursor.close() # 關閉數據庫連接 self.conn.close()
2.1 代碼說明
我們創建瞭一個名為MySQLPipeline
的自定義ScrapyPipeline。
__init__
方法中接收瞭MySQL數據庫的配置信息。
其中還調用瞭create_table
,當然如果保證表已經存在,也沒有必要這麼寫
如果你嫌每次連接都要寫信息的話,可以在setting.py中定義MySQL相關變量:
create_table
方法創建表book
process_item
方法用於將抓取的數據插入到數據庫表中。
close_spider
方法用於關閉遊標和連接。
2.2 pymysql介紹
2.2.1 遊標對象
在Python中,連接數據庫時需要創建一個數據庫連接對象,然後通過這個連接對象創建一個遊標對象。
遊標對象是執行數據庫操作的主要對象,它負責向數據庫發送查詢和獲取結果。
在Python中,常用的遊標對象有Cursor
、DictCursor
、SSCursor
等。
Cursor
:普通遊標(默認),返回結果為元組類型。DictCursor
:字典遊標,返回結果為字典類型。SSCursor
:嵌套遊標,可用於處理大數據集。
在獲取大量數據時效率比普通遊標更高,但是會占用更多的系統資源。
與普通遊標相比,嵌套遊標不會將整個查詢結果讀入內存,而是每次隻讀取部分數據。
根據需要,選擇不同類型的遊標對象可以方便我們對返回結果進行處理。
2.2.2 各種遊標說明
創建連接對象時有這麼一段代碼:
cursorclass=pymysql.cursors.DictCursor
用於設置遊標返回的數據類型,默認返回的是元組(tuple)類型,設置為DictCursor後可以返回字典(dict)類型,更方便處理數據。一般使用普通遊標就行瞭
三種遊標主要是在查詢時的方式存在區別:
cur = conn.cursor() cur.execute('SELECT * FROM my_table') result = cur.fetchone() # 獲取一條記錄,返回的是元組類型 # 普通遊標 print(result[0]) # 訪問第一個字段的值 # 字典遊標 print(result['id']) # 訪問數據庫中字段名為 id 的字段的值,{'id': 1, 'name': 'Alice'} # 嵌套遊標 print(result[0]) # 訪問第一個字段的值
如果是查詢的多條數據,則返回的是元組或字典組成的列表:
# 普通遊標 [(1, 'John', 'Doe'), (2, 'Jane', 'Doe'), (3, 'Bob', 'Smith')] # 字典遊標 [{'id': 1, 'first_name': 'John', 'last_name': 'Doe'}, {'id': 2, 'first_name': 'Jane', 'last_name': 'Doe'}, {'id': 3, 'first_name': 'Bob', 'last_name': 'Smith'}]
3. 特別說明
每個item在被提交給管道時都會調用一次管道類的process_item
方法。
每個item都會經過process_item
方法進行處理,而open_spider
和close_spider
方法隻會在爬蟲啟動和結束時執行一次。
在Scrapy中,可以通過在管道類的open_spider
和close_spider
方法中建立和關閉數據庫連接,以減少連接建立和關閉的次數。
__init__
方法也是隻在Spider啟動時隻執行一次
具體做法是,在open_spider
方法中建立數據庫連接,在process_item
方法中使用連接對數據進行存儲操作,在close_spider
方法中關閉連接。這樣做可以有效減少連接的建立和關閉次數,提高爬取效率。
如果你在open_spider
方法中創建瞭數據庫連接,那麼這個連接將會被共享並被多個process_item
方法使用。
同樣的,如果在close_spider
方法中關閉瞭數據庫連接,那麼這個連接也會被所有的process_item
方法共享並在爬蟲結束時關閉。
這種做法可以減少不必要的連接和關閉操作,從而提高性能。
到此這篇關於Scrapy將數據保存到Excel和MySQL中的方法實現的文章就介紹到這瞭,更多相關Scrapy數據保存到Excel和MySQL內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Scrapy之爬取結果導出為Excel的實現過程
- python實戰項目scrapy管道學習爬取在行高手數據
- Python中Scrapy+adbapi提高數據庫寫入效率實現
- scrapy框架ItemPipeline的使用
- Python全棧之學習MySQL(3)