scrapy爬取海量數據並保存在MongoDB和MySQL數據庫中


前言


       一般我們都會將數據爬取下來保存在臨時文件或者控制台直接輸出,但對於超大規模數據的快速讀寫,高並發場景的訪問,用數據庫管理無疑是不二之選。首先簡單描述一下MySQL和MongoDB的區別:MySQL與MongoDB都是開源的常用數據庫,MySQL是傳統的關系型數據庫,MongoDB則是非關系型數據庫,也叫文檔型數據庫,是一種NoSQL的數據庫。它們各有各的優點。我們所熟知的那些SQL語句就不適用於MongoDB了,因為SQL語句是關系型數據庫的標准語言。

 


 一、關系型數據庫

    關系模型就是指二維表格模型,因而一個關系型數據庫就是由二維表及其之間的聯系組成的一個數據組織。常見的有:Oracle、DB2、PostgreSQL、Microsoft SQL Server、Microsoft Access、MySQL、浪潮K-DB 等

MySQL:

1、在不同的引擎上有不同的存儲方式。

2、查詢語句是使用傳統的sql語句,擁有較為成熟的體系,成熟度很高。

3、開源數據庫的份額在不斷增加,mysql的份額頁在持續增長。
4、缺點就是在海量數據處理的時候效率會顯著變慢。


二、非關系型數據庫

    非關系型數據庫(nosql ),屬於文檔型數據庫。文檔的數據庫:即可以存放xml、json、bson類型的數據。這些數據具備自述性,呈現分層的樹狀數據結構。數據結構由鍵值(key=>value)對組成。常見的有:NoSql、Cloudant、MongoDB、redis、HBase。

NoSQL(Not only SQL),泛指非關系型的數據庫。隨着互聯網 web2.0 網站的興起,傳統的關系數據庫在應付 web2.0 網站,特別是超大規模和高並發的 SNS 類型的 web2.0 純動態網站已經顯得力不從心,暴露了很多難以克服的問題,而非關系型的數據庫則由於其本身的特點得到了非常迅速的發展。NoSQL 數據庫的產生就是為了解決大規模數據集合多重數據種類帶來的挑戰,尤其是大數據應用難題。非關系型數據庫可以為大數據建立快速、可擴展的存儲庫。

MongoDB

1、存儲方式:虛擬內存+持久化。
2、查詢語句:是獨特的MongoDB的查詢方式。
3、適合場景:事件的記錄,內容管理或者博客平台等等。
4、架構特點:可以通過副本集,以及分片來實現高可用。
5、數據處理:數據是存儲在硬盤上的,只不過需要經常讀取的數據會被加載到內存中,將數據存儲在物理內存中,從而達到高速讀寫。
6、成熟度與廣泛度:新興數據庫,成熟度較低,Nosql數據庫中最為接近關系型數據庫,比較完善的DB之一,適用人群不斷在增長。


三、MongoDB優勢與劣勢

優勢:
1、快速。  在適量級的內存的MongoDB的性能是非常迅速的,它將熱數據存儲在物理內存中,使得熱數據的讀寫變得十分快。
2、高擴展性。  MongoDB的高可用和集群架構擁有十分高的擴展性。
3、自身的FaiLover機制。  在副本集中,當主庫遇到問題,無法繼續提供服務的時候,副本集將選舉一個新的主庫繼續提供服務。
4、Json的存儲格式。  MongoDB的Bson和JSon格式的數據十分適合文檔格式的存儲與查詢。
劣勢:
1、 不支持事務操作。MongoDB本身沒有自帶事務機制,若需要在MongoDB中實現事務機制,需通過一個額外的表,從邏輯上自行實現事務。
2、 應用經驗少,由於NoSQL興起時間短,應用經驗相比關系型數據庫較少。
3、MongoDB占用空間過大。


  四、MySQL優勢與劣勢

 優勢:

1、在不同的引擎上有不同 的存儲方式。

2‘、查詢語句是使用傳統的sql語句,擁有較為成熟的體系,成熟度很高。

3、開源數據庫的份額在不斷增加,mysql的份額頁在持續增長。

 劣勢:

1、在海量數據處理的時候效率會顯著變慢。


五、Mysql和Mongodb主要應用場景

1.如果需要將mongodb作為后端db來代替mysql使用,即這里mysql與mongodb 屬於平行級別,那么,這樣的使用可能有以下幾種情況的考量:

   (1)  mongodb所負責部分以文檔形式存儲,能夠有較好的代碼親和性,json格式的直接寫入方便。(如日志之類)

   (2)  從datamodels設計階段就將原子性考慮於其中,無需事務之類的輔助。開發用如nodejs之類的語言來進行開發,對開發比較方便。

   (3)  mongodb本身的failover機制,無需使用如MHA之類的方式實現。

2.將mongodb作為類似redis ,memcache來做緩存db,為mysql提供服務,或是后端日志收集分析。 考慮到mongodb屬於nosql型數據庫,sql語句與數據結構不如mysql那么親和 ,也會有很多時候將mongodb做為輔助mysql而使用的類redis memcache 之類的緩存db來使用。 亦或是僅作日志收集分析。


六、對比

數據庫名 MongoDB MySQL 
數據庫模型 非關系型  關系型
存儲方式  以類JSON的文檔的格式存儲(虛擬內存+持久化) 不同引擎有不同的存儲方式 
 查詢語句 MongoDB查詢方式(包含類似JavaScript的函數) 傳統SQL語句
 數據處理方式   基於內存,將熱數據存放在物理內存中,從而達到高速讀寫  不同引擎有自己的特點
