以爬取豆瓣读书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'