# Python3 爬虫学习笔记 C10

TRHX

2019-09-03

Python3 学习笔记 / 爬虫学习

字数统计:

2,566字

阅读时长≈

12分

> Python3 爬虫学习笔记第十章 —— 【MySQL数据储存】

# 【10.1】MySQL 基本操作语句

安装完 MySQL 后，打开 MySQL x.x Command Line Client - Unicode，输入密码即可登录 MySQL，也可在 MySQL 安装目录下打开 cmd 使用命令登录数据库

## 数据库操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    # 连接数据库
    mysql -u root -p

    # 退出数据库
    exit

    # 查看所有的数据库
    SHOW DATABASES;

    # 创建一个数据库
    CREATE DATABASE X;

    # 删除一个数据库
    DROP DATABASE IF EXISTS X;

    # 使用这个数据库
    USE X;

## 表操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37

    # 查看所有的表
    SHOW TABLES ;

    # 创建一个表
    CREATE TABLE n(id INT, name VARCHAR(10));
    CREATE TABLE m(id INT, name VARCHAR(10), PRIMARY KEY (id), FOREIGN KEY (id) REFERENCES n(id), UNIQUE (name));
    CREATE TABLE m(id INT, name VARCHAR(10));

    # 直接将查询结果导入或复制到新创建的表
    CREATE TABLE n SELECT * FROM m;

    # 新创建的表与一个存在的表的数据结构类似
    CREATE TABLE m LIKE n;

    # 创建一个临时表
    # 临时表将在你连接MySQL期间存在。当断开连接时，MySQL将自动删除表并释放所用的空间。也可手动删除。
    CREATE TEMPORARY TABLE l(id INT, name VARCHAR(10));

    # 直接将查询结果导入或复制到新创建的临时表
    CREATE TEMPORARY TABLE tt SELECT * FROM n;

    # 删除一个存在表
    DROP TABLE IF EXISTS m;

    # 更改存在表的名称
    ALTER TABLE n RENAME m;
    RENAME TABLE n TO m;

    # 查看表的结构(以下五条语句效果相同）
    DESC n;
    DESCRIBE n;
    SHOW COLUMNS IN n;
    SHOW COLUMNS FROM n;
    EXPLAIN n;

    # 查看表的创建语句
    SHOW CREATE TABLE n;

## 表的结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    # 添加字段
    ALTER TABLE n ADD age VARCHAR(2);

    # 添加字段时设定位置
    ALTER TABLE n ADD age VARCHAR(2)  FIRST;
    ALTER TABLE n ADD age VARCHAR(2)  AFTER name;

    # 修改字段在表中的位置
    ALTER TABLE n MODIFY age VARCHAR(2) AFTER name;

    # 删除字段
    ALTER TABLE n DROP age;

    # 更改字段属性和属性
    ALTER TABLE n CHANGE age a INT;

    # 只更改字段属性
    ALTER TABLE n MODIFY age VARCHAR(7) ;

    # 改变表的存储引擎
    ALTER TABLE t ENGINE myisam;
    ALTER TABLE t ENGINE innodb;

    # 设定自增 初始为1，只能一个字段使用，该字段为主键的一部分
    ALTER TABLE t AUTO_INCREMENT = 0;

## 表的数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    # 增加数据
    INSERT INTO n VALUES (1, 'tom', '23'), (2, 'john', '22');
    INSERT INTO n SELECT * FROM n;  # 把数据复制一遍重新插入

    # 删除数据
    DELETE FROM n WHERE id = 2;

    # 更改数据
    UPDATE n SET name = 'tom' WHERE id = 2;

    # 数据查找
    SELECT * FROM n WHERE name LIKE '%h%';

    # 数据排序(反序)
    SELECT * FROM n ORDER BY name, id DESC ;

