一、前言

    因为本人比较菜,在学习Scrapy 框架之前都是自己手写爬虫,最多也只是开线程解决,最多的数据量也只有2W+, 

     先说下我以前怎么解决多线程数据库存储到本地(受到倍增启发),因为数据量比较小,没使用数据库,而是生成的excel表格

                  解决办法 一:写个全局锁,如果有人在写入,那么他就暂停,等待一下,然后再次访问.(后来学了计网,想再加上个二进制指针退避算法23333)

                 解决办法二:让他们在不同的时间段写入文件

                            如何保存这种情况呢,倍增的思想,首先将需要爬取的页面分为n,n*2, n*3,n*4,n*5.....。保证一个n 的时间大于文件写入的时间即可。这样每个n 的时间都有一个线程在写入,并且不会冲突(后来发现python 的线程是伪线程233333)

   因为数据量比较小,做了有了部分优化,开启,然后处理下其他的事情也就爬完了。但是还是不够!

二、使用Scrapy框架,异步存储到数据库中

      因为数据库有个唯一的主键,所以直接异步会出现问题。

  我们需要在paplines里面设置存储方:


使用 adbapi 数据库池 解决


代码如下有注释:

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

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

import pymysql
from twisted.enterprise import adbapi

class ScdemoPipeline(object):
    """
    这里是用来处理数据的
    """
    datalies = []

    def __init__(self, dbpool):
        print("*" * 80)
        self.dbpool = dbpool

    @classmethod
    def from_settings(cls, settings):
        # 连接数据库池 
        dbpool = adbapi.ConnectionPool('pymysql', host="localhost", port=3306, user="root", passwd="数据库密码",
                                       db="python_database")
        return cls(dbpool)

    def process_item(self, item, spider):
        # 在该函数内,利用连接池对象,开始操作数据,将数据写入到数据库中。
        # pool.map(self.insert_db, [1,2,3])
        # 同步阻塞的方式: cursor.execute() commit()
        # 异步非阻塞的方式
        # 参数1:在异步任务中要执行的函数insert_db;
        # 参数2:给该函数insert_db传递的参数
        query = self.dbpool.runInteraction(self.insert_db, item)

        # 如果异步任务执行失败的话,可以通过ErrBack()进行监听, 给insert_db添加一个执行失败的回调事件
        query.addErrback(self.handle_error)
        return item

    def handle_error(self, field):
        print('-----数据库写入失败:', field)

    def insert_db(self, cursor, item):
        insert_sql = "INSERT INTO `python_database`.`lecture` (`lecture_url`, `lecture_time`, `lecture_name`, " \
                     "`man`, `place`, `time`) " \
                     "VALUES (%s, %s, %s, %s, %s, %s)"
        cursor.execute(insert_sql,
                       (item["link"], item["lutime"], item["luname"], item["man"], item["place"], item["time"]))

 

 总算把以前没解决的问题解决了。

不过数据库池还需要深入,还有个玩意叫:线程池等我。