scrapy爬蟲成長日記之將抓取內容寫入mysql數據庫

 前面小試了一下scrapy抓取博客園的博客(您可在此查看scrapy爬蟲成長日記之建立工程-抽取數據-保存爲json格式的數據),可是前面抓取的數據時保存爲json格式的文本文件中的。這很顯然不知足咱們平常的實際應用,接下來看下如何將抓取的內容保存在常見的mysql數據庫中吧。html

  說明:全部的操做都是在「scrapy爬蟲成長日記之建立工程-抽取數據-保存爲json格式的數據」的基礎上完成,若是您錯過了這篇文章能夠移步這裏查看scrapy爬蟲成長日記之建立工程-抽取數據-保存爲json格式的數據python

  環境:mysql5.1.67-logmysql

  操做步驟:linux

  一、檢查python是否支持mysqlgit

[root@bogon ~]# python
Python 2.7.10 (default, Jun  5 2015, 17:56:24) 
[GCC 4.4.4 20100726 (Red Hat 4.4.4-13)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named MySQLdb

 

  若是出現:ImportError: No module named MySQLdb則說明python還沒有支持mysql,須要手工安裝,請參考步驟2;若是沒有報錯,請調到步驟3github

  二、python安裝mysql支持sql

[root@bogon ~]# pip install mysql-python
Collecting mysql-python
  Downloading MySQL-python-1.2.5.zip (108kB)
    100% |████████████████████████████████| 110kB 115kB/s 
Building wheels for collected packages: mysql-python
  Running setup.py bdist_wheel for mysql-python
  Stored in directory: /root/.cache/pip/wheels/8c/0d/11/d654cad764b92636ce047897dd2b9e1b0cd76c22f813c5851a
Successfully built mysql-python
Installing collected packages: mysql-python
Successfully installed mysql-python-1.2.5

 

  安裝完之後再次運行步驟1,檢查python是否已經支持mysql數據庫

  若是還有問題您能夠嘗試:LC_ALL=C pip install mysql-python
  若是依然報錯:error: Python.h: No such file or directory
  您能夠嘗試先安裝python-devel:json

yum install python-devel

 

  三、建立數據庫和表api

CREATE DATABASE cnblogsdb DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE TABLE `cnblogsinfo` (
  `linkmd5id` char(32) NOT NULL COMMENT 'url md5編碼id',
  `title` text COMMENT '標題',
  `description` text COMMENT '描述',
  `link` text  COMMENT 'url連接',
  `listUrl` text  COMMENT '分頁url連接',
  `updated` datetime DEFAULT NULL  COMMENT '最後更新時間',
  PRIMARY KEY (`linkmd5id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

 

   注意:

    a)、建立數據庫的時候加上DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci,這樣纔不至於出現亂碼。我就由於這個問題折騰了好久。

    b)、數據庫表的編碼爲utf8

  四、設置mysql配置信息

  根據前面的文章(scrapy爬蟲成長日記之建立工程-抽取數據-保存爲json格式的數據)咱們能夠知道,最終scrapy是經過pipelines.py對抓取的結果進行處理的。很顯然要保存到mysql數據庫中的話,修改pipelines.py這個文件是在所不免的了。然而在進行mysql操做的時候,咱們須要先連上數據庫,這時候就設計到數據庫鏈接字符串的問題了。咱們能夠直接寫死在pipelines.py文件中,可是這樣又不利於程序的維護,所以咱們能夠考慮將配置信息寫在項目的配置文件settings.py中。

  settings.py中添加以下配置項

# start MySQL database configure setting
MYSQL_HOST = 'localhost'
MYSQL_DBNAME = 'cnblogsdb'
MYSQL_USER = 'root'
MYSQL_PASSWD = 'root'
# end of MySQL database configure setting

   五、修改pipelines.py

  修改完的結果以下,須要注意的pipelines.py中定義了兩個類。JsonWithEncodingCnblogsPipeline是寫入json文件用的,而MySQLStoreCnblogsPipeline(須要記住,後面會用到哦!)纔是寫入數據庫用的。

  MySQLStoreCnblogsPipeline類作的主要功能有

    a)、讀取數據庫配置文件,並生成數據庫實例,主要經過類方法from_settings實現,

    b)、若是url不存在則直接寫入,若是url存在則更新,經過自定義的方法_do_upinsert實現,

    c)、確保url惟一性的md5函數_get_linkmd5id 。

[root@bogon cnblogs]# more pipelines.py
# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html

from scrapy import signals
import json
import codecs
from twisted.enterprise import adbapi
from datetime import datetime
from hashlib import md5
import MySQLdb
import MySQLdb.cursors

class JsonWithEncodingCnblogsPipeline(object):
    def __init__(self):
        self.file = codecs.open('cnblogs.json', 'w', encoding='utf-8')
    def process_item(self, item, spider):
        line = json.dumps(dict(item), ensure_ascii=False) + "\n"
        self.file.write(line)
        return item
    def spider_closed(self, spider):
        self.file.close()

class MySQLStoreCnblogsPipeline(object):
    def __init__(self, dbpool):
        self.dbpool = dbpool
    
    @classmethod
    def from_settings(cls, settings):
        dbargs = dict(
            host=settings['MYSQL_HOST'],
            db=settings['MYSQL_DBNAME'],
            user=settings['MYSQL_USER'],
            passwd=settings['MYSQL_PASSWD'],
            charset='utf8',
            cursorclass = MySQLdb.cursors.DictCursor,
            use_unicode= True,
        )
        dbpool = adbapi.ConnectionPool('MySQLdb', **dbargs)
        return cls(dbpool)

    #pipeline默認調用
    def process_item(self, item, spider):
        d = self.dbpool.runInteraction(self._do_upinsert, item, spider)
        d.addErrback(self._handle_error, item, spider)
        d.addBoth(lambda _: item)
        return d
    #將每行更新或寫入數據庫中
    def _do_upinsert(self, conn, item, spider):
        linkmd5id = self._get_linkmd5id(item)
        #print linkmd5id
        now = datetime.utcnow().replace(microsecond=0).isoformat(' ')
        conn.execute("""
                select 1 from cnblogsinfo where linkmd5id = %s
        """, (linkmd5id, ))
        ret = conn.fetchone()

        if ret:
            conn.execute("""
                update cnblogsinfo set title = %s, description = %s, link = %s, listUrl = %s, updated = %s where linkmd5id = %s
            """, (item['title'], item['desc'], item['link'], item['listUrl'], now, linkmd5id))
            #print """
            #    update cnblogsinfo set title = %s, description = %s, link = %s, listUrl = %s, updated = %s where linkmd5id = %s
            #""", (item['title'], item['desc'], item['link'], item['listUrl'], now, linkmd5id)
        else:
            conn.execute("""
                insert into cnblogsinfo(linkmd5id, title, description, link, listUrl, updated) 
                values(%s, %s, %s, %s, %s, %s)
            """, (linkmd5id, item['title'], item['desc'], item['link'], item['listUrl'], now))
            #print """
            #    insert into cnblogsinfo(linkmd5id, title, description, link, listUrl, updated)
            #    values(%s, %s, %s, %s, %s, %s)
            #""", (linkmd5id, item['title'], item['desc'], item['link'], item['listUrl'], now)
    #獲取url的md5編碼
    def _get_linkmd5id(self, item):
        #url進行md5處理,爲避免重複採集設計
        return md5(item['link']).hexdigest()
    #異常處理
    def _handle_error(self, failue, item, spider):
        log.err(failure)

 

   六、啓用MySQLStoreCnblogsPipeline類,讓它工做起來

  修改setting.py配置文件,添加MySQLStoreCnblogsPipeline的支持

ITEM_PIPELINES = {
    'cnblogs.pipelines.JsonWithEncodingCnblogsPipeline': 300,
    'cnblogs.pipelines.MySQLStoreCnblogsPipeline': 300,
}

  至此,全部的須要修改的文件都修改好了,下面測試看結果如何。

  七、測試

[root@bogon cnblogs]# scrapy crawl CnblogsSpider

  查看數據庫結果:

  至此,scrapy抓取網頁內容寫入數據庫的功能就已經實現了。然而這個爬蟲的功能還太弱小了,最基本的文件下載、分佈式抓取等都功能都還不具有;同時也試想一下如今不少網站的反爬蟲抓取的,萬一碰到這樣的網站咱們要怎麼處理呢?接下來的一段時間裏咱們來逐一解決這些問題吧。隨便暢想一下,若是爬蟲足夠強,內容足夠多;咱們是否是能夠打造一個屬於本身的垂直搜索引擎呢?想一想就興奮,盡情YY去吧!!!

  最後源碼更新至此:https://github.com/jackgitgz/CnblogsSpider

http://www.w2bc.com/Article/44862

相關文章
相關標籤/搜索