# 【10.2】Python 连接 MySQL

    1
    2
    3
    4
    5
    6
    7
    8
    9

    import pymysql

    db = pymysql.connect(host='localhost', user='root', password='000000', port=3306)
    cursor = db.cursor()
    cursor.execute('SELECT VERSION()')
    data = cursor.fetchone()
    print('Database version:', data)
    cursor.execute("CREATE DATABASE spiders DEFAULT CHARACTER SET utf8mb4")
    db.close()

通过 PyMySQL 的 connect 方法声明一个 MySQL 连接对象 db，当前 MySQL 数据库运行在本地，设定 `host='localhost'`，用户名为 `root`，登录密码为 `000000`，运行在 `3306` 端口，调用 `cursor()` 方法获得 MySQL 的操作游标，该游标用来执行 SQL 语句，通过游标操作 `execute()` 方法写入 SQL 语句，第一条 SQL 语句获取 MySQL 的版本信息，调用 `fetchone()` 方法获得第一条数据，即 MySQL 的版本号。第二条 SQL 语句执行创建 spiders 数据库的操作，编码为 utf8mb4，运行该段代码将输出 MySQL 的版本号：

    1

    Database version: ('8.0.17',)

# 【10.3】创建表

    1
    2
    3
    4
    5
    6
    7

    import pymysql

    db = pymysql.connect(host='localhost', user='root', password='000000', port=3306, db='spiders')
    cursor = db.cursor()
    sql = 'CREATE TABLE IF NOT EXISTS students (id VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, age VARCHAR(255) NOT NULL, PRIMARY KEY (id))'
    cursor.execute(sql)
    db.close()

该段代码实现了在 spiders 数据库里创建了一个名为 students 的表，包含 id、name、age 三个字段，类型依次为 varchar、varchar、int

# 【10.4】插入数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    import pymysql

    id = '17110105'
    user = 'TRH'
    age = 20
    db = pymysql.connect(host='localhost', user='root', password='000000', port=3306, db='spiders')
    cursor = db.cursor()
    sql = 'INSERT INTO students(id, name, age) values(%s, %s, %s)'
    try:
        cursor.execute(sql, (id, user, age))
        db.commit()
    except:
        db.rollback()
    db.close()

`commit()` 方法的作用是实现数据插入，是真正将语句提交到数据库执行的方法，使用 `try except` 语句实现异常处理，如果执行失败，则调用 `rollback()` 方法执行数据回滚，保证原数据不被破坏，使用查询语句可以看到已经插入的数据：

<fancybox>
</fancybox>

进阶操作：将需要插入的数据构造成一个字典，这样的做法可以让插入方法无需改动，只需要传入一个动态变化的字典就行了，改写原来的代码如下：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    import pymysql

    data = {
        'id': '17110105',
        'name': 'TRH',
        'age': 20
    }
    table = 'students'
    keys = ', '.join(data.keys())
    values = ', '.join(['%s']*len(data))
    db = pymysql.connect(host='localhost', user='root', password='000000', port=3306, db='spiders')
    cursor = db.cursor()
    sql = 'INSERT INTO {table}({keys}) VALUES ({values})'.format(table=table, keys=keys, values=values)
    try:
        cursor.execute(sql, tuple(data.values()))
        print('数据插入成功！')
        db.commit()
    except:
        print('数据插入失败！')
        db.rollback()
    db.close()

传入的数是字典，将其定义为 data 变量，表名定义成变量 table，构造插入的字段 id、name 和 age。`', '.join(data.keys())` 的结果就是 id, name, age，接着需要构造多个 `%s` 当作占位符，有三个字段，就需要构造 `%s, %s, %s`。首先定义长度为 1 的数组 `['%s']`，然后用乘法将其扩充为 `['%s', '%s', '%s']`，再调用 `join()` 方法，最终变成 `%s, %s, %s`。再利用字符串的 `format()` 方法将表名、字段名和占位符构造出来。最终的 SQL 语句就被动态构造成了如下语句：

    1

    INSERT INTO students(id, name, age) VALUES (%s, %s, %s)

