python爬虫之爬虫数据持久化保存

爬取豆瓣电影 top250movie.douban.com/top250的电影数据,并保存在数据库中。

1.items.py文件:自定义字段,确定要爬取的目标网站数据

import scrapy
class DoubanItem(scrapy.Item):
# 标题
title = scrapy.Field()
# 是否可播放的状态
playable = scrapy.Field()
# 简介
content = scrapy.Field()
# 评分
star = scrapy.Field()
# 评论数量
commentnum = scrapy.Field()
# 主题
inq = scrapy.Field()

2.spiders/douban.py 文件: 爬虫文件,在这里编写爬虫代码,解析数据,获取新的url

import scrapy
from douban.items import DoubanItem
class DoubanspiderSpider(scrapy.Spider):

name = 'doubanspider'
allowed_domains = ['douban.com']
#可以设置偏移量,也可以提取网站页面源码中下一页
#标签的链接,获取到下一页url地址
offset = 0
url = 'https://movie.douban.com/top250?start='
start_urls = [url + str(offset) + "&filter="]

def parse(self, response):
    itemlist = response.xpath("//div[@class='item']")
    for each in itemlist:
        item = DoubanItem()
        # 标题
        title = each.xpath(".//div[@class='info']/div[@class='hd']//span[@class='title']/text()").extract_first("")
        # 是否可播放的状态
        playable = each.xpath(".//div[@class='info']/div[@class='hd']/span[@class='playable']/text()").extract_first("")
        # 简介
        content = each.xpath(".//div[@class='info']//div[@class='bd']/p/text()").extract()
        content = "".join(content).strip()
        # 评分
        star = each.xpath(".//div[@class='star']//span[@class='rating_num']/text()").extract_first("")
        # 评论数量
        commentnum = each.xpath(".//div[@class='star']/span[4]/text()").extract_first("")
        # 主题
        inq = each.xpath(".//div[@class='info']//div[@class='bd']//span[@class='inq']/text()").extract_first("")

        item['title'] = title
        item['playable'] = playable
        item['content'] = content
        item['star'] = star
        item['commentnum'] = commentnum
        item['inq'] = inq

        yield item

    #下一页(方式一)
    if self.offset < 250:
        self.offset += 25
        yield scrapy.Request(self.url + str(self.offset) +"&filter=",callback= self.parse)

3.数据持久化

方式一:将数据存入mongodb

settings.py文件: 设置文件,在这里设置User-Agent,激活管道文件等...

ITEM_PIPELINES = {
'douban.pipelines.DoubanPipeline': 300,
}

MONGODB 主机名
MONGODB_HOST = '127.0.0.1'
MONGODB 端口号
MONGODB_PORT= 27017
数据库名称
MONGODB_DBNAME = "Douban"
存储数据的表名称
MONGODB_SHEETNAME= "doubanmovies"

4.pipelines.py管道:这里进行数据的清洗和持久化

import pymongo
from scrapy.conf import settings

class DoubanPipeline(object):

# 将数据存储在mongodb中
def __init__(self,host,port,dbname,sheetname):
    # 创建MONGODB数据库链接
    client = pymongo.MongoClient(host=host, port=port)
    # 指定数据库
    mydb = client[dbname]
    # 存放数据的集合名称
    self.mysheet = mydb[sheetname]

@classmethod
def from_crawler(cls, crawler):
    host = crawler.settings["MONGODB_HOST"]
    port = crawler.settings["MONGODB_PORT"]
    dbname = crawler.settings["MONGODB_DBNAME"]
    sheetname = crawler.settings["MONGODB_SHEETNAME"]

    return cls(host,port,dbname,sheetname)

def process_item(self,item,spider):
    data = dict(item)
    # mongodb数据插入语句,使用save保存数据的效率会很慢,因为它需要循环便利,操作费时
    self.mysheet.insert(data)
    return item

方式二:将数据存入mysql数据库

settings.py文件: 设置文件,在这里设置User-Agent,激活管道文件等...

ITEM_PIPELINES = {
'douban.pipelines.DoubanPipeline': 300,
}