架構特點 可以通過副本集,以及分片來實現高可用 常見有單點,M-S,MHA.MMMCluster等架構方式
成熟度 新興數據庫,成熟度較低  成熟度高
廣泛度 NoSQL數據庫中,比較完善且開源,使用人數在不斷增長  開源數據庫,市場份額不斷增長
事務性 僅支持單文檔事務操作,弱一致性 支持事務操作
占用空間 占用空間大  占用空間小
 join操作  MongoDB沒有join MySQL支持join
 

 七、scrapy爬取貓眼電影排行榜海量數據,並法將其保存在本地Mysql和MongoDB中。

  1.  創建虛擬環境,在適當的目 錄創建項目 本案例項目名 mongodb
       創建項目命令  :scrapy startproject myfrist(your_project_name)(scrapy  startproject mongodb)用pycharm打開項目所在目錄,並在終端輸入 scrapy  gendpider maoyan maoyan.com(以貓眼電影網頁為例) 創建爬蟲。  創建爬蟲命令  :scrapy genspider 爬蟲名 爬蟲的地址 ,完整項目結構如下:
 

 

 2.思路:先訪問首頁的排行榜,可以提取出首頁排行的電影名和得分(每頁三十個數據)。在首頁中提取下一頁標簽的href,不斷推送。就可以循環爬取啦。

 

 

 

maoyan.py代碼如下:

 1 import scrapy
 2 
 3 
 4 class MaoyanSpider(scrapy.Spider):
 5     name = 'maoyan'
 6     allowed_domains = ['maoyan.com']
 7     start_urls = ['https://maoyan.com/films?showType=3&offset=0']
 8     count = 0
 9     NUM_PAGE = 3  # 默認爬前三頁
10 
11     def parse(self, response):
12         if self.count == self.NUM_PAGE:  # 控制抓取的頁數 例如只抓取前三頁就循環三次
13             return
14         names = response.xpath('//dd/div[@class="channel-detail movie-item-title"]/@title').extract()
15         grades = [div.xpath('string(.)').extract_first() for div in response.xpath('//dd/div[@class="channel-detail channel-detail-orange"]')]
17         next_url = response.xpath('//ul[@class="list-pager"]/li[last()]/a/@href').extract_first()  # 匹配父標簽下相同子標簽的最后一個
18         for name, grade in zip(names, grades):
19             # 把數據推送給pipeline管道
20             yield {
21                 'name': name,
22                 'grade': grade
23             }
24         yield scrapy.Request(response.urljoin(next_url), callback=self.parse)
25         self.count += 1

 3.數據的保存是在pipelines.py模塊中,代碼如下。

from pymongo import MongoClient
from pymysql import connect


class MonogodbPipeline:
    """
    數據庫名:maoyan
    數據表名:t_maoyan_movie
    可以事先不用創建,python會自動創建數據庫和數據表
    """

    def open_spider(self, spider):
        self.client = MongoClient('localhost', 27017)
        self.db = self.client.maoyan
        self.collection = self.db.t_maoyan_movie

    def process_item(self, item, spider):
        self.collection.insert(item)
        return item

    def close_spider(self, spider):
        self.client.close()


class MySQLPipeline:
    """
    數據庫名:maoyan
    數據表名:t_maoyan_movie
    mysql需要自己手動創建數據庫和相對應的數據表
    """

    def open_spider(self, spider):
        self.client = connect(host='localhost', port=3306, user='root', password='root', database='maoyan',
                              charset='utf8')
        # 創建游標
        self.cursor = self.client.cursor()

    def process_item(self, item, spider):
        sql = 'insert into t_maoyan_movie values(0,%s,%s) '
        self.cursor.execute(sql, [item['name'], item['grade']])
        self.client.commit()
        return item

    def close_spider(self, spider):
        self.cursor.close()
        self.client.close()

 

 
 4. setting.py中設置配置,想保存哪個數據庫就引入並開啟哪個中間件。也可以兩個一起開啟。setting中如下設置:
from fake_useragent import UserAgent

# 偷懶的寫法,一般自己定義USER-AGENT中間件
USER_AGENT = UserAgent().chrome

ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 3 # 隔三秒爬一次
ITEM_PIPELINES = { 'monogodb.pipelines.MonogodbPipeline': 300, 'monogodb.pipelines.MySQLPipeline': 301, }

 5. 創建mysql數據庫和數據表  注意: python會自動創建mongodb數據庫和對應collection,但mysql需要先手動創建。如果嫌命令創建麻煩,完全可以使用Navicat連接數據庫界面操作。

   1.連接mysql  cmd中 命令: mysql -u root -p root

 2. 創建數據庫: create database  maoyan charser ''utf8    (庫名必須和代碼中庫名一致)

 3.切換到已創建數據庫創建表:user  maoyan  

    4. 創建表

create table t_maoyan_movie (id int primary key auto_increment,name varchar(20), grade varchar(20));

 

 

6. 執行程序插入數據

    創建start.py文件,並執行

from scrapy.cmdline import execute
execute('scrapy crawl maoyan'.split())

 

 也可以在終端中輸入: scrapy crawl maoyan

 7.結果:

     1.mysql中結果

 

 

 

可以看到有90條數據。因為只爬了前三頁,一頁30條。可以在程序中選擇頁數。

mongodb中結果:

打開Robo 3T,  執行 db.getCollection('t_maoyan_movie').find({})

可以看到電影信息啦

 

 

執行  db.getCollection('t_maoyan_movie').find({}).count()

 可以看到依然有90條數據。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM