如何使用RPA操作MySQL數(shù)據(jù)庫
通過RPA編輯器獲取到頁面數(shù)據(jù)之后,除了可將數(shù)據(jù)保存到本地表格之外,也可直接將數(shù)據(jù)處理后傳輸?shù)綌?shù)據(jù)庫中,本文檔主要介紹使用RPA獲取頁面數(shù)據(jù)場景中、將獲取到的數(shù)據(jù)傳輸?shù)綌?shù)據(jù)庫的實踐方法。
本文檔僅針對獲取數(shù)據(jù)并傳輸?shù)綌?shù)據(jù)庫的數(shù)據(jù)新增場景,涉及到數(shù)據(jù)庫已有數(shù)據(jù)調(diào)整、特別是業(yè)務(wù)數(shù)據(jù)調(diào)整的,不適合使用RPA來進(jìn)行操作,請謹(jǐn)慎考慮具體實踐。
前置準(zhǔn)備
獲取第三方包pymysql、peewee并導(dǎo)入編輯器
可在下列兩種方法中進(jìn)行二選一:
1.可以前往cmd黑窗口中將第三方包進(jìn)行打包操作
導(dǎo)入包操作可參考如何使用自定義組件
# 安裝PyMySQL 0.10.1版本
pip install PyMySQL==0.10.1
# 安裝peewee 3.14.4版本
pip install peewee==3.14.4
# 安裝rpapack工具
pip install rpapack
# 執(zhí)行打包操作
python -m rpapack PyMySQL
python -m rpapack peewee
2.獲取預(yù)先準(zhǔn)備好的常用第三方包
示例RPA工程文件中已導(dǎo)入第三方包,下載示例工程文件即可參考
常用第三方庫可參考:如何引用第三方庫(舊)
快捷生成表對象類-ORM
常見場景中,往往是需要操作數(shù)據(jù)庫中已有的表,需要用到對象關(guān)系映射模型(ORM),即將數(shù)據(jù)庫表轉(zhuǎn)化為python類、表字段轉(zhuǎn)化為類屬性,然后對屬性字段進(jìn)行操作。
安裝好pymysql及peewee之后,在命令行界面執(zhí)行peewee自帶的pwiz.py模組,將對應(yīng)數(shù)據(jù)庫中的表按需生成python類對應(yīng)的文本,以供后續(xù)數(shù)據(jù)操作,參考指令及說明如下:
# 生成本地數(shù)據(jù)庫(localhost)對象類
python -m pwiz -e mysql -u root -P test
# 生成非本地數(shù)據(jù)庫對象類
python -m pwiz -e mysql -H 4x.xxx.xxx.xx -p 3306 -u root -P -t users test
注意:執(zhí)行上述指令后,會在控制臺輸出對應(yīng)的python文本,要將其保存為文件,可使用重定向符號,例如:
# 將生成的對象類重定向到test.py文件中
python -m pwiz -e mysql -u root -P test > test.py
指令各部分說明如下:
指令文本 | 含義說明 | 說明 |
python -m pwiz | 通過命令行形式運行pwiz.py文件 | 必填 |
-e mysql | 指定數(shù)據(jù)庫引擎(操作MySQL需要先安裝PyMySQL庫) | 必填 |
-H 4x.xxx.xxx.xx | 指定數(shù)據(jù)庫服務(wù)host地址(IP或域名) | 連接非本地數(shù)據(jù)庫時必填 |
-p 3306 | 指定數(shù)據(jù)庫 | 非必填,默認(rèn)使用3306端口 |
-u root | 指定數(shù)據(jù)庫用戶 | 必填 |
-P | 指定使用密碼登錄數(shù)據(jù)庫 | 必填,執(zhí)行指令后會提示輸入數(shù)據(jù)庫用戶對應(yīng)的密碼,密碼正確才能連接數(shù)據(jù)庫并生成對應(yīng)文本。 |
-t users | 指定表名 | 非必填 |
test | 指定數(shù)據(jù)庫名 | 必填 |
以上內(nèi)容參考python第三方包peewee官方操作文檔。
基本CURD操作
peewee對數(shù)據(jù)庫的所有操作均基于表對應(yīng)的模型類,請參考快捷生成表對象類-ORM
生成的類對象文件中,將配置對應(yīng)數(shù)據(jù)庫連接。
(一)Create數(shù)據(jù)新增
1.單行數(shù)據(jù)插入
# 實例化表對象,每一個實例對應(yīng)一個數(shù)據(jù)行,使用save方法即可將數(shù)據(jù)行實例寫入到數(shù)據(jù)庫對應(yīng)表中
user1 = User()
user1.username = "Howie"
user1.save()
# 使用create方法,則會創(chuàng)建一個表數(shù)據(jù)行實例,并將其插入到對應(yīng)表中,并返回主鍵ID
User.create(username="Alier")
# 使用insert方法,則不會創(chuàng)建對象實例,直接將數(shù)據(jù)寫入表中
User.insert(username="Wayen").execute()
2.多行數(shù)據(jù)插入
# 對于鍵值對型的數(shù)據(jù),可以使用insert_many進(jìn)行批量插入
data = [
{"username":"Ali","age":22},
{"username":"Ant","age":7},
{"username":"Howie","age":25}
]
# 對于非鍵值對型的元組數(shù)據(jù),要插入多行,可以在使用insert_many方法的基礎(chǔ)上,按順序指定對應(yīng)字段名,以正確插入相關(guān)數(shù)據(jù)。
data = [
('Ali', 22),
('Ant', 7),
('Howie', 25)
]
User.insert_many(data, fields=[User.name, User.age]).execute()
3.分批插入
# 人工對數(shù)據(jù)進(jìn)行切片操作
for index in range(0,len(data),100):
User.insert_many(data[index:index+100]).execute()
# 使用chunked方法可以快速將數(shù)據(jù)分批
for batch in chunked(data, 100):
User.insert_many(batch).execute()
(二)Update數(shù)據(jù)更新
# 通過先按條件檢索出相關(guān)數(shù)據(jù)行,直接對對應(yīng)的行對象實例進(jìn)行save操作,如本例中取出主鍵ID為3的行,將其name字段改為"TEST"
user = User.get(3)
user.user_name = "TEST"
user.save()
# 使用update方法進(jìn)行更新
query = Bill.update(amount=0).where(Bill.amount<1000)
query.execute()
(三)Retrieve數(shù)據(jù)檢索
1.基礎(chǔ)查詢
# 通過select方法會返回對應(yīng)表中的所有行,作為ModelSelect對象進(jìn)行操作
query = User.select()
# 通過dicts方法,能將每一行轉(zhuǎn)換為字典結(jié)構(gòu);通過nametuples(),tuples()可以將
row_data_dicts = query.dicts()
for row_dict in row_data_dicts:
print(row_dict)
# {"name":"Ali","age":12}
# 關(guān)聯(lián)查詢,多表關(guān)聯(lián)查詢需要用到j(luò)oin方法進(jìn)行表關(guān)聯(lián),where方法限定查詢條件,方法中已做了謂詞下推等基本優(yōu)化。
# 最終將返回ModelSelect對象
query = (Bill
.select(Bill,User)
.join(User, on = Bill.user==User.id)
.where(Bill.user==1)
.order_by(Bill.bill_id.desc())
)
2.查詢新增聯(lián)合操作
# 使用get_or_create操作,會先檢索數(shù)據(jù)庫中是否存在對應(yīng)行數(shù)據(jù),不存在的情況下,進(jìn)行新增操作
# 使用類屬性參數(shù)來指定查詢條件,查詢無記錄的情況下,將對應(yīng)屬性作為新記錄執(zhí)行插入
# 使用defaults參數(shù)來指定當(dāng)行記錄不存在時,要新增的字段值
# get_or_create會返回形如(Model,Bool)的結(jié)果,其中Model是對應(yīng)的數(shù)據(jù)行模型,Bool指是否為新建記錄。
bill,created = Bill.get_or_create(
user=2,
defaults={'amount':666}
)
(四)Delete刪除數(shù)據(jù)
# 使用delete_instance方法刪除單個數(shù)據(jù)行實例
user = User.get(User.id == 1)
user.delete_instance()
# 使用delete方法根據(jù)條件刪除多行數(shù)據(jù)
query = Bill.delete().where(Bill.amount<1000)
query.execute()
事務(wù)型操作
# 使用with db.atomic聲明事務(wù)操作,保證批量數(shù)據(jù)插入的完整性,其中db為通過peewee的MySQLDatabase方法創(chuàng)建的數(shù)據(jù)庫連接實例
data = [
{"username":"Ali","age":"22"},
{"username":"Ant","age":"7"},
# ...
]
# 需要將數(shù)據(jù)作整體一次性插入時
with db.atomic():
User.insert_many(data).excute()
# 遇到數(shù)據(jù)量特別大的情況,可以考慮使用chunk方法進(jìn)行數(shù)據(jù)分批操作
with db.atomic():
for batch in chunked(data, 100):
User.insert_many(batch).execute()
實例-獲取GDP數(shù)據(jù)并存入數(shù)據(jù)庫
工程文件可前往以下地址進(jìn)行下載:RPA 4最佳實踐工程文件
本案例主要登錄特定網(wǎng)址,獲取GDP數(shù)據(jù),最終將其存放到本地MySQL數(shù)據(jù)庫中的rpa_demo庫中,詳情請參見工程源文件或者關(guān)鍵代碼說明。
關(guān)鍵代碼
1.數(shù)據(jù)庫操作
from peewee import *
# 根據(jù)實際情況設(shè)置數(shù)據(jù)庫用戶名密碼,以及要連接的庫名
db_user_name = 'root'
db_password = 'xxxxx'
db_name = 'rpa_demo'
# 構(gòu)建數(shù)據(jù)庫連接類
database = MySQLDatabase(db_name, **{'password': db_password, 'sql_mode': 'PIPES_AS_CONCAT', 'charset': 'utf8', 'user': db_user_name, 'use_unicode': True})
class BaseModel(Model):
class Meta:
database = database
# 構(gòu)建數(shù)據(jù)表對象類,用于存放GDP數(shù)據(jù)
class GdpDemo(BaseModel):
# 行ID
row_id = AutoField()
# 季度名
quarter = CharField()
# 國內(nèi)生產(chǎn)總值
# 絕對值
gdp_abs = CharField()
# 同比增長
gdp_yoy_growth = CharField()
# 第一產(chǎn)業(yè)
# 絕對值
pri_industry = CharField()
# 同比增長
pi_yoy_growth = CharField()
# 第二產(chǎn)業(yè)
# 絕對值
sec_industry = CharField()
# 同比增長
si_yoy_growth = CharField()
# 第三產(chǎn)業(yè)
# 絕對值
thi_industry = CharField()
# 同比增長
ti_yoy_growth = CharField()
# 數(shù)據(jù)更新日期
update_date = DateField()
class Meta:
table_name = 'gdp_demo'
# 新建表
def create_table(table):
if not table.table_exists():
table.create_table()
2.主程序
from rpa.core import *
from rpa.utils import *
import rpa4 as rpa # 使用V4引擎
import test_db as db
from datetime import datetime
def start():
# 在此處開始編寫您的應(yīng)用
page = rpa.app.ie.create("http://data.eastmoney.com/cjsj/gdp.html")
table_data = page.table("ie表格")
data = table_data[3:]
# 將當(dāng)前時間作為數(shù)據(jù)更新時間
for _ in data:
_.append(datetime.now())
# 創(chuàng)建數(shù)據(jù)庫表gdp_demo,如果表已存在則跳過
db.create_table(db.GdpDemo)
# 由于從網(wǎng)頁取到的數(shù)據(jù)并非字典結(jié)構(gòu),需要按數(shù)據(jù)順序設(shè)置字段映射關(guān)系
fileds_mapping = [
db.GdpDemo.quarter,
db.GdpDemo.gdp_abs,
db.GdpDemo.gdp_yoy_growth,
db.GdpDemo.pri_industry,
db.GdpDemo.pi_yoy_growth,
db.GdpDemo.sec_industry,
db.GdpDemo.si_yoy_growth,
db.GdpDemo.thi_industry,
db.GdpDemo.ti_yoy_growth,
db.GdpDemo.update_date]
# 批量插入數(shù)據(jù)
db.GdpDemo.insert_many(data,fields=fileds_mapping).execute()
rpa.system.dialog.msgbox("數(shù)據(jù)成功入庫","當(dāng)前時間{}:{}行數(shù)據(jù)已經(jīng)成功寫入到表gdp_demo中".format(datetime.now(),len(data)))
# 關(guān)閉數(shù)據(jù)庫
db.database.close()
pass