《Python核心编程》之数据库编程快速入门与项目实战

数据库存储是一种持久化存储,因此先从持久化存储说起吧。

1.持久化存储

(1).在任何应用中,都需要持久化存储。一般有3种基础的存储机制:文件、数据库系统和一些混合类型。这种混合类型包括现有现有系统上的API、ORM、文件管理器、电子表格、配置文件等。
(2).文件或简单的持久化存储可以满足一些小应用的需求,而大型数据库或高数据容量的应用则需要更加成熟的数据库系统。

2.数据库基本操作和SQL

(1).数据库的底层存储
数据库通常使用文件系统作为基本的持久化存储,它可以是普通的操作系统文件、专用的操作系统文件,甚至是原始的磁盘分区。
(2).用户接口
大多数数据库系统提供了命令行工具,可以用其执行SQL语句或查询。此外,还有一些GUI工具,使用命令行客户端或数据库客户端库,向用户提供更加便捷的界面。
(3).模式
数据库存储可以抽象为一张表。每行字段都有一些字段对应于数据库的列。每一列的表定义的集合以及每个表的数据类型放到一起定义了数据库的模式。
(4).SQL
数据库命令和查询操作是通过SQL语句提交给数据库的。虽然并非所有数据库都使用SQL,但是大多数关系数据库使用。注意,大部分数据库都是不区分大小写的,尤其是针对数据库命令而言。一般来说,对数据库关键字使用大写字母是最为广泛接受的风格。
SQL操作包括:
[1].对数据库的操作(CREATE, DROP)
[2].对表的操作(CREATE,DROP)
[3].对表中数据字段的操作(INSERT, DELETE, UPDATE, SELECT)
[4].对权限进行分配(GRANT)

3.数据库和Python

访问数据库包括直接通过数据库接口访问和使用ORM访问两种方式。其中,使用ORM访问的方式不需要显示给出SQL命令,但也能完成相同的任务。
在Python中,数据库是通过适配器的方式进行访问的。适配器是一个Python模块,使用它可以与关系数据库的客户端库(通常用C语言编写)接口相连。一般情况下,会推荐所有的Python适配器应当符合Python数据库兴趣小组的API标准。

4.Python的DB-API
目的是,为不同的关系数据库提供一致性的接口,使不同数据库间移植代码变得更加简单。
DB-API标准要求必须提供下文列出的功能和属性。一个兼容DB-API的模块必须定义apilevel、threadsafety、paramstyle和connect()四个全局属性。

模块属性
(1).数据属性
【1】apilevel:该字符串(注意,不是浮点型)指明了模块需要兼容的DB-API最高版本,比如,1.0、2.0等。
【2】threadsafety:这是一个整型值,可选值如下:
0:不支持线程安全。线程间不能共享模块。
1:最小化线程安全支持:线程间可以共享模块,但是不能共享连接。
2:适度的线程安全支持:线程间可以共享模块和连接,但是不能共享游标。
3:完整的线程安全支持:线程间可以共享模块、连接和游标。
【3】paramstyle:DB-API支持以不同的方式指明如何将参数与SQL语句进行整合,并最终传递给服务器中执行。该参数是一个字符串,用于指定构建查询行或命令时使用的字符串替代形式。
数据库参数风格paramstyle有:
numeric            数值位置风格            WHERE name=:1
named            命名风格                WHERE name=:name
pyformat        Python字典printf()格式转换    WHERE name=%(name)s
qmark            问号风格                WHERE name=?
format             ANSIC的printf()格式转换        WHERE name=%s

(2).函数属性
兼容模块必须实现connect()函数,该函数创建并返回一个Connection对象。下面是connect()的参数。
user        用户名
password    密码
host        主机名
database    数据库名
dsn            数据源名
可以使用包含多个参数的字符串(DSN)来传递数据库连接信息,也可以按照位置传递每个参数,或者是使用关键字参数的形式传入。
使用DSN还是独立参数主要基于所连接的系统。比如,如果你使用的是像ODBC或JDBC的API,则需要使用DSN;而如果你直接使用数据库,则更倾向于使用独立的登录参数。另一个使用独立参数的原因是很多数据库适配器并没有实现对DSN的支持。

