1. 程式人生 > >使用Twisted框架實現非同步儲存資料到MySQL資料庫中

使用Twisted框架實現非同步儲存資料到MySQL資料庫中

概述

以爬取豆瓣讀書Top250排行榜為例。

關鍵是使用Twisted框架的adbapi,建立資料庫連線池物件,然後使用這個資料庫連線池物件進行資料庫操作,
這樣就實現了資料儲存的非同步方案。

核心程式碼如下:
1.使用Twisted中的adbapi獲取資料庫連線池物件。
引數“pymsql”為使用的資料庫引擎名字,params與直接使用pymsql.connect(params)連線資料庫時相同
self.dbpool=adbapi.ConnectionPool('pymysql',**params)
2.使用資料庫連線池物件進行資料庫操作,自動傳遞cursor物件到資料庫操作方法的第一個引數,
query=self.dbpool.runInteraction(self.do_insert,item)


也可以設定出錯時的回撥方法,自動傳遞出錯訊息物件failure到錯誤處理方法的第一個引數
query.addErrback(self.on_error,spider)

程式碼

items.py

class DoubanbookItem(scrapy.Item):
    # 圖書詳情頁連結
    link=scrapy.Field()
    # 圖書名稱
    title=scrapy.Field()
    # 作者,出版資訊,價格等資訊
    info=scrapy.Field()
    # 豆瓣評分
    rating=scrapy.Field()
    # 引論
quote=scrapy.Field()

spider

# !/usr/bin/env python
# -*- coding:utf-8 -*-

import scrapy
from myscrapy.items import DoubanbookItem

class DoubanbookSpider(scrapy.Spider):
    """
    豆瓣讀書Top250爬蟲
        學習使用Twisted非同步框架的功能,實現非同步儲存資料到MySQL資料庫中
    """
    name = 'doubanbook'
    allowed_domains=['book.douban.com'
] def start_requests(self): base_url='https://book.douban.com/top250?start=' offset=0 start_urls=[base_url+str((offset+x)*25) for x in range(10)] for start_url in start_urls: yield scrapy.Request(url=start_url,callback=self.parse) def parse(self, response): tr_nodes=response.xpath('//div[@class="indent"]//tr') for tr_node in tr_nodes: link=tr_node.xpath('.//div[@class="pl2"]/a/@href').extract_first() title=tr_node.xpath('.//div[@class="pl2"]/a/text()').re(r'\w+')[0] info=tr_node.xpath('.//p[@class="pl"]/text()').extract_first() rating=tr_node.xpath('.//span[@class="rating_nums"]/text()').extract_first() quote=tr_node.xpath('.//span[@class="inq"]/text()').extract_first() item=DoubanbookItem() item['link']=link item['title']=title item['info']=info item['rating']=rating item['quote']=quote yield item

pipelines.py

import pymysql
import scrapy
from twisted.enterprise import adbapi

class DoubanbookPipeline(object):
    """
    豆瓣讀書Top250 Item Pipeline
        create table doubanbook250(
            id int primary key auto_increment,
            link varchar(100) not null,
            title varchar(200) not null,
            info varchar(500) not null,
            rating varchar(10) not null,
            quote varchar(200) not null);
    """

    def __init__(self,host,user,password,db):
        params=dict(
            host = host,
            user = user,
            password = password,
            db = db,
            charset = 'utf8',  # 不能用utf-8
            cursorclass = pymysql.cursors.DictCursor
        )
        # 使用Twisted中的adbapi獲取資料庫連線池物件
        self.dbpool=adbapi.ConnectionPool('pymysql',**params)

    @classmethod
    def from_crawler(cls,crawler):
        # 獲取settings檔案中的配置
        host=crawler.settings.get('HOST')
        user=crawler.settings.get('USER')
        password=crawler.settings.get('PASSWORD')
        db=crawler.settings.get('DB')
        return cls(host,user,password,db)

    def process_item(self,item,spider):
        # 使用資料庫連線池物件進行資料庫操作,自動傳遞cursor物件到第一個引數
        query=self.dbpool.runInteraction(self.do_insert,item)
        # 設定出錯時的回撥方法,自動傳遞出錯訊息物件failure到第一個引數
        query.addErrback(self.on_error,spider)
        return item

    def do_insert(self,cursor,item):
        sql='insert into doubanbook250(link,title,info,rating,quote) values(%s,%s,%s,%s,%s)'
        args=(item['link'],item['title'],item['info'],item['rating'],item['quote'])
        cursor.execute(sql,args)

    def on_error(self,failure,spider):
        spider.logger.error(failure)

settings.py

# -*- coding: utf-8 -*-

BOT_NAME = 'myscrapy'

SPIDER_MODULES = ['myscrapy.spiders']
NEWSPIDER_MODULE = 'myscrapy.spiders'

# scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware
# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# 配置下載延時
DOWNLOAD_DELAY = 1

DOWNLOADER_MIDDLEWARES = {
    'myscrapy.middlewares.UserAgentDownloaderMiddleware': 99,
}

ITEM_PIPELINES = {
    'myscrapy.pipelines.DoubanbookPipeline': 300,
}

# MySQL資料庫引數
HOST = 'localhost'
USER = 'root'
PASSWORD = '123456'
DB = 'mydb'

執行結果

這裡寫圖片描述