# 【10.5】更新数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    import pymysql

    data = {
        'id': '17110105',
        'name': 'TRH',
        'age': 21
    }
    table = 'students'
    keys = ', '.join(data.keys())
    values = ', '.join(['%s']*len(data))
    db = pymysql.connect(host='localhost', user='root', password='000000', port=3306, db='spiders')
    cursor = db.cursor()
    sql = 'INSERT INTO {table}({keys}) VALUES ({values}) ON DUPLICATE KEY UPDATE'.format(table=table, keys=keys, values=values)
    update = ','.join(["{key} = % s".format(key=key) for key in data])
    sql += update
    try:
        if cursor.execute(sql, tuple(data.values())*2):
            print('数据插入成功！')
            db.commit()
    except:
        print('数据插入失败！')
        db.rollback()
    db.close()

`ON DUPLICATE KEY UPDATE` 表示如果主键已经存在，就执行更新操作，最终被构造成如下语句：

    1

    INSERT INTO students(id, name, age) VALUES (% s, % s, % s) ON DUPLICATE KEY UPDATE id = % s, name = % s, age = % s

# 【10.6】删除数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    import pymysql

    table = 'students'
    condition = 'age = 20'
    db = pymysql.connect(host='localhost', user='root', password='000000', port=3306, db='spiders')
    cursor = db.cursor()
    sql = 'DELETE FROM  {table} WHERE {condition}'.format(table=table, condition=condition)
    try:
        cursor.execute(sql)
        print('数据删除成功！')
        db.commit()
    except:
        print('数据删除失败！')
        db.rollback()
    db.close()

删除操作直接使用 `DELETE` 语句，指定要删除的目标表名和删除条件即可

# 【10.7】查询数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    import pymysql

    table = 'students'
    db = pymysql.connect(host='localhost', user='root', password='000000', port=3306, db='spiders')
    cursor = db.cursor()
    sql = 'SELECT * FROM students WHERE age >= 20'
    try:
        cursor.execute(sql)
        print('Count:', cursor.rowcount)
        one = cursor.fetchone()
        print('One:', one)
        results = cursor.fetchall()
        print('Results:', results)
        print('Results Type:', type(results))
        for row in results:
            print(row)
    except:
        print('查询失败！')

`sql = 'SELECT * FROM students WHERE age >= 20'`：构造一条 SQL 语句，将年龄 大于等于20 岁的学生查询出来

`cursor.rowcount`：调用 cursor 的 rowcount 属性获取查询结果的条数

`cursor.fetchone()`：调用 cursor 的 fetchone() 方法，获取结果的第一条数据，返回结果是元组形式，元组的元素顺序跟字段一一对应，即第一个元素就是第一个字段 id，第二个元素就是第二个字段 name，以此类推

`cursor.fetchall()`：调用 cursor 的 fetchall() 方法，得到结果的所有数据，它是二重元组，每个元素都是一条记录，本例中显示的是 3 条数据而不是 4 条，这是因为它的内部实现有一个偏移指针用来指向查询结果，最开始偏移指针指向第一条数据，取一次之后，指针偏移到下一条数据，这样再取的话，就会取到下一条数据了。我们最初调用了一次 fetchone 方法，这样结果的偏移指针就指向下一条数据，fetchall 方法返回的是偏移指针指向的数据一直到结束的所有数据，所以该方法获取的结果就只剩 3 个了

# 【10.8】实战训练 — 爬取CSDN博客标题和地址保存到 MySQL

利用 requests 库构建请求，BeautifulSoup 解析库解析网页，获取自己博客文章的标题和地址，将其储存到本地 MySQL 数据库中，事先已经创建好了一个 blog 数据库，并创建了一个名为 article 的数据表，数据表包含 id、title、url 三个字段，其中 id 的 `AUTO_INCREMENT` 属性可以使 id 自己增加，`PRIMARY KEY` 关键字用于将 id 定义为主键