(3).异常
异常同样需要包含在兼容的模块中。DB-API类如下:
Warning            警告异常基类
Error            错误异常基类
    InterfaceError    数据库接口错误
    DatabaseError    数据库错误
        DataError    处理数据时出现问题
        OperationError    数据库操作执行期间出现错误
        IntegrityError    数据库关系完整性错误
        InternalError    数据库内部错误
        ProgrammingError    SQL命令执行失败
        NotSupportedError    出现不支持的操作

5.Connection对象

应用与数据库之间进行通信需要建立数据库连接。它是最基本的机制,只有通过数据库连接才能把命令传递到服务器,并得到返回的结果。当一个连接(或一个连接池)建立后,可以创建一个游标,向数据库发送请求,然后从数据库中接收回应。
Connection对象方法:不需要包含任何数据属性,不过应当定义如下几个方法:
close()            关闭数据库连接
commit()        提交当前事务
rollback()        取消当前事务
cursor()        使用该连接创建并返回一个游标或类游标的对象
errorhandler()    作为给定连接的游标的处理程序

6.Cursor对象

如果创建一个数据库适配器,还必须要实现cursor对象,原因:这样,无论你将数据库切换到支持到游标的数据库还是不支持游标的数据库,都能保持Python的一致性。
游标对象最重要的属性是execute*()和fetch*()方法,所有针对数据库的服务请求都是通过它们执行的。arraysize数据属性在为fetchmany()设置默认大小时非常有用。当然,在不需要时关闭游标是个好主意,而如果你的数据库系统支持存储过程,可能会用到callproc()。
arraysize        使用fetchmany()方法时,一次取出的结果行数,默认为1。
connection        创建此游标的连接(可选)
description        返回游标活动状态(7项元组):(name,type_code, display_size, display_size, internal_size, precision, scale, null_ok),只有name和type_code是必需的。
lastrowid        上次修改行的行ID
rowcount        上次execute*()方法处理或影响的行数
callproc(func[,args])        调用存储过程
close()            关闭游标
execute(op[,args])        执行数据库查询或命令
executemany(op, args)    类似execute()和map()的结合,为给定的所有参数准备并执行数据库查询或命令
fetchone()        获取查询结果的下一行
fetchmany([size=cursor.arraysize])        获取查询结果的下面size行
fetchall()        获取查询结果的所有(剩余)行
__iter__()        为游标创建迭代器对象
messages        游标执行后从数据库中获得的消息列表
next()            被迭代器用于获取查询结果的下一行(可选,类似fetchone(), 参考__iter__())
nextset()        移动到下一个结果集合(如果支持)
rownumber        当前结果集中游标的索引(以行为单位,从0开始,可选)
 

7.项目实战

扫描二维码关注公众号,回复: 4802835 查看本文章

在下面的项目中,我将从苏州吴中区行政处罚和行政许可公示中:爬取数据,并将数据存储在工作站上,当然,如果觉得数据插入的部分比较麻烦,可以删除掉一些字段。

以下为项目代码:

爬取行政处罚公示信息大致分为两步,

首先先爬取各处罚的名称和url,

然后根据这些url爬取详情页的信息。

# http://61.155.216.26:8011/publicity/gs/queryHistory post
import re
import requests
from bs4 import BeautifulSoup
import common
import chardet
import time
import json
import pymysql
from punishment.functions import normalize_string

conn = pymysql.connect(host='192.168.1.204', db='wuzhong', user='root', password='123')
cursor = conn.cursor()


def get_latest_time():
    sql = 'SELECT MAX(cf_date) FROM punishment'
    cursor.execute(sql)
    result = cursor.fetchone()
    if result:
        return result[0]
    else:
        return 0