#关于数据库的相关配置
MYSQL_HOST = '127.0.0.1'
MYSQL_PORT = 3306
MYSQL_USER = ''
MYSQL_PWD = ''
MYSQL_DB = ''

pipelines.py管道文件

import pymysql
class DoubanPipeline(object):

#     将数据存储值mysql数据库
#     _mysql_exceptions.OperationalError: (1366, 是因为数据库中的字符集与charset="utf8"不符合

def __init__(self,host,port,user,pwd,db,charset):
    self.client = pymysql.Connect(host,user,pwd,db,port,charset='utf8')
    self.cursor = self.client.cursor()

@classmethod
def from_crawler(cls,crawler):
    host = crawler.settings['MYSQL_HOST']
    port = crawler.settings['MYSQL_PORT']
    user = crawler.settings['MYSQL_USER']
    pwd = crawler.settings['MYSQL_PWD']
    db = crawler.settings['MYSQL_DB']

    return cls(host,port,user,pwd,db,charset)

def process_item(self,item,spider):
    insert_sql = """
           insert into doubanmovie(title, playable, content, star, commentnum, inq)
           VALUE (%s, %s, %s, %s, %s, %s)
    """
    try:
        self.cursor.execute(insert_sql, (item['title'],  item['content'], item['score'], item['info']))
        self.client.commit()
    except Exception as err:
        print(err)
        self.client.rollback()
    return item

5.思考???: 在pipeline中我们进行数据插入,如何解耦?

将sql语句和要插入的数据在item中定义一个方法返回,通过item调用,然后返回

class XxxxItem(scrapy.Item):

#名称
title = scrapy.Field()

def insert_data_to_db(self,dataDict):
    sql = """
    INSERT INTO caipu (%s)
    VALUES (%s)
    """ % (','.join(dataDict.keys()),','.join(['%s']*len(dataDict)))

    data = list(dataDict.values())

    return sql,data

mysql数据异步插入

settings.py配置文件

#将mysql相关信息写在settings中
MYSQL_HOST = '127.0.0.1'
MYSQL_ROOT = '数据库用户名'
MYSQL_PASSWORD = '数据库密码'
MYSQL_DBNAME = 'DouBan'

6.异步插入数据库

import pymysql
#twisted是一个异步的网络框架,这里可以帮助我们
实现异步将数据插入数据库
#adbapi里面的子线程会去执行数据库的阻塞操作,
当一个线程执行完毕之后,同时,原始线程能继续
进行正常的工作,服务其他请求。

from twisted.enterprise import adbapi

#异步插入数据库
class DoubanPipeline(object):

def __init__(self,dbpool):
    self.dbpool = dbpool

#使用这个函数来应用settings配置文件。
@classmethod
def from_crawler(cls, crawler):
    parmas = {
    'host':crawler.settings['MYSQL_HOST'],
    'user':crawler.settings['MYSQL_USER'],
    'passwd':crawler.settings['MYSQL_PASSWD'],
    'db':crawler.settings['MYSQL_DB'],
    'port':3306,
    'charset':'utf8',
    }

    # **表示字典,*tuple元组,
    # 使用ConnectionPool,起始最后返回的是一个ThreadPool
    dbpool = adbapi.ConnectionPool(
        'pymysql',
        **parmas
    )
    return cls(dbpool)

def process_item(self, item, spider):
    #这里去调用任务分配的方法
    query = self.dbpool.runInteraction(
        self.insert_data_todb,
        item,
        spider
    )
    #数据插入失败的回调
    query.addErrback(
        self.handle_error,
        item
    )

    #执行数据插入的函数
    def insert_data_todb(self,cursor,item,spider):
        insert_str,parmas = item.insertdata()
        cursor.execute(insert_str,parmas)
        print('插入成功')

def handle_error(self,failure,item):
    print(failure)
    print('插入错误')
    #在这里执行你想要的操作

def close_spider(self, spider):
    self.pool.close()

7.MySQL 解决批量插入数据去重问题(自学) https://blog.csdn.net/zp_00000/article/details/81042589

你可能感兴趣的:(python爬虫之爬虫数据持久化保存)