创建 article 数据表：

    1
    2
    3
    4
    5
    6
    7

    import pymysql

    db = pymysql.connect(host='localhost', user='root', password='000000', port=3306, db='blog')
    cursor = db.cursor()
    sql = 'CREATE TABLE IF NOT EXISTS article (id INT NOT NULL AUTO_INCREMENT, title VARCHAR(255) NOT NULL, url VARCHAR(255) NOT NULL, PRIMARY KEY (id))'
    cursor.execute(sql)
    db.close()

获取文章标题和对应的 URL 并将其储存到 MySQL 中：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    import requests
    import pymysql
    from bs4 import BeautifulSoup

    db = pymysql.connect(host='localhost', user='root', password='000000', port=3306, db='blog')
    cursor = db.cursor()

    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',
    }
    url = "https://blog.csdn.net/qq_36759224"

    request = requests.get(url, headers=headers)
    soup = BeautifulSoup(request.text, 'lxml')
    title_list = soup.find_all('h4')
    for list in title_list:
        s = list.a.text.strip()
        title = s.replace('原', '')
        url = list.a['href'].strip()
        # print(title + url)
        cursor.execute('INSERT INTO article (title, url) VALUES (%s, %s)', (title, url))
    db.commit()
    print('数据写入完毕！')
    db.close()

在命令行中使用 `SELECT * FROM article;` 命令可以查看到数据已经成功获取并储存到了数据库中：

<fancybox>
</fancybox>

您的喜欢是作者写作最大的动力！❤️

- PayPal
- AliPay
- WeChatPay
- QQPay

Donate

最后更新于 2020年3月14日

爬虫

MySQL

###### 上一页

#### Python3 爬虫学习笔记 C11

###### 爬虫 MongoDB

###### 下一页

#### Python3 爬虫学习笔记 C09

###### 爬虫 文件储存

#### 评论

## ๑۩ﺴ TRHX ﺴ۩๑

本文目录
欢迎光临

Hexo QQ 交流群 Telegram 交流群

CSDN 内容合伙人

文章分类

- BLOG
  (4)
- CDN
  (1)
- Hexo
  (9)
- Java
  (1)
- Linux
  (2)
- Markdown
  (2)
- Python 数据分析
  (27)
- Matplotlib
  (11)
- NumPy
  (6)
- Pandas
  (10)
- Python3 学习笔记
  (41)
- 基础学习
  (9)
- 学习经验
  (4)
- 爬虫学习
  (18)
- 爬虫实战
  (10)
- VPS
  (1)
- WEB前端
  (2)
- 图床
  (1)

热门标签
12306 3D图 58同城 Ajax BLOG Beautiful Soup CDN Coding Pages DataFrame Deepin Elicpse GitHub Pages Github Github Pages GroupBy HTTPS Hexo ICP备案 IO操作 Index JDBC JS 预加载 LaTeX Markdown Material X Matplotlib MongoDB MySQL NumPy PEP8 Pandas PicGo Pygame Python Redis SEO SQL Server 2012 SSR Selenium Series Ubuntu User-Agent VMware VPS XPath if语句 input()函数 instant.page jsDelivr lxml matplotibrc pyspider requests spfk urllib while循环 主题个性化 代理 位运算 公安备案 函数 函数应用 分割 切片 列表 判断函数 前程无忧 变量 合并数据集 哔哩哔哩 图例 图床 图形验证码 垃圾 备份 子图 字典 字符串函数 安居客 层级索引 年终总结 广播 异常 技巧 拼接 排序 排序函数 操作列表 散点图 数学函数 数据分裂 数据可视化 数据合并 数据替换 数据类型 数据读写 数据重塑 数组 文件 文件储存 无界面浏览器 时间序列 映射 条件函数 条形图 极区图 极坐标图 柱状图 模块 正则表达式 滑动验证码 点触验证码 爬虫 猫眼电影 瓜子二手车 画布 直方图 矩阵 等值线图 等高线图 算术函数 算术运算 类 索引 线性代数 线性图 统计函数 统计描述 统计计算 继承 编辑器 缺失值 网格 肺炎疫情 虎扑论坛 补丁 豆瓣电影 迭代 雷达图 饼状图
最近在听