使用Twisted框架實現非同步儲存資料到MySQL資料庫中
阿新 • • 發佈:2019-02-13
概述
以爬取豆瓣讀書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'