1. 程式人生 > >scrapy爬取海量資料並儲存在MongoDB和MySQL資料庫中

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條資料。

 

 

 

 

                                            &nbs