完整实战项目:Python爬虫+Flask,带你创建车标学习网站

有用的数据是哪些? 品牌名称、车标图片、成立时间、主要车型、官网。

那么让我们开始通过爬虫,获取车标网下所有的汽车品牌及车标,最终入库保存吧,开始!

数据库操作指南

针对简单的数据,我习惯用python自带的sqlite3进行数据库的存储,简单方便….那么如何管理我们的数据库呢?推荐使用 DBUtils !

安装:pip install DBUtils

DBUtils is a suite of tools providing solid, persistent and pooled connections to a database that can be used in all kinds of multi-threaded environments like Webware for Python or other web application servers. The suite supports DB-API 2 compliant database interfaces and the classic PyGreSQL interface.

简而言之,DBUtils是一套为数据库提供可靠,持久和池式连接的工具,可用于各种多线程环境。我们一般使用DBUtils.PooledDB来创建一批连接池进行并发处理。常用参数如下:

参数 说明
creator 使用链接数据库的模块(sqllite3、pymysql…)
maxconnections 连接池允许的最大连接数,0和None表示不限制连接数
mincached 初始化时,链接池中至少创建的空闲的链接,0表示不创建
maxcached 链接池中最多闲置的链接,0和None不限制
blocking 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
maxusage 一个链接最多被重复使用的次数,None表示无限制
host ip
user 用户名
password 密码
database 数据库名
charset 字符集(Mysql用的比较多,SQLite没有)

因为之前都是拿DBUtils链接Mysql数据库的,这次默认就直接改成sqlite3,结果简单配置下,封装上常用的方法…一跑程序挂了!Why?
SQLite本身无法应对多个线程并发访问,由一个线程创建并访问的sqlite的数据库,无法允许另外一个线程进行访问,找解决办法呗,最终找到通过设置check_same_thread=False,使SQLite支持多线程并发(但并发的效果很一般)。

# -*- coding: utf-8 -*-
# @Author   : 王翔
# @微信号   : King_Uranus
# @公众号    : 清风Python
# @GitHub   : https://github.com/BreezePython
# @Date     : 2019/12/15 20:27
# @Software : PyCharm
# @version  :Python 3.7.3
# @File     : db_maker.py


import sqlite3
from DBUtils.PooledDB import PooledDB


class DB_Maker:
    def __init__(self):
        self.POOL = PooledDB(
            check_same_thread=False,
            creator=sqlite3,  # 使用链接数据库的模块
            maxconnections=10,  
            mincached=2,  
            maxcached=5,  
            blocking=True,  
            maxusage=None,  
            ping=0,
            database='database.db',
        )
        self.check_db()

    def check_db(self):
        sql = "SELECT name FROM sqlite_master where name=?"
        if not self.fetch_one(sql, ('idiom',)):
            self.create_table()

    def create_table(self):
        print("create table ...")
        sql = """create table idiom (
                        [id]            integer PRIMARY KEY autoincrement,
                        [name]         varchar (10),
                        [speak]      varchar (30),
                        [meaning]      varchar (100),
                        [source]      varchar (100),
                        [example]      varchar (100),
                        [hot]      int(10)
                    )"""
        self.fetch_one(sql)

    def db_conn(self):
        conn = self.POOL.connection()
        cursor = conn.cursor()
        return conn, cursor

    @staticmethod
    def db_close(conn, cursor):
        cursor.close()
        conn.close()

    def fetch_one(self, sql, args=None):
        conn, cursor = self.db_conn
        if not args:
            cursor.execute(sql)
        else:
            cursor.execute(sql, args)
        record = cursor.fetchone()
        self.db_close(conn, cursor)
        return record

    def fetch_all(self, sql, args):
        conn, cursor = self.db_conn
        cursor.execute(sql, args)
        record_list = cursor.fetchall()
        self.db_close(conn, cursor)
        return record_list

    def insert(self, sql, args):
        conn, cursor = self.db_conn
        row = cursor.execute(sql, args)
        conn.commit()
        self.db_close(conn, cursor)

本次有一个知识点,我们需要将车标图片,存储在数据库中,那么如何在数据库中存储图片,使用类型BLOB。举一个简单的数据库图片读写例子

# -*- coding: utf-8 -*-
# @Author   : 王翔
# @微信号   : King_Uranus
# @公众号    : 清风Python
# @GitHub   : https://github.com/BreezePython
# @Date     : 2019/12/15 20:27
# @Software : PyCharm
# @version  :Python 3.7.3
# @File     : show.py

import sqlite3

db = sqlite3.connect('Car.db')
cur = db.cursor()
cur.execute("CREATE TABLE if not exists image_save (image BLOB);")

with open('Audi.jpg', 'rb') as f:
    cur.execute("insert into image_save values(?)", (sqlite3.Binary(f.read()),))
    db.commit()

cur.execute('select image from image_save limit 1')
b = cur.fetchone()[0]

with open('1.jpg', 'wb') as f:
    f.write(b)

我们创建一个image_save的测试表,然后将图片读取为二进制字节的方式,通过 sqlite3.Binary 将二进制文件存储至数据库。
那么同样的,我们将BLOB类型的图片读取出来后,进行写入,即可达到效果,来看看这个1.jpg是否正常:

图片下载小技巧

看过了二进制的存储方式,大家肯定说明白了,网站获取到图片链接然后找着上面的例子下载到本地,然后再进行二进制的读取后存储数据库即可,对吗?不对…有什么问题呢?来看一个例子:

这里Audi图片的链接地址,我们通过requests来下载看看….