url_name_times = []
urls = []
for index in range(1, 30):
    print('正在爬取第{}页数据'.format(index))
    url = 'http://61.155.216.26:8011/publicity/gs/queryHistory'
    headers = common.get_user_agent()
    headers['Cookie'] = 'JSESSIONID=5FE868E99AC3C2D14DFE457C0469CEB5'
    print('index:', index)
    post_data = {
        'endTime': "",
        'gsType': '1',
        'page': index,
        'startTime': "",
        'userId': "",
        'xkrName': "",
        'userId': '001018',
    }

    response = requests.post(url, headers=headers, data=post_data, timeout=10)
    if response.status_code == 200:
        response.encoding = 'utf-8'
        soup = BeautifulSoup(response.text, 'lxml')
        dicts = json.loads(response.text)
        datas_list = dicts['obj']['list']
        print(datas_list)
        for data in datas_list:
            company = normalize_string(data.get('cfXdrMc'))
            punish_title = data.get('cfAjmc')
            msecs = data.get('cfJdrq')
            punish_time = time.strftime("%Y-%m-%d", time.localtime(msecs/1000))
            latest_time = str(get_latest_time())
            id = data.get('id')
            page_url = 'http://61.155.216.26:8011/publicity/xzcf/queryDetail?id={}&xzType=1'.format(id)
            if page_url not in urls and punish_time > latest_time:
                url_name_times.append((page_url, punish_title))
                urls.append(page_url)
    print(len(url_name_times))
    time.sleep(3)


try:
    for each in url_name_times:
        sql = 'INSERT INTO punishment(url, title, flag, province_id, city_id)' \
              ' VALUES("%s", "%s", "%s", "%s", "%s")' % (each[0], each[1], 0, 10, 79)
        cursor.execute(query=sql)
        conn.commit()
except Exception as e:
    print(e)
    conn.rollback()


# -------------------之后将flag为0的url进行更新-----------------------


def get_id_urls(cursor):
    try:
        sql = 'SELECT id, url FROM punishment WHERE flag = 0;'
        cursor.execute(sql)
        result = cursor.fetchall()
    except Exception as e:
        print(e)

    return result


def save_data(cursor, id, data):
    update_time = time.strftime("%Y-%m-%d", time.localtime())
    sql = 'UPDATE punishment' \
          ' SET cf_number = "%s", reason="%s", basis="%s", category="%s", xz_name="%s", ' \
          'credit_number="%s", legal_person_name="%s", id_card="%s", cf_result="%s", update_time="%s",' \
          'cf_date="%s", cf_department="%s", note="%s", source="%s", flag="%s"' \
          'WHERE id = "%s"' % (
        data.get('行政处罚决定书文号'), data.get('处罚事由'), data.get('处罚依据'), data.get('处罚类别1') + " " + data.get('处罚类别2'), data.get('行政相对人名称'),
        data.get('统一社会信用代码'), data.get('法定代表人姓名'), data.get('居民身份证号'), data.get('处罚结果'), update_time,
        data.get('处罚决定日期').replace('年', '-').replace('月', '-').replace('日', ''), data.get('处罚机关'), data.get('备注'), '吴中区信用信息公示', 1,
        id,
    )
    try:
        cursor.execute(sql)
        conn.commit()
        print('数据库插入成功!')
    except Exception as e:
        print(e)
        conn.rollback()


id_urls = get_id_urls(cursor)
for each in id_urls:
    url = each[1]
    id = each[0]
    print(url)
    response = requests.get(url, headers=common.get_user_agent(), timeout=10)
    response.encoding = chardet.detect(response.content)['encoding']
    soup = BeautifulSoup(response.text, 'lxml')
    table = soup.select('#home1DetailTable')[0]
    trs = table.find_all(name='tr')

    data = {}
    for tr in trs:
        tds = tr.find_all(name='td')
        data[normalize_string(tds[0].text)] = normalize_string(tds[1].text)

    save_data(cursor, id, data)
    time.sleep(3)

cursor.close()
conn.close()



猜你喜欢

转载自blog.csdn.net/qq_37597345/article/details/84940698
今日推荐