完整实战项目: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来下载看看….