美文网首页python
Python爬虫+Flask,带你创建车标学习网站

Python爬虫+Flask,带你创建车标学习网站

作者: 清风Python | 来源:发表于2019-12-16 00:17 被阅读0次
    文化不分边界

    人,为什么要读书?举个例子:
    当看到天边飞鸟,你会说:“落霞与孤鹜齐飞,秋水共长天一色。”而不是:“卧靠,好多鸟。”;
    当你失恋时你低吟浅唱道:“人生若只如初见,何事秋风悲画扇。”而不是千万遍地悲喊:“蓝瘦,香菇!”
    今天回家早,陪俩小爷在楼下遛弯,忽然听见一阵马达轰鸣声,嗖~~闪一辆跑车,大大问;“爸爸,这是什么车啊”我:“红色的车...”,小小说:“爸爸肯定不认识,我也知道是红色的车。”气氛有些冷场...

    别人看车关注牌子,我看车关注宽敞不,睡着舒服不?可不管怎样不能在孩子面前丢份啊,我决定学习学习车标!首先我们爬取车标及其相关信息,然后通过Flask来做一个车标学习网站。

    先来看看实现效果:


    车标学习.gif
    车标网数据爬虫

    在网上找了半天车标的数据,最后看到了这个网站:车标网:http://www.chebiaow.com/logo

    车标网
    网站将车系按照字母从A-Z进行了排序,然后点击每个车标进入详细信息,那Audi做例子:
    奥迪
    有用的数据时哪些?品牌名称、车标图片、成立时间、主要车型、官网。
    那么然我们开始通过爬虫,获取车标网下所有的汽车品牌及车标,最终入库保存吧,开始!
    数据库操作指南

    针对简单的数据,我习惯用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是否正常:

    1.jpg
    图片下载小技巧

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


    Audi图片链接

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

    import requests
    r =requests.get('http://img.chebiaow.com/thumb/cb/allimg/1303/1-1303061Z600520,c_fill,h_138,w_160.jpg')
    r.content
    b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01...'
    

    可以看到我们通过requests.get获取到的content就已经是二进制数据了,为何还要存储成图片,在转化呢?省去了我们保存图片的多余过程。

    网页分析

    针对A-Z的车标排序,网站的url匹配关系很简单:

    from string import ascii_uppercase as au
    # ascii_uppercase代表A-Z,当然你可以不引入模块自己生成也OK...
    for uppercase in au:
        "http://www.chebiaow.com/logo/{}.html".format(au)
    
    品牌获取

    可以看到在包含cb-list方法的ul下匹配所有li中的第一个a标签,然后拼接base_url即可。

    品牌详情

    进入品牌详情界面后,我们针对左右栏目的设置,分别获取所需标红的内容


    品牌详情

    最终存储的数据库如下:

    数据库展示

    由于图片是BLOB类型的二进制文件,所以大家看到的是星星,最终获取网站258份车辆信息(虽然我能认识的不到20种...)
    这个中兴看了半天还以为是搞错了,没想到是同名的...

    万法同源

    一直觉得可能自己不太适合搞技术,更适合在天桥底下支个摊子说书。技术的东西从来没人关注,扯东扯西的文章莫名的火。之前的一篇文章MarkDown添加图片的三种方式不管是在技术为主的CSDN还是娱乐为主的简书,都莫名的火爆,看图:

    markdown添加图片
    其实文章没什么含量,就是介绍了下markdown添加图片的方式,唯一新奇的可能就是使用了base64的图片二进制转化。
    ![avatar]\(data:image/png;base64,iVBORw0......)
    1. 使用python将图片转化为base64字符串
    import base64
    f=open('723.png','rb') #二进制方式打开图文件
    ls_f=base64.b64encode(f.read()) #读取文件内容,转换为base64编码
    f.close()
    print(ls_f)
    
    1. base64字符串转化为图片
    import base64
    bs='iVBORw0KGgoAAAANSUhEUg....' # 太长了省略
    imgdata=base64.b64decode(bs)
    file=open('2.jpg','wb')
    file.write(imgdata)
    file.close()
    

    通过request.get(url).content获取的二进制字符串,直接存储至SQLite数据库的BLOB字段中。如果我们需要显示图片,直接通过open函数的写入数据即可生成原始的图片。但是,如果我不想写入图片,而希望直接展示在web界面上呢?也可以通过markdown添加图片的方式,使用base64的编码来实现!

    Flask展示图片例子

    我们先不通过读取数据库,而是直接获取requests.get(url).content的方式测试Flask的图片展示。
    HTML代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <img src="data:;base64,{{ img }}">
    </body>
    </html>
    

    Flask后台代码:

    # -*- coding: utf-8 -*-
    # @Author   : 王翔
    # @JianShu  : 清风Python
    # @Date     : 2019/7/24 0:25
    # @Software : PyCharm
    # @version  :Python 3.7.3
    # @File     : image_show.py
    
    
    from flask import Flask, render_template
    import base64
    import requests
    
    app = Flask(__name__)
    
    
    @app.route("/show")
    def show_image():
        r = requests.get('http://img.chebiaow.com/thumb/cb/allimg/1303/1-1303061Z600520,c_fill,h_138,w_160.jpg')
        image = base64.b64encode(r.content).decode('ascii')
        return render_template('index.html', img=image)
    
    
    if __name__ == '__main__':
        app.run()
    
    base64展示图片

    图片展示OK,使用这种方式,我们就没必要将图片文件先从数据库中读取生成后,再通过url_for('static',filename='x.png')的方式进行显示了。

    完善车标测试app

    我们就把这些数据库信息配合Flask完成一个简单的车标学习简单网站吧,来看看实现效果:


    车标学习.gif

    后台Flask代码:

    # -*- coding: utf-8 -*-
    # @Author   : 王翔
    # @JianShu  : 清风Python
    # @Date     : 2019/7/25 1:37
    # @Software : PyCharm
    # @version  :Python 3.7.3
    # @File     : app.py
    
    from flask import Flask, render_template, g
    import sqlite3
    import random
    import base64
    
    app = Flask(__name__)
    DATABASE = 'static/db/car.db'
    app.secret_key = 'Breeze Python'
    
    
    def connect_db():
        return sqlite3.connect(DATABASE)
    
    
    @app.before_request
    def before_request():
        g.db = connect_db()
    
    
    @app.teardown_request
    def teardown_request(exception):
        if hasattr(g, 'db'):
            g.db.close()
    
    
    def query_db(query, args=()):
        cur = g.db.execute(query, args)
        rv = [dict((cur.description[idx][0], value)
                   for idx, value in enumerate(row)) for row in cur.fetchall()]
        if not query.startswith('select'):
            g.db.commit()
        return rv[0] if rv else None
    
    
    @app.route('/car')
    @app.route('/')
    def index():
        id = random.randint(1, 141)
        car_info = query_db('select name,image,founded,models,website from car_logo where id={}'.format(id))
        car_info['image'] = base64.b64encode(car_info['image']).decode('ascii')
        print(car_info)
        return render_template('index.html', car=car_info)
    
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=7000)
    
    

    前台HTML代码就不再这里展示了...
    公众号回复车标,下载整套代码及数据库信息。

    The End

    期待你关注我的公众号清风Python,如果你觉得不错,希望能动动手指转发给你身边的朋友们。

    相关文章

      网友评论

        本文标题:Python爬虫+Flask,带你创建车标学习网站

        本文链接:https://www.haomeiwen.com/subject/xsfrnctx.html