'commit'
This commit is contained in:
6
.vscode/extensions.json
vendored
Normal file
6
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"ms-python.python",
|
||||||
|
"ms-python.vscode-pylance"
|
||||||
|
]
|
||||||
|
}
|
||||||
13
.vscode/launch.json
vendored
Normal file
13
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Run wxChat",
|
||||||
|
"type": "python",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/Start.py",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"justMyCode": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"python.defaultInterpreterPath": "D:\\anaconda3\\envs\\py310\\python.exe"
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -1,127 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"prid",
|
|
||||||
"order_id",
|
|
||||||
"outtradeno",
|
|
||||||
"pay_time",
|
|
||||||
"pay_money",
|
|
||||||
"refund_time",
|
|
||||||
"refund_money",
|
|
||||||
"refund_state",
|
|
||||||
"order_time",
|
|
||||||
"pay_xml",
|
|
||||||
"refund_xml",
|
|
||||||
"check_xml",
|
|
||||||
"pay_state",
|
|
||||||
"pay_type",
|
|
||||||
"phone",
|
|
||||||
"check_time",
|
|
||||||
"user_id",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"donate_money",
|
|
||||||
"memo",
|
|
||||||
"refund_memo",
|
|
||||||
"refund_outtradno",
|
|
||||||
"refund_image",
|
|
||||||
"refund_operer",
|
|
||||||
"rechage_operer",
|
|
||||||
"refund_reason",
|
|
||||||
"vip",
|
|
||||||
"meal_id",
|
|
||||||
"refund_apply_time",
|
|
||||||
"pay_method"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_account_recharge"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}",
|
|
||||||
"where": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"prid",
|
|
||||||
"order_id",
|
|
||||||
"outtradeno",
|
|
||||||
"pay_time",
|
|
||||||
"pay_money",
|
|
||||||
"refund_time",
|
|
||||||
"refund_money",
|
|
||||||
"refund_state",
|
|
||||||
"order_time",
|
|
||||||
"pay_xml",
|
|
||||||
"refund_xml",
|
|
||||||
"check_xml",
|
|
||||||
"pay_state",
|
|
||||||
"pay_type",
|
|
||||||
"phone",
|
|
||||||
"check_time",
|
|
||||||
"user_id",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"donate_money",
|
|
||||||
"memo",
|
|
||||||
"refund_memo",
|
|
||||||
"refund_outtradno",
|
|
||||||
"refund_image",
|
|
||||||
"refund_operer",
|
|
||||||
"rechage_operer",
|
|
||||||
"refund_reason",
|
|
||||||
"vip",
|
|
||||||
"meal_id",
|
|
||||||
"refund_apply_time",
|
|
||||||
"pay_method"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_account_recharge"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_account_recharge"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"cash",
|
|
||||||
"phone",
|
|
||||||
"txt_desc",
|
|
||||||
"sign_msg",
|
|
||||||
"reason",
|
|
||||||
"sign",
|
|
||||||
"type",
|
|
||||||
"order_id",
|
|
||||||
"treatment",
|
|
||||||
"user_id",
|
|
||||||
"pay_status",
|
|
||||||
"pay_method",
|
|
||||||
"update_time",
|
|
||||||
"create_time",
|
|
||||||
"pre_balance",
|
|
||||||
"bef_balance",
|
|
||||||
"memo",
|
|
||||||
"donate_money",
|
|
||||||
"ua_balance",
|
|
||||||
"to_user_id"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_account_water"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}",
|
|
||||||
"where": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"cash",
|
|
||||||
"phone",
|
|
||||||
"txt_desc",
|
|
||||||
"sign_msg",
|
|
||||||
"reason",
|
|
||||||
"sign",
|
|
||||||
"type",
|
|
||||||
"order_id",
|
|
||||||
"treatment",
|
|
||||||
"user_id",
|
|
||||||
"pay_status",
|
|
||||||
"pay_method",
|
|
||||||
"update_time",
|
|
||||||
"create_time",
|
|
||||||
"pre_balance",
|
|
||||||
"bef_balance",
|
|
||||||
"memo",
|
|
||||||
"donate_money",
|
|
||||||
"ua_balance",
|
|
||||||
"to_user_id"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_account_water"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_account_water"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"car_plate_no",
|
|
||||||
"car_sn",
|
|
||||||
"car_brand_name",
|
|
||||||
"car_model_name",
|
|
||||||
"car_vin",
|
|
||||||
"car_engine",
|
|
||||||
"car_type",
|
|
||||||
"car_owner_company_id",
|
|
||||||
"car_business",
|
|
||||||
"car_bus_path",
|
|
||||||
"is_auto_charge",
|
|
||||||
"user_id",
|
|
||||||
"user_card_no",
|
|
||||||
"is_disable",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"operator_id"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_car"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}",
|
|
||||||
"where": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"car_plate_no",
|
|
||||||
"car_sn",
|
|
||||||
"car_brand_name",
|
|
||||||
"car_model_name",
|
|
||||||
"car_vin",
|
|
||||||
"car_engine",
|
|
||||||
"car_type",
|
|
||||||
"car_owner_company_id",
|
|
||||||
"car_business",
|
|
||||||
"car_bus_path",
|
|
||||||
"is_auto_charge",
|
|
||||||
"user_id",
|
|
||||||
"user_card_no",
|
|
||||||
"is_disable",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"operator_id"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_car"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_car"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"company_no",
|
|
||||||
"company_type",
|
|
||||||
"company_name",
|
|
||||||
"company_state",
|
|
||||||
"company_logo",
|
|
||||||
"company_admin_phone",
|
|
||||||
"company_admin_name",
|
|
||||||
"balance_remind",
|
|
||||||
"balance_remind_phone",
|
|
||||||
"agent_id",
|
|
||||||
"station_set_type",
|
|
||||||
"specified_range",
|
|
||||||
"specified_operator_ids",
|
|
||||||
"is_company_discount",
|
|
||||||
"is_overlay_coupons",
|
|
||||||
"station_ids",
|
|
||||||
"no_discount_stationids",
|
|
||||||
"remark",
|
|
||||||
"invoice_eligible",
|
|
||||||
"refuse_invoice_tip",
|
|
||||||
"is_share_master",
|
|
||||||
"settlement_method",
|
|
||||||
"charge_discount_type",
|
|
||||||
"charge_discount",
|
|
||||||
"settle_status",
|
|
||||||
"charge_unit_service",
|
|
||||||
"charge_unit_electric",
|
|
||||||
"is_custom_price",
|
|
||||||
"company_order_permission",
|
|
||||||
"open_station_ids",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"minimum_recharge_amount",
|
|
||||||
"inner_person"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_company"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}",
|
|
||||||
"where": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"company_no",
|
|
||||||
"company_type",
|
|
||||||
"company_name",
|
|
||||||
"company_state",
|
|
||||||
"company_logo",
|
|
||||||
"company_admin_phone",
|
|
||||||
"company_admin_name",
|
|
||||||
"balance_remind",
|
|
||||||
"balance_remind_phone",
|
|
||||||
"agent_id",
|
|
||||||
"station_set_type",
|
|
||||||
"specified_range",
|
|
||||||
"specified_operator_ids",
|
|
||||||
"is_company_discount",
|
|
||||||
"is_overlay_coupons",
|
|
||||||
"station_ids",
|
|
||||||
"no_discount_stationids",
|
|
||||||
"remark",
|
|
||||||
"invoice_eligible",
|
|
||||||
"refuse_invoice_tip",
|
|
||||||
"is_share_master",
|
|
||||||
"settlement_method",
|
|
||||||
"charge_discount_type",
|
|
||||||
"charge_discount",
|
|
||||||
"settle_status",
|
|
||||||
"charge_unit_service",
|
|
||||||
"charge_unit_electric",
|
|
||||||
"is_custom_price",
|
|
||||||
"company_order_permission",
|
|
||||||
"open_station_ids",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"minimum_recharge_amount",
|
|
||||||
"inner_person"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_company"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_company"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"info_value",
|
|
||||||
"type_id",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"remark",
|
|
||||||
"renzheng_flag"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_company_info_value"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}",
|
|
||||||
"where": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"info_value",
|
|
||||||
"type_id",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"remark",
|
|
||||||
"renzheng_flag"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_company_info_value"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_company_info_value"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"equipment_id",
|
|
||||||
"connector_sn",
|
|
||||||
"connector_short_sn",
|
|
||||||
"connector_no",
|
|
||||||
"connector_name",
|
|
||||||
"connector_type",
|
|
||||||
"voltage_upper_limits",
|
|
||||||
"voltage_lower_limits",
|
|
||||||
"current",
|
|
||||||
"power",
|
|
||||||
"parkno",
|
|
||||||
"appointment_id",
|
|
||||||
"appointment_user_id",
|
|
||||||
"open_lock_user_id",
|
|
||||||
"detection_type",
|
|
||||||
"is_ground_lock",
|
|
||||||
"is_ground_lock_msg",
|
|
||||||
"is_geomagnetic",
|
|
||||||
"is_geomagnetic_msg",
|
|
||||||
"is_appointment",
|
|
||||||
"is_appointment_msg",
|
|
||||||
"auto_open_lock_time",
|
|
||||||
"create_time",
|
|
||||||
"update_time"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_connector"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}",
|
|
||||||
"where": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"equipment_id",
|
|
||||||
"connector_sn",
|
|
||||||
"connector_short_sn",
|
|
||||||
"connector_no",
|
|
||||||
"connector_name",
|
|
||||||
"connector_type",
|
|
||||||
"voltage_upper_limits",
|
|
||||||
"voltage_lower_limits",
|
|
||||||
"current",
|
|
||||||
"power",
|
|
||||||
"parkno",
|
|
||||||
"appointment_id",
|
|
||||||
"appointment_user_id",
|
|
||||||
"open_lock_user_id",
|
|
||||||
"detection_type",
|
|
||||||
"is_ground_lock",
|
|
||||||
"is_ground_lock_msg",
|
|
||||||
"is_geomagnetic",
|
|
||||||
"is_geomagnetic_msg",
|
|
||||||
"is_appointment",
|
|
||||||
"is_appointment_msg",
|
|
||||||
"auto_open_lock_time",
|
|
||||||
"create_time",
|
|
||||||
"update_time"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_connector"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_connector"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"station_id",
|
|
||||||
"agreement_id",
|
|
||||||
"equipment_name",
|
|
||||||
"equipment_sn",
|
|
||||||
"equipment_short_sn",
|
|
||||||
"equipment_no",
|
|
||||||
"manufacturer_id",
|
|
||||||
"manufacturer_sn",
|
|
||||||
"manufacturer_name",
|
|
||||||
"equipment_model",
|
|
||||||
"production_date",
|
|
||||||
"equipment_type",
|
|
||||||
"equipment_type_msg",
|
|
||||||
"equipment_lng",
|
|
||||||
"equipment_lat",
|
|
||||||
"connector_count",
|
|
||||||
"power",
|
|
||||||
"national_standard",
|
|
||||||
"national_standard_msg",
|
|
||||||
"status",
|
|
||||||
"equipment_business_type",
|
|
||||||
"equipment_business_type_msg",
|
|
||||||
"is_use_card",
|
|
||||||
"is_use_card_msg",
|
|
||||||
"charge_host_esn",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"aux_power",
|
|
||||||
"app_show"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_equipment"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}",
|
|
||||||
"where": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"station_id",
|
|
||||||
"agreement_id",
|
|
||||||
"equipment_name",
|
|
||||||
"equipment_sn",
|
|
||||||
"equipment_short_sn",
|
|
||||||
"equipment_no",
|
|
||||||
"manufacturer_id",
|
|
||||||
"manufacturer_sn",
|
|
||||||
"manufacturer_name",
|
|
||||||
"equipment_model",
|
|
||||||
"production_date",
|
|
||||||
"equipment_type",
|
|
||||||
"equipment_type_msg",
|
|
||||||
"equipment_lng",
|
|
||||||
"equipment_lat",
|
|
||||||
"connector_count",
|
|
||||||
"power",
|
|
||||||
"national_standard",
|
|
||||||
"national_standard_msg",
|
|
||||||
"status",
|
|
||||||
"equipment_business_type",
|
|
||||||
"equipment_business_type_msg",
|
|
||||||
"is_use_card",
|
|
||||||
"is_use_card_msg",
|
|
||||||
"charge_host_esn",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"aux_power",
|
|
||||||
"app_show"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_equipment"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_equipment"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,285 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"user_id",
|
|
||||||
"company_id",
|
|
||||||
"station_id",
|
|
||||||
"equipment_id",
|
|
||||||
"connector_id",
|
|
||||||
"user_card_no",
|
|
||||||
"state",
|
|
||||||
"operate_state",
|
|
||||||
"order_no",
|
|
||||||
"platform_order_no",
|
|
||||||
"platform_sale_type",
|
|
||||||
"platform_driver_id",
|
|
||||||
"platform_phone",
|
|
||||||
"charging_amt",
|
|
||||||
"order_type",
|
|
||||||
"order_time",
|
|
||||||
"charge_begin_time",
|
|
||||||
"charge_end_time",
|
|
||||||
"charge_begin_degree",
|
|
||||||
"charge_end_degree",
|
|
||||||
"charge_degree",
|
|
||||||
"charge_ah",
|
|
||||||
"charge_times_degree",
|
|
||||||
"charge_begin_soc",
|
|
||||||
"charge_end_soc",
|
|
||||||
"charge_cur_soc",
|
|
||||||
"charge_duration",
|
|
||||||
"charge_settle_type",
|
|
||||||
"charge_unit_price",
|
|
||||||
"charge_unit_cost",
|
|
||||||
"charge_unit_service_fee",
|
|
||||||
"receivable_electric_fee",
|
|
||||||
"receivable_service_fee",
|
|
||||||
"receivable_total_fee",
|
|
||||||
"charge_elecfee_amount",
|
|
||||||
"charge_elecfee_cost_amount",
|
|
||||||
"charge_service_amount",
|
|
||||||
"actual_pay_amount",
|
|
||||||
"pay_order_no",
|
|
||||||
"pay_amount",
|
|
||||||
"pay_method",
|
|
||||||
"pay_status",
|
|
||||||
"pay_time",
|
|
||||||
"user_coupon_id",
|
|
||||||
"coupon_name",
|
|
||||||
"coupon_type",
|
|
||||||
"coupon_amount",
|
|
||||||
"elecfee_coupon_amount",
|
|
||||||
"servicefee_coupon_amount",
|
|
||||||
"invoice_id",
|
|
||||||
"invoice_fee",
|
|
||||||
"ticket_status",
|
|
||||||
"activity_electric_fee",
|
|
||||||
"activity_service_fee",
|
|
||||||
"charge_plate_no",
|
|
||||||
"charge_vin",
|
|
||||||
"charge_strategy",
|
|
||||||
"charge_strategy_param",
|
|
||||||
"operator_id",
|
|
||||||
"operator_income",
|
|
||||||
"plat_service_fee",
|
|
||||||
"charge_discount_type",
|
|
||||||
"settle_electric_fee",
|
|
||||||
"settle_service_fee",
|
|
||||||
"settle_fee",
|
|
||||||
"settle_method",
|
|
||||||
"settle_coupon_amount",
|
|
||||||
"settle_coupon_electric_fee",
|
|
||||||
"settle_coupon_service_fee",
|
|
||||||
"settle_status",
|
|
||||||
"cancel_type",
|
|
||||||
"cancel_code",
|
|
||||||
"cancel_msg",
|
|
||||||
"cancel_time",
|
|
||||||
"finish_type",
|
|
||||||
"finish_code",
|
|
||||||
"finish_msg",
|
|
||||||
"finish_time",
|
|
||||||
"boot_mode",
|
|
||||||
"settlement_type",
|
|
||||||
"is_parking_coupon",
|
|
||||||
"control_source",
|
|
||||||
"exception_flag",
|
|
||||||
"exception_msg",
|
|
||||||
"report_time",
|
|
||||||
"com_service_fee",
|
|
||||||
"com_electric_fee",
|
|
||||||
"com_total_fee",
|
|
||||||
"com_charge_discount_type",
|
|
||||||
"com_charge_discount",
|
|
||||||
"has_shallow_report",
|
|
||||||
"has_deep_report",
|
|
||||||
"is_exception",
|
|
||||||
"shallow_report_is_received",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"charge_market_id",
|
|
||||||
"coupon_total_amount",
|
|
||||||
"coupon_service_total_amount",
|
|
||||||
"coupon_elecfee_total_amount",
|
|
||||||
"activity_name",
|
|
||||||
"activity_total_fee",
|
|
||||||
"company_activity_id",
|
|
||||||
"company_activity_name",
|
|
||||||
"company_activity_total_fee",
|
|
||||||
"company_activity_service_fee",
|
|
||||||
"company_activity_electric_fee",
|
|
||||||
"subsidy_degree",
|
|
||||||
"subsidy_fee",
|
|
||||||
"special_channel_order_source"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_equipment_charge_order"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}",
|
|
||||||
"where": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"user_id",
|
|
||||||
"company_id",
|
|
||||||
"station_id",
|
|
||||||
"equipment_id",
|
|
||||||
"connector_id",
|
|
||||||
"user_card_no",
|
|
||||||
"state",
|
|
||||||
"operate_state",
|
|
||||||
"order_no",
|
|
||||||
"platform_order_no",
|
|
||||||
"platform_sale_type",
|
|
||||||
"platform_driver_id",
|
|
||||||
"platform_phone",
|
|
||||||
"charging_amt",
|
|
||||||
"order_type",
|
|
||||||
"order_time",
|
|
||||||
"charge_begin_time",
|
|
||||||
"charge_end_time",
|
|
||||||
"charge_begin_degree",
|
|
||||||
"charge_end_degree",
|
|
||||||
"charge_degree",
|
|
||||||
"charge_ah",
|
|
||||||
"charge_times_degree",
|
|
||||||
"charge_begin_soc",
|
|
||||||
"charge_end_soc",
|
|
||||||
"charge_cur_soc",
|
|
||||||
"charge_duration",
|
|
||||||
"charge_settle_type",
|
|
||||||
"charge_unit_price",
|
|
||||||
"charge_unit_cost",
|
|
||||||
"charge_unit_service_fee",
|
|
||||||
"receivable_electric_fee",
|
|
||||||
"receivable_service_fee",
|
|
||||||
"receivable_total_fee",
|
|
||||||
"charge_elecfee_amount",
|
|
||||||
"charge_elecfee_cost_amount",
|
|
||||||
"charge_service_amount",
|
|
||||||
"actual_pay_amount",
|
|
||||||
"pay_order_no",
|
|
||||||
"pay_amount",
|
|
||||||
"pay_method",
|
|
||||||
"pay_status",
|
|
||||||
"pay_time",
|
|
||||||
"user_coupon_id",
|
|
||||||
"coupon_name",
|
|
||||||
"coupon_type",
|
|
||||||
"coupon_amount",
|
|
||||||
"elecfee_coupon_amount",
|
|
||||||
"servicefee_coupon_amount",
|
|
||||||
"invoice_id",
|
|
||||||
"invoice_fee",
|
|
||||||
"ticket_status",
|
|
||||||
"activity_electric_fee",
|
|
||||||
"activity_service_fee",
|
|
||||||
"charge_plate_no",
|
|
||||||
"charge_vin",
|
|
||||||
"charge_strategy",
|
|
||||||
"charge_strategy_param",
|
|
||||||
"operator_id",
|
|
||||||
"operator_income",
|
|
||||||
"plat_service_fee",
|
|
||||||
"charge_discount_type",
|
|
||||||
"settle_electric_fee",
|
|
||||||
"settle_service_fee",
|
|
||||||
"settle_fee",
|
|
||||||
"settle_method",
|
|
||||||
"settle_coupon_amount",
|
|
||||||
"settle_coupon_electric_fee",
|
|
||||||
"settle_coupon_service_fee",
|
|
||||||
"settle_status",
|
|
||||||
"cancel_type",
|
|
||||||
"cancel_code",
|
|
||||||
"cancel_msg",
|
|
||||||
"cancel_time",
|
|
||||||
"finish_type",
|
|
||||||
"finish_code",
|
|
||||||
"finish_msg",
|
|
||||||
"finish_time",
|
|
||||||
"boot_mode",
|
|
||||||
"settlement_type",
|
|
||||||
"is_parking_coupon",
|
|
||||||
"control_source",
|
|
||||||
"exception_flag",
|
|
||||||
"exception_msg",
|
|
||||||
"report_time",
|
|
||||||
"com_service_fee",
|
|
||||||
"com_electric_fee",
|
|
||||||
"com_total_fee",
|
|
||||||
"com_charge_discount_type",
|
|
||||||
"com_charge_discount",
|
|
||||||
"has_shallow_report",
|
|
||||||
"has_deep_report",
|
|
||||||
"is_exception",
|
|
||||||
"shallow_report_is_received",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"charge_market_id",
|
|
||||||
"coupon_total_amount",
|
|
||||||
"coupon_service_total_amount",
|
|
||||||
"coupon_elecfee_total_amount",
|
|
||||||
"activity_name",
|
|
||||||
"activity_total_fee",
|
|
||||||
"company_activity_id",
|
|
||||||
"company_activity_name",
|
|
||||||
"company_activity_total_fee",
|
|
||||||
"company_activity_service_fee",
|
|
||||||
"company_activity_electric_fee",
|
|
||||||
"subsidy_degree",
|
|
||||||
"subsidy_fee",
|
|
||||||
"special_channel_order_source"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_equipment_charge_order"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_equipment_charge_order"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"order_no",
|
|
||||||
"charge_degree",
|
|
||||||
"service_fee",
|
|
||||||
"electric_fee",
|
|
||||||
"cost_fee",
|
|
||||||
"service_fee_unit_price",
|
|
||||||
"electric_fee_unit_price",
|
|
||||||
"cost_fee_unit_price",
|
|
||||||
"activity_service_fee",
|
|
||||||
"activity_electric_fee",
|
|
||||||
"charge_startr_time",
|
|
||||||
"charge_end_time",
|
|
||||||
"charge_meal_electric_fee",
|
|
||||||
"charge_meal_service_fee",
|
|
||||||
"charge_meal_total_fee",
|
|
||||||
"electric_card_use_dgree",
|
|
||||||
"check_electric_unit_price",
|
|
||||||
"check_service_unit_price",
|
|
||||||
"time_flag",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"detail_more"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_equipment_charge_order_detail"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}",
|
|
||||||
"where": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"order_no",
|
|
||||||
"charge_degree",
|
|
||||||
"service_fee",
|
|
||||||
"electric_fee",
|
|
||||||
"cost_fee",
|
|
||||||
"service_fee_unit_price",
|
|
||||||
"electric_fee_unit_price",
|
|
||||||
"cost_fee_unit_price",
|
|
||||||
"activity_service_fee",
|
|
||||||
"activity_electric_fee",
|
|
||||||
"charge_startr_time",
|
|
||||||
"charge_end_time",
|
|
||||||
"charge_meal_electric_fee",
|
|
||||||
"charge_meal_service_fee",
|
|
||||||
"charge_meal_total_fee",
|
|
||||||
"electric_card_use_dgree",
|
|
||||||
"check_electric_unit_price",
|
|
||||||
"check_service_unit_price",
|
|
||||||
"time_flag",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"detail_more"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_equipment_charge_order_detail"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_equipment_charge_order_detail"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"order_no",
|
|
||||||
"telephone",
|
|
||||||
"user_id",
|
|
||||||
"message1",
|
|
||||||
"message2",
|
|
||||||
"create_time",
|
|
||||||
"station_id",
|
|
||||||
"equipment_id",
|
|
||||||
"connector_id",
|
|
||||||
"flag",
|
|
||||||
"close_time",
|
|
||||||
"finish_time",
|
|
||||||
"minutesDifference",
|
|
||||||
"reduce_money",
|
|
||||||
"beforeBalance",
|
|
||||||
"afterBalance",
|
|
||||||
"fee_station",
|
|
||||||
"manual_count",
|
|
||||||
"last_manual_time",
|
|
||||||
"last_manual_message",
|
|
||||||
"person_id",
|
|
||||||
"refund_status",
|
|
||||||
"refund_time",
|
|
||||||
"refund_person_id",
|
|
||||||
"refund_person_name",
|
|
||||||
"refund_amount",
|
|
||||||
"refund_type",
|
|
||||||
"unplug_time"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_ext_hurry_quit"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"order_no",
|
|
||||||
"telephone",
|
|
||||||
"user_id",
|
|
||||||
"message1",
|
|
||||||
"message2",
|
|
||||||
"create_time",
|
|
||||||
"station_id",
|
|
||||||
"equipment_id",
|
|
||||||
"connector_id",
|
|
||||||
"flag",
|
|
||||||
"close_time",
|
|
||||||
"finish_time",
|
|
||||||
"minutesDifference",
|
|
||||||
"reduce_money",
|
|
||||||
"beforeBalance",
|
|
||||||
"afterBalance",
|
|
||||||
"fee_station",
|
|
||||||
"manual_count",
|
|
||||||
"last_manual_time",
|
|
||||||
"last_manual_message",
|
|
||||||
"person_id",
|
|
||||||
"refund_status",
|
|
||||||
"refund_time",
|
|
||||||
"refund_person_id",
|
|
||||||
"refund_person_name",
|
|
||||||
"refund_amount",
|
|
||||||
"refund_type",
|
|
||||||
"unplug_time"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_ext_hurry_quit"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_ext_hurry_quit"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"station_sn",
|
|
||||||
"operator_id",
|
|
||||||
"equioment_owner_id",
|
|
||||||
"station_name",
|
|
||||||
"country_code",
|
|
||||||
"region_id",
|
|
||||||
"region_code",
|
|
||||||
"regional_name",
|
|
||||||
"regional_code",
|
|
||||||
"address",
|
|
||||||
"station_tel",
|
|
||||||
"service_tel",
|
|
||||||
"station_type",
|
|
||||||
"station_type_msg",
|
|
||||||
"station_business_type",
|
|
||||||
"station_business_type_msg",
|
|
||||||
"station_status",
|
|
||||||
"station_status_msg",
|
|
||||||
"park_nums",
|
|
||||||
"station_lng",
|
|
||||||
"station_lat",
|
|
||||||
"site_guide",
|
|
||||||
"construction",
|
|
||||||
"construction_msg",
|
|
||||||
"pictures",
|
|
||||||
"match_cars",
|
|
||||||
"park_info",
|
|
||||||
"business_start_time",
|
|
||||||
"business_end_time",
|
|
||||||
"electricity_fee",
|
|
||||||
"service_fee",
|
|
||||||
"is_park_fee",
|
|
||||||
"park_fee",
|
|
||||||
"payment",
|
|
||||||
"payment_msg",
|
|
||||||
"support_order",
|
|
||||||
"support_order_msg",
|
|
||||||
"service_item",
|
|
||||||
"service_item_image_url",
|
|
||||||
"service_item_msg",
|
|
||||||
"station_location_type",
|
|
||||||
"station_location_type_msg",
|
|
||||||
"station_charge_type",
|
|
||||||
"station_charge_type_msg",
|
|
||||||
"station_power",
|
|
||||||
"station_voltage",
|
|
||||||
"station_current",
|
|
||||||
"is_open",
|
|
||||||
"is_open_msg",
|
|
||||||
"is_display",
|
|
||||||
"is_display_msg",
|
|
||||||
"sharing_code",
|
|
||||||
"sharing_applet_picture",
|
|
||||||
"theme_picture",
|
|
||||||
"is_barrier_flag",
|
|
||||||
"is_barrier_flag_msg",
|
|
||||||
"charge_settle_type",
|
|
||||||
"charge_settle_type_msg",
|
|
||||||
"fast_connector_nums",
|
|
||||||
"slow_connector_nums",
|
|
||||||
"transformer_capacity",
|
|
||||||
"installed_capacity",
|
|
||||||
"remark",
|
|
||||||
"record_unique_no",
|
|
||||||
"equipment_owner_name",
|
|
||||||
"supply_type",
|
|
||||||
"resident_no",
|
|
||||||
"watt_hour_meter_no",
|
|
||||||
"forward_power",
|
|
||||||
"operation_date",
|
|
||||||
"charge_replace_type",
|
|
||||||
"is_hlht",
|
|
||||||
"is_subsidy",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"area_code_countryside",
|
|
||||||
"business_expand_type",
|
|
||||||
"capacity",
|
|
||||||
"video_monitor",
|
|
||||||
"electricity_type",
|
|
||||||
"receive_shop"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_station"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"station_sn",
|
|
||||||
"operator_id",
|
|
||||||
"equioment_owner_id",
|
|
||||||
"station_name",
|
|
||||||
"country_code",
|
|
||||||
"region_id",
|
|
||||||
"region_code",
|
|
||||||
"regional_name",
|
|
||||||
"regional_code",
|
|
||||||
"address",
|
|
||||||
"station_tel",
|
|
||||||
"service_tel",
|
|
||||||
"station_type",
|
|
||||||
"station_type_msg",
|
|
||||||
"station_business_type",
|
|
||||||
"station_business_type_msg",
|
|
||||||
"station_status",
|
|
||||||
"station_status_msg",
|
|
||||||
"park_nums",
|
|
||||||
"station_lng",
|
|
||||||
"station_lat",
|
|
||||||
"site_guide",
|
|
||||||
"construction",
|
|
||||||
"construction_msg",
|
|
||||||
"pictures",
|
|
||||||
"match_cars",
|
|
||||||
"park_info",
|
|
||||||
"business_start_time",
|
|
||||||
"business_end_time",
|
|
||||||
"electricity_fee",
|
|
||||||
"service_fee",
|
|
||||||
"is_park_fee",
|
|
||||||
"park_fee",
|
|
||||||
"payment",
|
|
||||||
"payment_msg",
|
|
||||||
"support_order",
|
|
||||||
"support_order_msg",
|
|
||||||
"service_item",
|
|
||||||
"service_item_image_url",
|
|
||||||
"service_item_msg",
|
|
||||||
"station_location_type",
|
|
||||||
"station_location_type_msg",
|
|
||||||
"station_charge_type",
|
|
||||||
"station_charge_type_msg",
|
|
||||||
"station_power",
|
|
||||||
"station_voltage",
|
|
||||||
"station_current",
|
|
||||||
"is_open",
|
|
||||||
"is_open_msg",
|
|
||||||
"is_display",
|
|
||||||
"is_display_msg",
|
|
||||||
"sharing_code",
|
|
||||||
"sharing_applet_picture",
|
|
||||||
"theme_picture",
|
|
||||||
"is_barrier_flag",
|
|
||||||
"is_barrier_flag_msg",
|
|
||||||
"charge_settle_type",
|
|
||||||
"charge_settle_type_msg",
|
|
||||||
"fast_connector_nums",
|
|
||||||
"slow_connector_nums",
|
|
||||||
"transformer_capacity",
|
|
||||||
"installed_capacity",
|
|
||||||
"remark",
|
|
||||||
"record_unique_no",
|
|
||||||
"equipment_owner_name",
|
|
||||||
"supply_type",
|
|
||||||
"resident_no",
|
|
||||||
"watt_hour_meter_no",
|
|
||||||
"forward_power",
|
|
||||||
"operation_date",
|
|
||||||
"charge_replace_type",
|
|
||||||
"is_hlht",
|
|
||||||
"is_subsidy",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"area_code_countryside",
|
|
||||||
"business_expand_type",
|
|
||||||
"capacity",
|
|
||||||
"video_monitor",
|
|
||||||
"electricity_type",
|
|
||||||
"receive_shop"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_station"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_station"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"time_fq",
|
|
||||||
"teme_ve"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_time_day"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"time_fq",
|
|
||||||
"teme_ve"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_time_day"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_time_day"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"user_name",
|
|
||||||
"nicker_name",
|
|
||||||
"sex",
|
|
||||||
"phone",
|
|
||||||
"qk_openid",
|
|
||||||
"open_id",
|
|
||||||
"ali_user_id",
|
|
||||||
"birthday",
|
|
||||||
"avatar",
|
|
||||||
"app_type",
|
|
||||||
"password",
|
|
||||||
"upper_user",
|
|
||||||
"master_flag",
|
|
||||||
"user_type",
|
|
||||||
"multi_charge",
|
|
||||||
"relation_phone",
|
|
||||||
"user_owner_id",
|
|
||||||
"union_id",
|
|
||||||
"state",
|
|
||||||
"reg_channel",
|
|
||||||
"reg_time",
|
|
||||||
"city_label_code",
|
|
||||||
"city_label",
|
|
||||||
"reg_source",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"operator",
|
|
||||||
"invite_code",
|
|
||||||
"identity_id",
|
|
||||||
"operator_id",
|
|
||||||
"address",
|
|
||||||
"vip_level",
|
|
||||||
"province_code",
|
|
||||||
"province",
|
|
||||||
"work_company",
|
|
||||||
"is_bind_wxinfo",
|
|
||||||
"company_min_charge_balance",
|
|
||||||
"enable_online_recharge",
|
|
||||||
"integral",
|
|
||||||
"shared_user",
|
|
||||||
"enable_online_refund",
|
|
||||||
"recommenderId",
|
|
||||||
"lx_wx_user_id",
|
|
||||||
"phone_area"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_user"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"user_name",
|
|
||||||
"nicker_name",
|
|
||||||
"sex",
|
|
||||||
"phone",
|
|
||||||
"qk_openid",
|
|
||||||
"open_id",
|
|
||||||
"ali_user_id",
|
|
||||||
"birthday",
|
|
||||||
"avatar",
|
|
||||||
"app_type",
|
|
||||||
"password",
|
|
||||||
"upper_user",
|
|
||||||
"master_flag",
|
|
||||||
"user_type",
|
|
||||||
"multi_charge",
|
|
||||||
"relation_phone",
|
|
||||||
"user_owner_id",
|
|
||||||
"union_id",
|
|
||||||
"state",
|
|
||||||
"reg_channel",
|
|
||||||
"reg_time",
|
|
||||||
"city_label_code",
|
|
||||||
"city_label",
|
|
||||||
"reg_source",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"operator",
|
|
||||||
"invite_code",
|
|
||||||
"identity_id",
|
|
||||||
"operator_id",
|
|
||||||
"address",
|
|
||||||
"vip_level",
|
|
||||||
"province_code",
|
|
||||||
"province",
|
|
||||||
"work_company",
|
|
||||||
"is_bind_wxinfo",
|
|
||||||
"company_min_charge_balance",
|
|
||||||
"enable_online_recharge",
|
|
||||||
"integral",
|
|
||||||
"shared_user",
|
|
||||||
"enable_online_refund",
|
|
||||||
"recommenderId",
|
|
||||||
"lx_wx_user_id",
|
|
||||||
"phone_area"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_user"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_user"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"user_id",
|
|
||||||
"ua_balance",
|
|
||||||
"ua_deposit",
|
|
||||||
"ua_balance_time",
|
|
||||||
"ua_password",
|
|
||||||
"ua_state",
|
|
||||||
"ua_real_balance",
|
|
||||||
"ua_real_degree",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"donate_money",
|
|
||||||
"donate_able_money",
|
|
||||||
"ua_able_balance",
|
|
||||||
"refund_money",
|
|
||||||
"ua_consume_money",
|
|
||||||
"ua_clear_zero_money"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_user_account"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"user_id",
|
|
||||||
"ua_balance",
|
|
||||||
"ua_deposit",
|
|
||||||
"ua_balance_time",
|
|
||||||
"ua_password",
|
|
||||||
"ua_state",
|
|
||||||
"ua_real_balance",
|
|
||||||
"ua_real_degree",
|
|
||||||
"create_time",
|
|
||||||
"update_time",
|
|
||||||
"donate_money",
|
|
||||||
"donate_able_money",
|
|
||||||
"ua_able_balance",
|
|
||||||
"refund_money",
|
|
||||||
"ua_consume_money",
|
|
||||||
"ua_clear_zero_money"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_user_account"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_user_account"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
{
|
|
||||||
"job": {
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"reader": {
|
|
||||||
"name": "mysqlreader",
|
|
||||||
"parameter": {
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"equipment_id",
|
|
||||||
"user_id",
|
|
||||||
"fault_config_id",
|
|
||||||
"remark",
|
|
||||||
"create_time",
|
|
||||||
"update_time"
|
|
||||||
],
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": [
|
|
||||||
"${src_jdbc}"
|
|
||||||
],
|
|
||||||
"table": [
|
|
||||||
"t_user_upload_fault"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${src_user}",
|
|
||||||
"password": "${src_pwd}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"writer": {
|
|
||||||
"name": "doriswriter",
|
|
||||||
"parameter": {
|
|
||||||
"loadUrl": [
|
|
||||||
"${dest_load_url}"
|
|
||||||
],
|
|
||||||
"column": [
|
|
||||||
"id",
|
|
||||||
"equipment_id",
|
|
||||||
"user_id",
|
|
||||||
"fault_config_id",
|
|
||||||
"remark",
|
|
||||||
"create_time",
|
|
||||||
"update_time"
|
|
||||||
],
|
|
||||||
"username": "${dest_user}",
|
|
||||||
"password": "${dest_pwd}",
|
|
||||||
"postSql": [],
|
|
||||||
"preSql": [
|
|
||||||
"TRUNCATE TABLE t_user_upload_fault"
|
|
||||||
],
|
|
||||||
"flushInterval": 30000,
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_jdbc}",
|
|
||||||
"selectedDatabase": "yltcharge",
|
|
||||||
"table": [
|
|
||||||
"t_user_upload_fault"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadProps": {
|
|
||||||
"format": "json",
|
|
||||||
"strip_outer_array": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"setting": {
|
|
||||||
"speed": {
|
|
||||||
"channel": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
|
||||||
[ -f /etc/profile ] && . /etc/profile
|
|
||||||
[ -f ~/.bash_profile ] && . ~/.bash_profile
|
|
||||||
[ -f ~/.profile ] && . ~/.profile
|
|
||||||
|
|
||||||
TARGET=$1
|
|
||||||
|
|
||||||
if [ -z "$TARGET" ]; then
|
|
||||||
echo "用法: $0 <target>"
|
|
||||||
echo "请指定同步目标:"
|
|
||||||
echo " doris - 全量同步到 Doris (默认端口 9030)"
|
|
||||||
echo " mysql - 全量同步到 MySQL (CSV Load 模式,高性能)"
|
|
||||||
# echo " mysql_jdbc - 全量同步到 MySQL (JDBC Batch 模式,速度较慢)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
DATAX_HOME="/usr/local/datax"
|
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
|
||||||
CONF_DIR="$SCRIPT_DIR/json" # 更新为统一目录
|
|
||||||
BIN_DIR="$DATAX_HOME/bin"
|
|
||||||
DATAX_PY="$BIN_DIR/datax.py"
|
|
||||||
TOOL_DIR="$SCRIPT_DIR/tool"
|
|
||||||
|
|
||||||
JOBS=(
|
|
||||||
"t_equipment_charge_order.json"
|
|
||||||
"t_equipment_charge_order_detail.json"
|
|
||||||
"t_account_recharge.json"
|
|
||||||
"t_account_water.json"
|
|
||||||
"t_car.json"
|
|
||||||
"t_company.json"
|
|
||||||
"t_company_info_value.json"
|
|
||||||
"t_connector.json"
|
|
||||||
"t_equipment.json"
|
|
||||||
"t_station.json"
|
|
||||||
"t_ext_hurry_quit.json"
|
|
||||||
"t_time_day.json"
|
|
||||||
"t_user.json"
|
|
||||||
"t_user_account.json"
|
|
||||||
"t_user_upload_fault.json"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 公共源端参数
|
|
||||||
SRC_PARAMS="-Dsrc_user=ylt -Dsrc_pwd=Ycharge666 -Dsrc_jdbc=jdbc:mysql://rm-bp1ux6tuk49er80t9xo.mysql.rds.aliyuncs.com:3306/yltcharge?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"
|
|
||||||
|
|
||||||
if [ "$TARGET" == "doris" ]; then
|
|
||||||
echo "模式: Doris 全量同步"
|
|
||||||
DEST_PARAMS="-Ddest_user=root -Ddest_pwd=DsideaL147258369 -Ddest_load_url=10.10.14.204:8030 -Ddest_jdbc=jdbc:mysql://10.10.14.204:9030/yltcharge?useSSL=false"
|
|
||||||
PARAMS="$SRC_PARAMS $DEST_PARAMS"
|
|
||||||
elif [ "$TARGET" == "mysql" ]; then
|
|
||||||
echo "模式: MySQL 全量同步 (CSV Load)"
|
|
||||||
# 注意: CSV Load 模式下 DataX 负责写文件,Python 负责 Load。JDBC 参数用于 Python 连接。
|
|
||||||
DEST_PARAMS="-Ddest_mysql_user=ylt -Ddest_mysql_pwd=Ycharge666 -Ddest_mysql_jdbc=jdbc:mysql://10.10.14.210:22066/yltcharge?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowLoadLocalInfile=true"
|
|
||||||
PARAMS="$SRC_PARAMS $DEST_PARAMS"
|
|
||||||
# elif [ "$TARGET" == "mysql_jdbc" ]; then
|
|
||||||
# echo "模式: MySQL 全量同步 (JDBC Batch)"
|
|
||||||
# DEST_PARAMS="-Ddest_mysql_user=ylt -Ddest_mysql_pwd=Ycharge666 -Ddest_mysql_jdbc=jdbc:mysql://10.10.14.210:22066/yltcharge?useUnicode=true&characterEncoding=UTF-8&useSSL=false&rewriteBatchedStatements=true&autoReconnect=true&failOverReadOnly=false"
|
|
||||||
# PARAMS="$SRC_PARAMS $DEST_PARAMS"
|
|
||||||
else
|
|
||||||
echo "错误: 未知目标 '$TARGET'。请使用 'doris' 或 'mysql'。"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
SCRIPT_START_TIME=$(date '+%Y-%m-%d %H:%M:%S')
|
|
||||||
SCRIPT_START_TIMESTAMP=$(date +%s)
|
|
||||||
|
|
||||||
echo "====================================="
|
|
||||||
echo "DataX 全量同步脚本 (Target: $TARGET)"
|
|
||||||
echo "====================================="
|
|
||||||
echo "配置文件目录: $CONF_DIR"
|
|
||||||
echo "任务数量: ${#JOBS[@]}"
|
|
||||||
echo "脚本开始时间: $SCRIPT_START_TIME"
|
|
||||||
echo "====================================="
|
|
||||||
|
|
||||||
cd "$CONF_DIR" || { echo "错误: 无法进入配置文件目录 $CONF_DIR"; exit 1; }
|
|
||||||
|
|
||||||
SUCCESS_COUNT=0
|
|
||||||
FAIL_COUNT=0
|
|
||||||
TOTAL=${#JOBS[@]}
|
|
||||||
CURRENT=0
|
|
||||||
|
|
||||||
# 清理旧的 CSV 临时目录
|
|
||||||
if [ "$TARGET" == "mysql" ]; then
|
|
||||||
rm -rf "$SCRIPT_DIR/datax_tmp_csv"
|
|
||||||
fi
|
|
||||||
|
|
||||||
for JOB in "${JOBS[@]}"; do
|
|
||||||
CURRENT=$((CURRENT + 1))
|
|
||||||
echo "任务 [$CURRENT/$TOTAL] $JOB"
|
|
||||||
echo "----------------------------------------"
|
|
||||||
|
|
||||||
if [ ! -f "$JOB" ]; then
|
|
||||||
echo "✗ 错误: 文件不存在 - $JOB"
|
|
||||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
START_TIME=$(date +%s)
|
|
||||||
JOB_FILE="$JOB"
|
|
||||||
|
|
||||||
# 变量用于存储 mysql_load 模式下的元数据
|
|
||||||
TABLE_NAME=""
|
|
||||||
COLUMNS_JSON=""
|
|
||||||
CSV_DIR=""
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
# 配置转换逻辑
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
|
|
||||||
TMP_FILE="/tmp/datax_optimized_${TARGET}_${JOB}"
|
|
||||||
|
|
||||||
# 传递目标类型和 CSV 输出目录给 Python
|
|
||||||
export DATAX_TARGET="$TARGET"
|
|
||||||
if [ "$TARGET" == "mysql" ]; then
|
|
||||||
CSV_DIR="$SCRIPT_DIR/datax_tmp_csv/${JOB%.json}"
|
|
||||||
export DATAX_CSV_DIR="$CSV_DIR"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 执行 Python 转换脚本并捕获输出
|
|
||||||
TRANSFORM_OUTPUT=$(/usr/bin/python - <<'PY' "$JOB" "$TMP_FILE"
|
|
||||||
import json, sys, re, os
|
|
||||||
|
|
||||||
src_path = sys.argv[1]
|
|
||||||
dst_path = sys.argv[2]
|
|
||||||
target = os.environ.get('DATAX_TARGET', 'doris')
|
|
||||||
csv_dir = os.environ.get('DATAX_CSV_DIR', '')
|
|
||||||
|
|
||||||
with open(src_path, 'r', encoding='utf-8') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
|
|
||||||
# 1. 基础性能优化 (设置并发和内存限制)
|
|
||||||
if 'setting' not in data['job']:
|
|
||||||
data['job']['setting'] = {}
|
|
||||||
data['job']['setting']['speed'] = {
|
|
||||||
"channel": 8, # 提高并发到 8,加速 Reader 读取
|
|
||||||
}
|
|
||||||
data['job']['setting']['errorLimit'] = {
|
|
||||||
"record": 0
|
|
||||||
}
|
|
||||||
|
|
||||||
unit = data['job']['content'][0]
|
|
||||||
reader = unit.get('reader', {})
|
|
||||||
writer = unit.get('writer', {})
|
|
||||||
rp = reader.get('parameter', {})
|
|
||||||
wp = writer.get('parameter', {})
|
|
||||||
|
|
||||||
# 2. Reader 优化 (FetchSize)
|
|
||||||
rp['fetchSize'] = 10000 # 极大增加读取缓存,减少网络往返
|
|
||||||
|
|
||||||
# 获取表名
|
|
||||||
table_name = None
|
|
||||||
try:
|
|
||||||
# 优先尝试从 writer.parameter.connection[0].table[0] 获取
|
|
||||||
table_name = wp.get('connection', [{}])[0].get('table', [None])[0]
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
if not table_name:
|
|
||||||
try:
|
|
||||||
# 其次尝试从 reader.parameter.connection[0].table[0] 获取
|
|
||||||
table_name = rp.get('connection', [{}])[0].get('table', [None])[0]
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
if not table_name:
|
|
||||||
# 最后尝试从 querySql 解析
|
|
||||||
q = rp.get('connection', [{}])[0].get('querySql', [None])[0]
|
|
||||||
if q:
|
|
||||||
m = re.search(r'FROM\s+`?(\w+)`?', q, re.IGNORECASE)
|
|
||||||
if m:
|
|
||||||
table_name = m.group(1)
|
|
||||||
|
|
||||||
if not table_name:
|
|
||||||
# 如果还是没找到,使用文件名去掉 .json
|
|
||||||
table_name = os.path.basename(src_path).replace('.json', '')
|
|
||||||
|
|
||||||
# 获取列
|
|
||||||
columns = wp.get('column') or rp.get('column')
|
|
||||||
if not columns:
|
|
||||||
# 默认使用 * (虽然 DataX 不推荐,但作为兜底)
|
|
||||||
columns = ["*"]
|
|
||||||
|
|
||||||
# 3. 根据目标转换 Writer
|
|
||||||
if target == 'mysql':
|
|
||||||
if not os.path.exists(csv_dir):
|
|
||||||
os.makedirs(csv_dir)
|
|
||||||
|
|
||||||
new_writer = {
|
|
||||||
"name": "txtfilewriter",
|
|
||||||
"parameter": {
|
|
||||||
"path": csv_dir,
|
|
||||||
"fileName": table_name,
|
|
||||||
"writeMode": "truncate",
|
|
||||||
"fileFormat": "csv",
|
|
||||||
"separator": ",",
|
|
||||||
"quoteChar": "\"",
|
|
||||||
"escapeChar": "\\",
|
|
||||||
"nullFormat": "\\N",
|
|
||||||
"header": [],
|
|
||||||
"column": columns
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unit['writer'] = new_writer
|
|
||||||
|
|
||||||
# 输出元数据供 Shell 使用
|
|
||||||
print(table_name)
|
|
||||||
print(json.dumps(columns))
|
|
||||||
|
|
||||||
with open(dst_path, 'w', encoding='utf-8') as f:
|
|
||||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
|
||||||
PY
|
|
||||||
)
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "✗ 错误: 生成配置文件失败 - $JOB"
|
|
||||||
echo "$TRANSFORM_OUTPUT"
|
|
||||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
JOB_FILE="$TMP_FILE"
|
|
||||||
|
|
||||||
# 解析元数据
|
|
||||||
TABLE_NAME=$(echo "$TRANSFORM_OUTPUT" | sed -n '1p' | tr -d '\r')
|
|
||||||
COLUMNS_JSON=$(echo "$TRANSFORM_OUTPUT" | sed -n '2p' | tr -d '\r')
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
# 执行 DataX
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
|
|
||||||
# 构造 Java 命令
|
|
||||||
CLASS_PATH="$DATAX_HOME/lib/*:$DATAX_HOME/conf:."
|
|
||||||
# 优化 JVM 参数: 增大内存,使用 G1 回收器提高吞吐,增加 Metaspace 空间
|
|
||||||
JVM_OPTS="-server -Xms2g -Xmx2g -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError"
|
|
||||||
|
|
||||||
java $JVM_OPTS -classpath "$CLASS_PATH" \
|
|
||||||
-Dfile.encoding=UTF-8 \
|
|
||||||
-Dlogback.statusListenerClass=ch.qos.logback.core.status.NopStatusListener \
|
|
||||||
-Djava.security.egd=file:///dev/urandom \
|
|
||||||
-Ddatax.home="$DATAX_HOME" \
|
|
||||||
-Dlogback.configurationFile="$DATAX_HOME/conf/logback.xml" \
|
|
||||||
$PARAMS \
|
|
||||||
com.alibaba.datax.core.Engine \
|
|
||||||
-mode standalone \
|
|
||||||
-jobid -1 \
|
|
||||||
-job "$JOB_FILE" | sed "s/^/[$TABLE_NAME] /"
|
|
||||||
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
# 后置处理: mysql 模式下执行导入
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
|
|
||||||
if [ $EXIT_CODE -eq 0 ] && [ "$TARGET" == "mysql" ]; then
|
|
||||||
echo "DataX 导出完成,开始执行 MySQL Load Data..."
|
|
||||||
|
|
||||||
# 提取连接参数
|
|
||||||
# 注意: 这里简化处理,直接写死或从 PARAMS 中解析有点麻烦
|
|
||||||
# 我们直接复用脚本顶部的变量,但要注意这些变量包含 -D 前缀
|
|
||||||
# 所以最好直接传递硬编码的值或者重新定义变量
|
|
||||||
|
|
||||||
# 解析参数 (简单暴力去除 -Ddest_mysql_... 前缀)
|
|
||||||
# 这里为了稳健,我们直接使用 Python 脚本解析 JDBC URL
|
|
||||||
|
|
||||||
# 定义 DB 连接信息 (与 DEST_PARAMS 保持一致)
|
|
||||||
DB_USER="ylt"
|
|
||||||
DB_PWD="Ycharge666"
|
|
||||||
DB_JDBC="jdbc:mysql://10.10.14.210:22066/yltcharge?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowLoadLocalInfile=true"
|
|
||||||
|
|
||||||
python "$TOOL_DIR/LoadCsvToMysql.py" \
|
|
||||||
"$DB_JDBC" \
|
|
||||||
"$DB_USER" \
|
|
||||||
"$DB_PWD" \
|
|
||||||
"$TABLE_NAME" \
|
|
||||||
"$CSV_DIR" \
|
|
||||||
"$COLUMNS_JSON"
|
|
||||||
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
# 清理临时 CSV
|
|
||||||
rm -rf "$CSV_DIR"
|
|
||||||
fi
|
|
||||||
|
|
||||||
END_TIME=$(date +%s)
|
|
||||||
DURATION=$((END_TIME - START_TIME))
|
|
||||||
|
|
||||||
if [ $EXIT_CODE -eq 0 ]; then
|
|
||||||
echo "✓ 成功: $JOB 用时 ${DURATION}s"
|
|
||||||
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
|
|
||||||
else
|
|
||||||
echo "✗ 失败: $JOB 用时 ${DURATION}s (exit=$EXIT_CODE)"
|
|
||||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
||||||
fi
|
|
||||||
echo "----------------------------------------"
|
|
||||||
done
|
|
||||||
|
|
||||||
TOTAL_TIME=$(( $(date +%s) - SCRIPT_START_TIMESTAMP ))
|
|
||||||
echo "完成: 成功 $SUCCESS_COUNT, 失败 $FAIL_COUNT, 总耗时 ${TOTAL_TIME}s"
|
|
||||||
exit $([ $FAIL_COUNT -eq 0 ] && echo 0 || echo 1)
|
|
||||||
@@ -1,260 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
|
||||||
[ -f /etc/profile ] && . /etc/profile
|
|
||||||
[ -f ~/.bash_profile ] && . ~/.bash_profile
|
|
||||||
[ -f ~/.profile ] && . ~/.profile
|
|
||||||
|
|
||||||
TARGET=$1
|
|
||||||
|
|
||||||
if [ -z "$TARGET" ]; then
|
|
||||||
echo "用法: $0 <target>"
|
|
||||||
echo "请指定同步目标:"
|
|
||||||
echo " doris - 增量同步到 Doris"
|
|
||||||
echo " mysql - 增量同步到 MySQL"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
DATAX_HOME="/usr/local/datax"
|
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
|
||||||
CONF_DIR="$SCRIPT_DIR/json" # 更新为统一目录
|
|
||||||
BIN_DIR="$DATAX_HOME/bin"
|
|
||||||
DATAX_PY="$BIN_DIR/datax.py"
|
|
||||||
|
|
||||||
JOBS=(
|
|
||||||
"t_equipment_charge_order.json"
|
|
||||||
"t_equipment_charge_order_detail.json"
|
|
||||||
"t_account_recharge.json"
|
|
||||||
"t_account_water.json"
|
|
||||||
"t_car.json"
|
|
||||||
"t_company.json"
|
|
||||||
"t_company_info_value.json"
|
|
||||||
"t_connector.json"
|
|
||||||
"t_equipment.json"
|
|
||||||
"t_station.json"
|
|
||||||
"t_ext_hurry_quit.json"
|
|
||||||
"t_time_day.json"
|
|
||||||
"t_user.json"
|
|
||||||
"t_user_account.json"
|
|
||||||
"t_user_upload_fault.json"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 公共源端参数
|
|
||||||
SRC_PARAMS="-Dsrc_user=ylt -Dsrc_pwd=Ycharge666 -Dsrc_jdbc=jdbc:mysql://rm-bp1ux6tuk49er80t9xo.mysql.rds.aliyuncs.com:3306/yltcharge?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"
|
|
||||||
|
|
||||||
if [ "$TARGET" == "doris" ]; then
|
|
||||||
echo "模式: Doris 增量同步"
|
|
||||||
DEST_PARAMS="-Ddest_user=root -Ddest_pwd=DsideaL147258369 -Ddest_load_url=10.10.14.204:8030 -Ddest_jdbc=jdbc:mysql://10.10.14.204:9030/yltcharge?useSSL=false"
|
|
||||||
PARAMS="$SRC_PARAMS $DEST_PARAMS"
|
|
||||||
elif [ "$TARGET" == "mysql" ]; then
|
|
||||||
echo "模式: MySQL 增量同步 (10.10.14.210:22066)"
|
|
||||||
DEST_PARAMS="-Ddest_mysql_user=ylt -Ddest_mysql_pwd=Ycharge666 -Ddest_mysql_jdbc=jdbc:mysql://10.10.14.210:22066/yltcharge?useUnicode=true&characterEncoding=UTF-8&useSSL=false&rewriteBatchedStatements=true&autoReconnect=true&failOverReadOnly=false"
|
|
||||||
PARAMS="$SRC_PARAMS $DEST_PARAMS"
|
|
||||||
else
|
|
||||||
echo "错误: 未知目标 '$TARGET'。请使用 'doris' 或 'mysql'。"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
SCRIPT_START_TIME=$(date '+%Y-%m-%d %H:%M:%S')
|
|
||||||
SCRIPT_START_TIMESTAMP=$(date +%s)
|
|
||||||
|
|
||||||
echo "====================================="
|
|
||||||
echo "DataX 增量同步脚本 (Target: $TARGET)"
|
|
||||||
echo "====================================="
|
|
||||||
echo "配置文件目录: $CONF_DIR"
|
|
||||||
echo "任务数量: ${#JOBS[@]}"
|
|
||||||
echo "脚本开始时间: $SCRIPT_START_TIME"
|
|
||||||
echo "====================================="
|
|
||||||
|
|
||||||
cd "$CONF_DIR" || { echo "错误: 无法进入配置文件目录 $CONF_DIR"; exit 1; }
|
|
||||||
|
|
||||||
SUCCESS_COUNT=0
|
|
||||||
FAIL_COUNT=0
|
|
||||||
TOTAL=${#JOBS[@]}
|
|
||||||
CURRENT=0
|
|
||||||
|
|
||||||
for JOB in "${JOBS[@]}"; do
|
|
||||||
CURRENT=$((CURRENT + 1))
|
|
||||||
echo "任务 [$CURRENT/$TOTAL] $JOB"
|
|
||||||
echo "----------------------------------------"
|
|
||||||
|
|
||||||
if [ ! -f "$JOB" ]; then
|
|
||||||
echo "✗ 错误: 文件不存在 - $JOB"
|
|
||||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
START_TIME=$(date +%s)
|
|
||||||
JOB_FILE="$JOB"
|
|
||||||
|
|
||||||
# 生成临时配置文件: 修改 Reader 为 querySql (增量逻辑) 且根据目标修改 Writer
|
|
||||||
TMP_FILE="/tmp/datax_inc_${TARGET}_${JOB}"
|
|
||||||
|
|
||||||
# 传递目标类型给 Python 脚本
|
|
||||||
export DATAX_TARGET="$TARGET"
|
|
||||||
|
|
||||||
/usr/bin/python - <<'PY' "$JOB" "$TMP_FILE"
|
|
||||||
import json, sys, os, re
|
|
||||||
|
|
||||||
src_path = sys.argv[1]
|
|
||||||
dst_path = sys.argv[2]
|
|
||||||
target = os.environ.get('DATAX_TARGET', 'doris')
|
|
||||||
|
|
||||||
with open(src_path, 'r', encoding='utf-8') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
|
|
||||||
# 0. 基础性能优化 (设置并发和内存限制)
|
|
||||||
if 'setting' not in data['job']:
|
|
||||||
data['job']['setting'] = {}
|
|
||||||
data['job']['setting']['speed'] = {
|
|
||||||
"channel": 8, # 提高并发到 8
|
|
||||||
}
|
|
||||||
|
|
||||||
unit = data['job']['content'][0]
|
|
||||||
reader = unit.get('reader', {})
|
|
||||||
writer = unit.get('writer', {})
|
|
||||||
rp = reader.get('parameter', {})
|
|
||||||
wp = writer.get('parameter', {})
|
|
||||||
|
|
||||||
# 0.1 Reader 优化 (FetchSize)
|
|
||||||
rp['fetchSize'] = 10000 # 极大增加读取缓存,减少网络往返
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
# 1. Reader 转换: 从 table 模式转换为 querySql 模式 (增量逻辑)
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
|
|
||||||
# 获取列列表
|
|
||||||
columns = rp.get('column')
|
|
||||||
if not columns:
|
|
||||||
# 尝试从 writer 获取
|
|
||||||
columns = wp.get('column')
|
|
||||||
|
|
||||||
if not columns:
|
|
||||||
# 兜底
|
|
||||||
columns = ["*"]
|
|
||||||
|
|
||||||
# 获取表名
|
|
||||||
table_name = None
|
|
||||||
try:
|
|
||||||
table_name = rp.get('connection', [{}])[0].get('table', [None])[0]
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not table_name:
|
|
||||||
# 尝试从 querySql 解析 (如果源文件已经是 querySql 模式)
|
|
||||||
try:
|
|
||||||
q = rp.get('connection', [{}])[0].get('querySql', [None])[0]
|
|
||||||
if q:
|
|
||||||
m = re.search(r'FROM\s+`?(\w+)`?', q, re.IGNORECASE)
|
|
||||||
if m:
|
|
||||||
table_name = m.group(1)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not table_name:
|
|
||||||
# 兜底:使用文件名
|
|
||||||
table_name = os.path.basename(src_path).replace('.json', '')
|
|
||||||
|
|
||||||
# 构建增量查询 SQL: SELECT col1, col2... FROM table ORDER BY id DESC LIMIT 1000
|
|
||||||
# 注意: 这里假设所有表都有 id 列。如果无 id 列,可能需要特殊处理。
|
|
||||||
has_id = 'id' in columns or columns == ["*"] # 如果是 *,我们尝试加上 id 排序
|
|
||||||
|
|
||||||
if has_id:
|
|
||||||
# 构建列字符串,处理反引号
|
|
||||||
if columns == ["*"]:
|
|
||||||
col_str = "*"
|
|
||||||
else:
|
|
||||||
col_str = ", ".join(["`{}`".format(c) for c in columns])
|
|
||||||
inc_sql = "SELECT {} FROM `{}` ORDER BY id DESC LIMIT 1000".format(col_str, table_name)
|
|
||||||
|
|
||||||
# 更新 Reader 配置
|
|
||||||
new_reader_conn = [
|
|
||||||
{
|
|
||||||
"jdbcUrl": rp.get('connection', [{}])[0].get('jdbcUrl', ["${src_jdbc}"]),
|
|
||||||
"querySql": [inc_sql]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
rp['connection'] = new_reader_conn
|
|
||||||
# 清除 table 和 where 参数,因为 querySql 模式下这些通常不生效或冲突
|
|
||||||
if 'table' in rp: del rp['table']
|
|
||||||
if 'where' in rp: del rp['where']
|
|
||||||
else:
|
|
||||||
print("警告: 表 %s 没有 id 列,无法使用 ORDER BY id DESC 策略,保持原样" % table_name)
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
# 2. Writer 转换: 如果目标是 MySQL,转换为 mysqlwriter
|
|
||||||
# ---------------------------------------------------------
|
|
||||||
|
|
||||||
if target == 'mysql':
|
|
||||||
new_writer = {
|
|
||||||
"name": "mysqlwriter",
|
|
||||||
"parameter": {
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"jdbcUrl": "${dest_mysql_jdbc}",
|
|
||||||
"table": [table_name]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "${dest_mysql_user}",
|
|
||||||
"password": "${dest_mysql_pwd}",
|
|
||||||
"column": columns,
|
|
||||||
"writeMode": "replace", # 增量同步使用 replace 模式
|
|
||||||
"batchSize": 2048,
|
|
||||||
"preSql": [],
|
|
||||||
"postSql": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unit['writer'] = new_writer
|
|
||||||
|
|
||||||
# 输出表名供 Shell 使用
|
|
||||||
print(table_name)
|
|
||||||
|
|
||||||
with open(dst_path, 'w', encoding='utf-8') as f:
|
|
||||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
|
||||||
PY
|
|
||||||
)
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "✗ 错误: 生成增量配置文件失败 - $JOB"
|
|
||||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 提取 Python 输出的第一行作为表名
|
|
||||||
TABLE_NAME=$(echo "$TRANSFORM_OUTPUT" | sed -n '1p' | tr -d '\r')
|
|
||||||
JOB_FILE="$TMP_FILE"
|
|
||||||
|
|
||||||
# 构造 Java 命令
|
|
||||||
CLASS_PATH="$DATAX_HOME/lib/*:$DATAX_HOME/conf:."
|
|
||||||
# 优化 JVM 参数: 增大内存,使用 G1 回收器提高吞吐,增加 Metaspace 空间
|
|
||||||
JVM_OPTS="-server -Xms2g -Xmx2g -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError"
|
|
||||||
|
|
||||||
java $JVM_OPTS -classpath "$CLASS_PATH" \
|
|
||||||
-Dfile.encoding=UTF-8 \
|
|
||||||
-Dlogback.statusListenerClass=ch.qos.logback.core.status.NopStatusListener \
|
|
||||||
-Djava.security.egd=file:///dev/urandom \
|
|
||||||
-Ddatax.home="$DATAX_HOME" \
|
|
||||||
-Dlogback.configurationFile="$DATAX_HOME/conf/logback.xml" \
|
|
||||||
$PARAMS \
|
|
||||||
com.alibaba.datax.core.Engine \
|
|
||||||
-mode standalone \
|
|
||||||
-jobid -1 \
|
|
||||||
-job "$JOB_FILE" | sed "s/^/[$TABLE_NAME] /"
|
|
||||||
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
END_TIME=$(date +%s)
|
|
||||||
DURATION=$((END_TIME - START_TIME))
|
|
||||||
|
|
||||||
if [ $EXIT_CODE -eq 0 ]; then
|
|
||||||
echo "✓ 成功: $JOB 用时 ${DURATION}s"
|
|
||||||
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
|
|
||||||
else
|
|
||||||
echo "✗ 失败: $JOB 用时 ${DURATION}s (exit=$EXIT_CODE)"
|
|
||||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
||||||
fi
|
|
||||||
echo "----------------------------------------"
|
|
||||||
done
|
|
||||||
|
|
||||||
TOTAL_TIME=$(( $(date +%s) - SCRIPT_START_TIMESTAMP ))
|
|
||||||
echo "完成: 成功 $SUCCESS_COUNT, 失败 $FAIL_COUNT, 总耗时 ${TOTAL_TIME}s"
|
|
||||||
exit $([ $FAIL_COUNT -eq 0 ] && echo 0 || echo 1)
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
TARGET=$1
|
|
||||||
|
|
||||||
if [ -z "$TARGET" ]; then
|
|
||||||
echo "用法: $0 <target>"
|
|
||||||
echo "请指定同步目标:"
|
|
||||||
echo " doris - 启动 Doris 增量同步定时任务"
|
|
||||||
echo " mysql - 启动 MySQL 增量同步定时任务"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$TARGET" != "doris" ] && [ "$TARGET" != "mysql" ]; then
|
|
||||||
echo "错误: 请指定目标 (doris 或 mysql)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
WORK_DIR="/usr/local/datax"
|
|
||||||
SCRIPT_NAME="run_jobs_inc.sh"
|
|
||||||
SCRIPT_PATH="$WORK_DIR/$SCRIPT_NAME"
|
|
||||||
LOG_FILE="$WORK_DIR/logs/datax_inc_${TARGET}_cron.log"
|
|
||||||
|
|
||||||
export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
|
||||||
[ -f /etc/profile ] && . /etc/profile
|
|
||||||
[ -f ~/.bash_profile ] && . ~/.bash_profile
|
|
||||||
[ -f ~/.profile ] && . ~/.profile
|
|
||||||
|
|
||||||
echo "正在检查环境..."
|
|
||||||
if [ ! -d "$WORK_DIR" ]; then
|
|
||||||
echo "错误: 工作目录 $WORK_DIR 不存在"; exit 1
|
|
||||||
fi
|
|
||||||
if [ ! -f "$SCRIPT_PATH" ]; then
|
|
||||||
echo "错误: 执行脚本 $SCRIPT_PATH 不存在"; exit 1
|
|
||||||
fi
|
|
||||||
if [ ! -d "$(dirname "$LOG_FILE")" ]; then
|
|
||||||
mkdir -p "$(dirname "$LOG_FILE")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
chmod +x "$SCRIPT_PATH"
|
|
||||||
# 构造 cron 命令,注意转义和参数传递
|
|
||||||
# 修改为每 5 秒运行一次 (通过循环实现,因为 crontab 最小粒度是分钟)
|
|
||||||
CRON_CMD="* * * * * for i in {1..12}; do /bin/bash $SCRIPT_PATH $TARGET >> $LOG_FILE 2>&1; sleep 5; done"
|
|
||||||
|
|
||||||
# 查找已存在的任务 (匹配脚本路径和目标参数)
|
|
||||||
EXISTING_JOB=$(crontab -l 2>/dev/null | grep "$SCRIPT_PATH $TARGET")
|
|
||||||
|
|
||||||
if [ -n "$EXISTING_JOB" ]; then
|
|
||||||
echo "提示: 该任务已存在,将先删除旧任务再重新添加..."
|
|
||||||
crontab -l 2>/dev/null | grep -v "$SCRIPT_PATH $TARGET" | crontab -
|
|
||||||
fi
|
|
||||||
|
|
||||||
(crontab -l 2>/dev/null; echo "$CRON_CMD") | crontab -
|
|
||||||
|
|
||||||
echo "✅ $TARGET 增量定时任务设置成功"
|
|
||||||
crontab -l
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
TARGET=$1
|
|
||||||
|
|
||||||
if [ -z "$TARGET" ]; then
|
|
||||||
echo "用法: $0 <target>"
|
|
||||||
echo "请指定同步目标:"
|
|
||||||
echo " doris - 停止 Doris 增量同步定时任务"
|
|
||||||
echo " mysql - 停止 MySQL 增量同步定时任务"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$TARGET" != "doris" ] && [ "$TARGET" != "mysql" ]; then
|
|
||||||
echo "错误: 请指定目标 (doris 或 mysql)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
WORK_DIR="/usr/local/datax"
|
|
||||||
SCRIPT_NAME="run_jobs_inc.sh"
|
|
||||||
SCRIPT_PATH="$WORK_DIR/$SCRIPT_NAME"
|
|
||||||
|
|
||||||
export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
|
||||||
[ -f /etc/profile ] && . /etc/profile
|
|
||||||
[ -f ~/.bash_profile ] && . ~/.bash_profile
|
|
||||||
[ -f ~/.profile ] && . ~/.profile
|
|
||||||
|
|
||||||
echo "正在检查定时任务..."
|
|
||||||
# 精确匹配包含脚本路径和参数的行
|
|
||||||
EXISTING_JOB=$(crontab -l 2>/dev/null | grep "$SCRIPT_PATH $TARGET")
|
|
||||||
|
|
||||||
if [ -z "$EXISTING_JOB" ]; then
|
|
||||||
echo "提示: 未发现 $TARGET 增量任务,无需停止。"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
BACKUP_FILE="/tmp/crontab_backup_$(date +%Y%m%d_%H%M%S).txt"
|
|
||||||
crontab -l > "$BACKUP_FILE" 2>/dev/null
|
|
||||||
# 删除特定任务
|
|
||||||
crontab -l 2>/dev/null | grep -v "$SCRIPT_PATH $TARGET" | crontab -
|
|
||||||
|
|
||||||
REMAINING_JOB=$(crontab -l 2>/dev/null | grep "$SCRIPT_PATH $TARGET")
|
|
||||||
if [ -z "$REMAINING_JOB" ]; then
|
|
||||||
echo "✅ $TARGET 增量定时任务已停止"
|
|
||||||
crontab -l
|
|
||||||
else
|
|
||||||
echo "❌ 停止失败,请手动执行: crontab -e"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
import pymysql
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import glob
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
from urllib.parse import urlparse, parse_qs
|
|
||||||
|
|
||||||
def parse_jdbc_url(url):
|
|
||||||
# jdbc:mysql://host:port/db?params
|
|
||||||
# remove jdbc:mysql://
|
|
||||||
if url.startswith("jdbc:mysql://"):
|
|
||||||
url = url[13:]
|
|
||||||
|
|
||||||
# split host:port and db
|
|
||||||
if "/" in url:
|
|
||||||
address, remainder = url.split("/", 1)
|
|
||||||
if "?" in remainder:
|
|
||||||
db, params = remainder.split("?", 1)
|
|
||||||
else:
|
|
||||||
db = remainder
|
|
||||||
params = ""
|
|
||||||
else:
|
|
||||||
address = url
|
|
||||||
db = ""
|
|
||||||
params = ""
|
|
||||||
|
|
||||||
if ":" in address:
|
|
||||||
host, port = address.split(":")
|
|
||||||
port = int(port)
|
|
||||||
else:
|
|
||||||
host = address
|
|
||||||
port = 3306
|
|
||||||
|
|
||||||
return host, port, db
|
|
||||||
|
|
||||||
def load_csv(jdbc_url, user, password, table, csv_dir, columns=None):
|
|
||||||
host, port, db = parse_jdbc_url(jdbc_url)
|
|
||||||
|
|
||||||
print(f"Connecting to MySQL {host}:{port}/{db} as {user}...")
|
|
||||||
|
|
||||||
try:
|
|
||||||
conn = pymysql.connect(
|
|
||||||
host=host,
|
|
||||||
port=port,
|
|
||||||
user=user,
|
|
||||||
password=password,
|
|
||||||
database=db,
|
|
||||||
local_infile=True,
|
|
||||||
charset='utf8mb4',
|
|
||||||
cursorclass=pymysql.cursors.DictCursor
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Connection failed: {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
with conn.cursor() as cursor:
|
|
||||||
# Optimization settings
|
|
||||||
print("Setting session parameters for speed...")
|
|
||||||
cursor.execute("SET NAMES utf8mb4")
|
|
||||||
|
|
||||||
# 逐个尝试设置优化参数,避免因单个参数(如 SQL_LOG_BIN)权限不足导致整体失败
|
|
||||||
opts = [
|
|
||||||
("SET FOREIGN_KEY_CHECKS = 0", "Foreign Key Checks Disabled"),
|
|
||||||
("SET UNIQUE_CHECKS = 0", "Unique Checks Disabled"),
|
|
||||||
("SET SQL_LOG_BIN = 0", "Binary Logging Disabled (Requires SUPER privilege)")
|
|
||||||
]
|
|
||||||
|
|
||||||
for sql, desc in opts:
|
|
||||||
try:
|
|
||||||
cursor.execute(sql)
|
|
||||||
print(f" - {desc}: Success")
|
|
||||||
except Exception as e:
|
|
||||||
# 如果是权限问题 (1227),打印更友好的信息
|
|
||||||
if "1227" in str(e):
|
|
||||||
print(f" - {desc}: Skipped (Insufficient privileges, but that's okay)")
|
|
||||||
else:
|
|
||||||
print(f" - {desc}: Failed ({e})")
|
|
||||||
|
|
||||||
# Truncate table
|
|
||||||
print(f"Truncating table {table}...")
|
|
||||||
cursor.execute(f"TRUNCATE TABLE `{table}`")
|
|
||||||
|
|
||||||
# Find files
|
|
||||||
files = glob.glob(os.path.join(csv_dir, "*"))
|
|
||||||
if not files:
|
|
||||||
print(f"No files found in {csv_dir}")
|
|
||||||
return
|
|
||||||
|
|
||||||
total_rows = 0
|
|
||||||
start_time = time.time()
|
|
||||||
|
|
||||||
for file_path in files:
|
|
||||||
file_path = os.path.abspath(file_path).replace('\\', '/')
|
|
||||||
print(f"Loading file: {file_path}")
|
|
||||||
|
|
||||||
# Build SQL
|
|
||||||
# Assuming DataX txtfilewriter defaults:
|
|
||||||
# separator: ,
|
|
||||||
# quoteChar: "
|
|
||||||
# escapeChar: \
|
|
||||||
# nullFormat: \N
|
|
||||||
|
|
||||||
col_sql = ""
|
|
||||||
if columns:
|
|
||||||
col_list = [f"`{c}`" for c in columns]
|
|
||||||
col_sql = "(" + ", ".join(col_list) + ")"
|
|
||||||
|
|
||||||
sql = f"""
|
|
||||||
LOAD DATA LOCAL INFILE '{file_path}'
|
|
||||||
INTO TABLE `{table}`
|
|
||||||
CHARACTER SET utf8mb4
|
|
||||||
FIELDS TERMINATED BY ','
|
|
||||||
OPTIONALLY ENCLOSED BY '"'
|
|
||||||
ESCAPED BY '\\\\'
|
|
||||||
LINES TERMINATED BY '\\n'
|
|
||||||
{col_sql}
|
|
||||||
"""
|
|
||||||
|
|
||||||
cursor.execute(sql)
|
|
||||||
rows = cursor.rowcount
|
|
||||||
total_rows += rows
|
|
||||||
print(f" -> Loaded {rows} rows")
|
|
||||||
|
|
||||||
# 显示 MySQL 警告(SHOW WARNINGS)的功能,用于排查导入差异
|
|
||||||
try:
|
|
||||||
cursor.execute("SHOW WARNINGS")
|
|
||||||
warnings = cursor.fetchall()
|
|
||||||
if warnings:
|
|
||||||
print(f" - MySQL Warnings ({len(warnings)}):")
|
|
||||||
# 最多显示前 5 条警告,避免日志过多
|
|
||||||
for i, warn in enumerate(warnings[:5]):
|
|
||||||
print(f" - {warn.get('Level', 'Warning')}: {warn.get('Message', 'Unknown error')}")
|
|
||||||
if len(warnings) > 5:
|
|
||||||
print(f" - ... and {len(warnings) - 5} more warnings")
|
|
||||||
except Exception as warn_e:
|
|
||||||
print(f" - Could not fetch warnings: {warn_e}")
|
|
||||||
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
duration = time.time() - start_time
|
|
||||||
print(f"Total loaded: {total_rows} rows in {duration:.2f}s ({total_rows/duration if duration > 0 else 0:.2f} rows/s)")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error during load: {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
finally:
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(sys.argv) < 6:
|
|
||||||
print("Usage: python LoadCsvToMysql.py <jdbc_url> <user> <password> <table> <csv_dir> [columns_json]")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
jdbc_url = sys.argv[1]
|
|
||||||
user = sys.argv[2]
|
|
||||||
password = sys.argv[3]
|
|
||||||
table = sys.argv[4]
|
|
||||||
csv_dir = sys.argv[5]
|
|
||||||
|
|
||||||
columns = None
|
|
||||||
if len(sys.argv) > 6:
|
|
||||||
try:
|
|
||||||
columns = json.loads(sys.argv[6])
|
|
||||||
except:
|
|
||||||
print("Warning: Could not parse columns JSON")
|
|
||||||
|
|
||||||
load_csv(jdbc_url, user, password, table, csv_dir, columns)
|
|
||||||
139
DataX/说明.md
139
DataX/说明.md
@@ -1,139 +0,0 @@
|
|||||||
# DataX 同步部署与使用说明
|
|
||||||
|
|
||||||
#### 一、下载与安装 DataX
|
|
||||||
|
|
||||||
1. **下载 DataX 包**
|
|
||||||
官方下载地址:https://datax-opensource.oss-cn-hangzhou.aliyuncs.com/202309/datax.tar.gz
|
|
||||||
|
|
||||||
2. **部署到服务器**
|
|
||||||
将压缩包上传并解压到 `/usr/local/` 目录:
|
|
||||||
```shell
|
|
||||||
cd /usr/local
|
|
||||||
tar zxvf datax.tar.gz
|
|
||||||
# 解压后应当存在 /usr/local/datax 目录
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 二、配置部署
|
|
||||||
|
|
||||||
本方案通过一套脚本支持 **Doris** 和 **MySQL** 的同步,并统一了 JSON 配置目录。
|
|
||||||
|
|
||||||
1. **环境准备 (重要)**
|
|
||||||
高性能同步工具依赖 Python 的 MySQL 驱动,请先在服务器执行以下命令安装:
|
|
||||||
```shell
|
|
||||||
# Rocky Linux / CentOS 9
|
|
||||||
yum install -y python3-PyMySQL
|
|
||||||
|
|
||||||
# 验证安装 (返回“成功”即表示OK)
|
|
||||||
python3 -c "import pymysql; print('成功')"
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **上传文件**
|
|
||||||
请将本地 `d:\dsWork\aiData\DataX\` 目录下的以下内容上传至服务器 `/usr/local/datax/` 根目录下:
|
|
||||||
|
|
||||||
* 文件夹 `json/` (存放统一的 JSON 模板)
|
|
||||||
* 文件夹 `tool/` (存放高性能导入工具)
|
|
||||||
* 脚本 `run_jobs_full.sh` (全量执行脚本)
|
|
||||||
* 脚本 `run_jobs_inc.sh` (增量执行脚本)
|
|
||||||
* 脚本 `start_cron_inc.sh`(启动定时任务)
|
|
||||||
* 脚本 `stop_cron_inc.sh` (停止定时任务)
|
|
||||||
|
|
||||||
**上传后的服务器目录结构应如下所示:**
|
|
||||||
```text
|
|
||||||
/usr/local/datax/
|
|
||||||
├── bin/
|
|
||||||
├── conf/
|
|
||||||
├── json/ <-- 统一配置目录 (包含全量/增量通用模板)
|
|
||||||
├── tool/ <-- 导入工具目录 (包含 LoadCsvToMysql.py)
|
|
||||||
├── run_jobs_full.sh <-- 全量同步脚本 (支持 doris/mysql)
|
|
||||||
├── run_jobs_inc.sh <-- 增量同步脚本 (支持 doris/mysql)
|
|
||||||
├── start_cron_inc.sh<-- 启动增量定时任务
|
|
||||||
└── stop_cron_inc.sh <-- 停止增量定时任务
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **赋予执行权限**
|
|
||||||
```shell
|
|
||||||
cd /usr/local/datax
|
|
||||||
chmod +x *.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 三、运行策略说明
|
|
||||||
|
|
||||||
脚本现在支持通过参数指定同步目标:`doris` 或 `mysql`。
|
|
||||||
|
|
||||||
**1. 全量同步 (Full Sync)**
|
|
||||||
* **适用场景**:系统初始化,或数据需要彻底重刷。
|
|
||||||
* **同步逻辑**:
|
|
||||||
1. **Doris**: 使用 `TRUNCATE` 清空目标表,通过 Stream Load 写入。
|
|
||||||
2. **MySQL**: 自动切换为 **CSV Load 模式**(高性能),通过生成 CSV 并执行 `LOAD DATA LOCAL INFILE` 实现秒级同步。
|
|
||||||
* **执行命令**:
|
|
||||||
```shell
|
|
||||||
./run_jobs_full.sh doris # 同步到 Doris
|
|
||||||
./run_jobs_full.sh mysql # 同步到 MySQL
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. 增量同步 (Incremental Sync)**
|
|
||||||
* **适用场景**:日常实时数据同步。
|
|
||||||
* **同步逻辑**:
|
|
||||||
1. **动态 SQL**: 自动解析模板并生成 `ORDER BY id DESC LIMIT 1000` 查询。
|
|
||||||
2. **Upsert**: 利用目标库主键模型自动完成“存在即更新,不存在即插入”。
|
|
||||||
* **执行命令**:
|
|
||||||
```shell
|
|
||||||
./run_jobs_inc.sh doris # 同步到 Doris
|
|
||||||
./run_jobs_inc.sh mysql # 同步到 MySQL
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 四、自动化定时任务配置
|
|
||||||
|
|
||||||
增量同步已优化为 **高频实时同步**。
|
|
||||||
|
|
||||||
1. **启动定时任务**
|
|
||||||
```shell
|
|
||||||
./start_cron_inc.sh doris # 启动同步到 Doris 的任务
|
|
||||||
./start_cron_inc.sh mysql # 启动同步到 MySQL 的任务
|
|
||||||
```
|
|
||||||
* **执行频率**: 每 **5 秒** 执行一次。
|
|
||||||
* **单次数据量**: 每次同步最新的 **1000 条**。
|
|
||||||
|
|
||||||
2. **停止定时任务**
|
|
||||||
```shell
|
|
||||||
./stop_cron_inc.sh doris
|
|
||||||
./stop_cron_inc.sh mysql
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **验证与日志**
|
|
||||||
* **查看任务**:`crontab -l`
|
|
||||||
* **查看日志**:日志保存在 `logs/` 目录下。
|
|
||||||
```shell
|
|
||||||
tail -f logs/datax_inc_mysql_cron.log
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 五、重要性能说明与测试报告
|
|
||||||
|
|
||||||
本方案针对 MySQL 到 MySQL/Doris 的同步进行了深度榨干级的性能优化,实测效果惊人。
|
|
||||||
|
|
||||||
**1. 性能实测报告 (2026-02-06 百万级数据实测)**
|
|
||||||
* **同步数据量**: **278 万条** (2.78 Million Records)。
|
|
||||||
* **同步速率**: 稳定在 **11,500 ~ 12,000 条/秒**。
|
|
||||||
* **吞吐量**: 稳定在 **6.5 ~ 6.8 MB/s**。
|
|
||||||
* **内存表现**:
|
|
||||||
* **Eden Space**: 占用约 650MB (50%),内存分配非常充裕。
|
|
||||||
* **GC 效率**: G1 回收器表现极佳,72次 Young GC 总耗时仅 **0.597秒**(平均每次仅 **8ms**),对同步性能零干扰。
|
|
||||||
* **稳定性**: 全程 0 错误,`WaitWriterTime` 极低 (0.7s),写入端完全无压力。
|
|
||||||
|
|
||||||
**2. 核心技术优化揭秘**
|
|
||||||
* **消除 SSL 握手开销**:
|
|
||||||
* 在 JDBC 连接中强制指定 `useSSL=false`。
|
|
||||||
* **效果**: 既消除了日志中的安全警告,也减少了每次连接建立时的加密握手时间,在高频同步场景下提升显著。
|
|
||||||
* **Reader 侧吞吐量暴增**:
|
|
||||||
* **高并发**: 将 `channel` 提升至 **8**,并行抽取能力翻倍。
|
|
||||||
* **大缓存**: 将 `fetchSize` 提升至 **10,000**。这是解决 `WaitReaderTime` 的核心,极大减少了 DataX 与源数据库之间的交互次数。
|
|
||||||
* **CSV Load 模式 (全量核心)**:
|
|
||||||
* 通过 Python 脚本自动将 DataX 转换为 `txtfilewriter` 生成 CSV。
|
|
||||||
* 利用 MySQL 官方最快的 `LOAD DATA LOCAL INFILE` 导入,比传统 JDBC `INSERT` 快 **30倍** 以上。
|
|
||||||
* **JDBC Batch 优化 (增量/JDBC 模式)**:
|
|
||||||
* 启用了 `rewriteBatchedStatements=true`,将多条 `REPLACE` 语句合并为单条执行,大幅降低网络往返。
|
|
||||||
|
|
||||||
**3. 最终优化参数清单**
|
|
||||||
* **Reader**: `channel=8`, `fetchSize=10000`, `useSSL=false`。
|
|
||||||
* **Writer**: `batchSize=2048`, `rewriteBatchedStatements=true`, `LOAD DATA` (全量)。
|
|
||||||
* **JVM**: `-server -Xms2g -Xmx2g -XX:+UseG1GC -XX:MaxMetaspaceSize=256m`。
|
|
||||||
176
DouYin/Test/T1_GetCookie.py
Normal file
176
DouYin/Test/T1_GetCookie.py
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
"""
|
||||||
|
Douyin Cookie Fetcher (T1)
|
||||||
|
用途: 模拟打开浏览器,用户扫码登录后自动获取 Cookie 并保存到 config_douyin.yml
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import yaml
|
||||||
|
import asyncio
|
||||||
|
import io
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# 强制设置控制台输出编码为 UTF-8,解决 Windows 环境下的乱码问题
|
||||||
|
if sys.platform.startswith('win'):
|
||||||
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||||
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# 1. 环境配置与路径初始化
|
||||||
|
# =================================================================
|
||||||
|
current_file_path = os.path.abspath(__file__)
|
||||||
|
current_dir = os.path.dirname(current_file_path)
|
||||||
|
config_path = os.path.join(current_dir, "config_douyin.yml")
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# 2. Cookie 过滤与更新逻辑
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
# 我们关注的核心 Cookie 键名
|
||||||
|
# 进一步扩大范围以包含所有可能的校验 Cookie
|
||||||
|
REQUIRED_KEYS = {
|
||||||
|
"msToken", "ttwid", "odin_tt", "passport_csrf_token", "sid_guard",
|
||||||
|
"sessionid", "sid_tt", "uid_tt", "uid_tt_ss", "sid_ucp_v1",
|
||||||
|
"ssid_ucp_v1", "n_sdk_version", "s_v_web_id", "webid",
|
||||||
|
"__ac_nonce", "__ac_signature", "fp", "device_web_cpu_core",
|
||||||
|
"device_web_memory_size", "architecture", "hevc_supported"
|
||||||
|
}
|
||||||
|
|
||||||
|
def update_config_yaml(new_cookies):
|
||||||
|
"""将获取到的 Cookie 更新到 config_douyin.yml"""
|
||||||
|
config_data = {}
|
||||||
|
|
||||||
|
# 1. 读取现有配置
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
try:
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
config_data = yaml.safe_load(f) or {}
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ Warning ]: Failed to read existing config: {e}")
|
||||||
|
|
||||||
|
# 2. 更新 cookies 字段
|
||||||
|
if "cookies" not in config_data:
|
||||||
|
config_data["cookies"] = {}
|
||||||
|
|
||||||
|
# 过滤出我们需要的键
|
||||||
|
filtered_cookies = {k: v for k, v in new_cookies.items() if k in REQUIRED_KEYS}
|
||||||
|
config_data["cookies"].update(filtered_cookies)
|
||||||
|
|
||||||
|
# 同时更新全局 cookie 字符串 - 包含所有捕获到的 cookie 以确保完整性
|
||||||
|
cookie_str = "; ".join(f"{k}={v}" for k, v in new_cookies.items())
|
||||||
|
config_data["cookie"] = cookie_str
|
||||||
|
|
||||||
|
# 3. 写回文件
|
||||||
|
try:
|
||||||
|
with open(config_path, 'w', encoding='utf-8') as f:
|
||||||
|
yaml.dump(config_data, f, allow_unicode=True, default_flow_style=False, sort_keys=False)
|
||||||
|
print(f"\n[ Success ]: Cookie updated to: {config_path}")
|
||||||
|
print(f"[ Info ]: Captured {len(new_cookies)} total cookies, {len(filtered_cookies)} essential keys saved.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ Error ]: Failed to write config: {e}")
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# 3. Playwright 自动化逻辑
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
try:
|
||||||
|
from playwright.async_api import async_playwright
|
||||||
|
except ImportError:
|
||||||
|
print("[ Error ]: Playwright not installed. Run: pip install playwright && playwright install chromium")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print(" Douyin Login & Cookie Fetcher")
|
||||||
|
print("="*60)
|
||||||
|
print("[ Instructions ]:")
|
||||||
|
print("1. Browser will open and navigate to Douyin.")
|
||||||
|
print("2. Please login via QR code scanning.")
|
||||||
|
print("3. After login, return here and press [ENTER] to save cookies.")
|
||||||
|
print("="*60 + "\n")
|
||||||
|
|
||||||
|
async with async_playwright() as p:
|
||||||
|
# 启动浏览器
|
||||||
|
browser = await p.chromium.launch(headless=False)
|
||||||
|
context = await browser.new_context(
|
||||||
|
viewport={'width': 1280, 'height': 800},
|
||||||
|
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36'
|
||||||
|
)
|
||||||
|
page = await context.new_page()
|
||||||
|
|
||||||
|
# 跳转到抖音
|
||||||
|
# 优化: 使用 'domcontentloaded' 提高在弱网环境下的加载成功率,并增加超时到 90s
|
||||||
|
print("[ Navigating ]: https://www.douyin.com/ ...")
|
||||||
|
try:
|
||||||
|
await page.goto("https://www.douyin.com/", wait_until="domcontentloaded", timeout=90000)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ Warning ]: Initial navigation timed out or failed: {e}")
|
||||||
|
print("[ Info ]: Will continue anyway, please check if the page is visible.")
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# 自动检测登录 + 手动回车双重保险
|
||||||
|
# =================================================================
|
||||||
|
print("\n" + "-"*40)
|
||||||
|
print("[ Waiting ]: Please complete the QR login in the browser.")
|
||||||
|
print("[ Auto-Detect ]: The script will automatically proceed if login is detected.")
|
||||||
|
print("[ Manual ]: If auto-detect fails, type 'go' and press [ENTER] here.")
|
||||||
|
print("-"*40 + "\n")
|
||||||
|
|
||||||
|
# 尝试自动检测登录成功的元素(比如头像或“发布视频”按钮)
|
||||||
|
login_detected = False
|
||||||
|
for _ in range(120): # 最多等待 120 秒
|
||||||
|
try:
|
||||||
|
# 检查是否存在登录后的特有元素
|
||||||
|
# .dy-avatar 是头像,.upload-video-text 是发布视频按钮
|
||||||
|
if await page.query_selector('.dy-avatar') or await page.query_selector('text=发布视频'):
|
||||||
|
print("[ Success ]: Login detected automatically!")
|
||||||
|
login_detected = True
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
if not login_detected:
|
||||||
|
# 如果自动检测没成功,再尝试手动输入
|
||||||
|
print("[ Timeout ]: Auto-detection timed out. Please ensure you are logged in.")
|
||||||
|
print("[ Action ]: Type anything and press [ENTER] to force capture cookies:")
|
||||||
|
await asyncio.to_thread(sys.stdin.readline)
|
||||||
|
|
||||||
|
# 获取所有 Cookie
|
||||||
|
all_cookies = await context.cookies()
|
||||||
|
cookie_dict = {c['name']: c['value'] for c in all_cookies}
|
||||||
|
|
||||||
|
# 尝试捕获动态参数 msToken (如果存在于页面中)
|
||||||
|
try:
|
||||||
|
# 1. 尝试从 localStorage 获取
|
||||||
|
ms_token = await page.evaluate("() => window.localStorage.getItem('msToken') || ''")
|
||||||
|
|
||||||
|
# 2. 如果没获取到,尝试从所有 Cookie 中找最新的 msToken
|
||||||
|
if not ms_token:
|
||||||
|
ms_token = cookie_dict.get('msToken', '')
|
||||||
|
|
||||||
|
# 3. 尝试从页面全局变量中寻找
|
||||||
|
if not ms_token:
|
||||||
|
ms_token = await page.evaluate("() => window._ROUTER_DATA?.msToken || ''")
|
||||||
|
|
||||||
|
if ms_token:
|
||||||
|
cookie_dict['msToken'] = ms_token
|
||||||
|
print(f"[ Info ]: Captured msToken: {ms_token[:20]}...")
|
||||||
|
else:
|
||||||
|
print("[ Warning ]: msToken not found in common locations.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ Debug ]: Error capturing msToken: {e}")
|
||||||
|
|
||||||
|
# 关闭浏览器
|
||||||
|
await context.close()
|
||||||
|
await browser.close()
|
||||||
|
|
||||||
|
# 更新配置文件
|
||||||
|
if cookie_dict:
|
||||||
|
update_config_yaml(cookie_dict)
|
||||||
|
else:
|
||||||
|
print("[ Failed ]: No cookies captured. Did you login successfully?")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
203
DouYin/Test/T2_BigV.py
Normal file
203
DouYin/Test/T2_BigV.py
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
"""
|
||||||
|
Douyin User Profile & Video Crawler (T2)
|
||||||
|
访问注释中的页面,获取页面中的内容信息(用户信息及最近作品)
|
||||||
|
|
||||||
|
URL: https://www.douyin.com/user/MS4wLjABAAAA2P7MeZl0VUsDmCzKbZeLlVGVTDRAuXmvr_zcC6XNqd-6R4n9ssCguSgA-gnBfjUO
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import yaml
|
||||||
|
import time
|
||||||
|
import io
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# 强制设置控制台输出编码为 UTF-8,解决 Windows 环境下的乱码问题
|
||||||
|
if sys.platform.startswith('win'):
|
||||||
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||||
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# 1. 环境配置与路径初始化
|
||||||
|
# =================================================================
|
||||||
|
current_file_path = os.path.abspath(__file__)
|
||||||
|
current_dir = os.path.dirname(current_file_path)
|
||||||
|
douyin_root = os.path.dirname(current_dir)
|
||||||
|
|
||||||
|
# 将 DouYin 根目录添加到 sys.path
|
||||||
|
if douyin_root not in sys.path:
|
||||||
|
sys.path.append(douyin_root)
|
||||||
|
|
||||||
|
# 尝试导入核心爬虫模块
|
||||||
|
try:
|
||||||
|
from apiproxy.douyin.douyin import Douyin
|
||||||
|
from apiproxy.douyin import douyin_headers
|
||||||
|
except ImportError as e:
|
||||||
|
print(f"[ Error ]: Failed to import core modules. Error: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# 2. 工具函数定义
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
def extract_url_from_file(file_path):
|
||||||
|
"""从文件头部的注释中提取抖音用户 URL"""
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
urls = re.findall(r'https?://(?:www\.)?douyin\.com/user/[a-zA-Z0-9\-_]+', content)
|
||||||
|
return urls[0] if urls else None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ Error ]: Failed to read script file: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def load_config():
|
||||||
|
"""从 Test 目录或项目根目录加载 config_douyin.yml 配置"""
|
||||||
|
# 优先检查当前 Test 目录
|
||||||
|
test_config_path = os.path.join(current_dir, "config_douyin.yml")
|
||||||
|
# 其次检查 DouYin 根目录
|
||||||
|
root_config_path = os.path.join(douyin_root, "config_douyin.yml")
|
||||||
|
|
||||||
|
config_path = test_config_path if os.path.exists(test_config_path) else root_config_path
|
||||||
|
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
try:
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
print(f"[ Info ]: Loading config from: {os.path.abspath(config_path)}")
|
||||||
|
return yaml.safe_load(f)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ Warning ]: Failed to parse config: {e}")
|
||||||
|
else:
|
||||||
|
print(f"[ Warning ]: config_douyin.yml not found.")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def setup_cookies(config):
|
||||||
|
"""设置 Douyin 请求所需的 Cookie"""
|
||||||
|
# 优先使用完整的全局 cookie 字符串
|
||||||
|
cookie_str = config.get("cookie", "")
|
||||||
|
cookies_dict = config.get("cookies", {})
|
||||||
|
|
||||||
|
if cookie_str:
|
||||||
|
# 如果有 raw cookie,确保 msToken 也被包含进去(如果 dict 中有的话)
|
||||||
|
if cookies_dict.get("msToken") and "msToken=" not in cookie_str:
|
||||||
|
cookie_str = f"msToken={cookies_dict['msToken']}; " + cookie_str
|
||||||
|
douyin_headers["Cookie"] = cookie_str
|
||||||
|
print(f"[ Info ]: Using raw cookie string (Length: {len(cookie_str)})")
|
||||||
|
elif cookies_dict:
|
||||||
|
cookie_str = "; ".join(f"{k}={v}" for k, v in cookies_dict.items())
|
||||||
|
douyin_headers["Cookie"] = cookie_str
|
||||||
|
print(f"[ Info ]: Using combined cookies from dict (Count: {len(cookies_dict)})")
|
||||||
|
|
||||||
|
if not douyin_headers.get("Cookie"):
|
||||||
|
print("[ Warning ]: No valid Cookie detected. Most API calls will fail.")
|
||||||
|
print(" Please run T1_GetCookie.py first.")
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# 3. 核心爬取逻辑
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
def crawl_user_profile(url):
|
||||||
|
"""获取用户信息及其最近的作品列表"""
|
||||||
|
dy = Douyin()
|
||||||
|
# 增加接口重试的超时时间
|
||||||
|
dy.timeout = 30
|
||||||
|
|
||||||
|
print(f"[ Start ]: Target URL: {url}")
|
||||||
|
|
||||||
|
# 步骤 1: 解析 URL 获取 sec_uid
|
||||||
|
print("[ Step 1/2 ]: Fetching blogger profile...")
|
||||||
|
try:
|
||||||
|
# 使用 getKey 获取 sec_uid
|
||||||
|
key_type, sec_uid = dy.getKey(url)
|
||||||
|
if key_type != "user" or not sec_uid:
|
||||||
|
print(f"[ Failed ]: Invalid URL or failed to parse sec_uid. Type: {key_type}")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f" (sec_uid: {sec_uid[:15]}...)")
|
||||||
|
|
||||||
|
# 获取详细信息
|
||||||
|
# 现在核心类 Douyin 已更新,会自动从 Cookie 中提取并拼接 msToken
|
||||||
|
print(f"[ Step 1/2 ]: Fetching blogger profile...")
|
||||||
|
user_detail = dy.getUserDetailInfo(sec_uid)
|
||||||
|
|
||||||
|
if not user_detail or user_detail.get("status_code") != 0:
|
||||||
|
print(f"[ Failed ]: Failed to fetch profile. Status: {user_detail.get('status_code') if user_detail else 'None'}")
|
||||||
|
if user_detail:
|
||||||
|
print(f" Msg: {user_detail.get('status_msg', 'Unknown error')}")
|
||||||
|
print(" Hint: Please check if Cookie is expired or network is restricted.")
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ Error ]: An unexpected error occurred: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
user_data = user_detail.get("user", {})
|
||||||
|
nickname = user_data.get('nickname', 'Unknown')
|
||||||
|
|
||||||
|
# 打印博主信息
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print(f"Blogger: {nickname}")
|
||||||
|
print("-" * 60)
|
||||||
|
print(f"ID: {user_data.get('unique_id') or user_data.get('short_id', 'Unknown')}")
|
||||||
|
print(f"Bio: {user_data.get('signature', 'N/A')}")
|
||||||
|
print(f"Followers:{user_data.get('m_follower_count') or user_data.get('follower_count', 0)}")
|
||||||
|
print(f"Likes: {user_data.get('total_favorited', 0)}")
|
||||||
|
print(f"Following:{user_data.get('following_count', 0)}")
|
||||||
|
print("="*60 + "\n")
|
||||||
|
|
||||||
|
# 步骤 3: 获取最近的作品列表
|
||||||
|
print(f"[ Step 2/2 ]: Fetching recent works...")
|
||||||
|
aweme_list = dy.getUserInfo(sec_uid, count=10)
|
||||||
|
|
||||||
|
result_data = {
|
||||||
|
"user_info": user_data,
|
||||||
|
"recent_videos": aweme_list or [],
|
||||||
|
"crawl_time": datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
}
|
||||||
|
|
||||||
|
if aweme_list:
|
||||||
|
print(f"Successfully fetched {len(aweme_list)} videos:\n")
|
||||||
|
for i, aweme in enumerate(aweme_list, 1):
|
||||||
|
ctime = aweme.get('create_time')
|
||||||
|
if isinstance(ctime, (int, float)):
|
||||||
|
ctime_str = datetime.fromtimestamp(ctime).strftime('%Y-%m-%d %H:%M')
|
||||||
|
else:
|
||||||
|
ctime_str = str(ctime)
|
||||||
|
|
||||||
|
desc = aweme.get('desc', 'No Title')
|
||||||
|
desc = (desc[:47] + "...") if len(desc) > 50 else desc
|
||||||
|
|
||||||
|
stats = aweme.get('statistics', {})
|
||||||
|
print(f"{i:02d}. [{ctime_str}] {desc}")
|
||||||
|
print(f" ❤️ {stats.get('digg_count', 0):<8} 💬 {stats.get('comment_count', 0):<8} ⭐ {stats.get('collect_count', 0)}")
|
||||||
|
print(f" 🔗 https://www.douyin.com/video/{aweme.get('aweme_id')}\n")
|
||||||
|
else:
|
||||||
|
print("[ Info ]: No public videos found. Account might be private or API limited.")
|
||||||
|
|
||||||
|
# 步骤 4: 保存数据
|
||||||
|
output_file = os.path.join(current_dir, f"user_data_{sec_uid[:8]}.json")
|
||||||
|
try:
|
||||||
|
with open(output_file, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(result_data, f, ensure_ascii=False, indent=4)
|
||||||
|
print(f"[ Success ]: Data saved to: {os.path.basename(output_file)}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ Warning ]: Failed to save data: {e}")
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# 4. 主入口
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 提取 URL
|
||||||
|
target_url = extract_url_from_file(current_file_path)
|
||||||
|
|
||||||
|
if target_url:
|
||||||
|
# 配置环境
|
||||||
|
config = load_config()
|
||||||
|
setup_cookies(config)
|
||||||
|
|
||||||
|
# 执行爬取
|
||||||
|
crawl_user_profile(target_url)
|
||||||
|
else:
|
||||||
|
print("[ Error ]: No valid Douyin URL found in file comments.")
|
||||||
16
DouYin/Test/config_douyin.yml
Normal file
16
DouYin/Test/config_douyin.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
cookie: __ac_nonce=069a13bcc00cacbb09800; __ac_signature=_02B4Z6wo00f01EiD5NQAAIDB-WNazgGqWRxIo8BAAHuJ33;
|
||||||
|
ttwid=1%7CxZrCypV7044-lvm6_oK7nlsTEtEn-H_yJXdZRYjRQg0%7C1772174285%7C38825b7026cf7c8724e4070f81748a477168eb58988b8e09b67142bc6441a676;
|
||||||
|
enter_pc_once=1; UIFID_TEMP=630dc87f7218843564944b22829d362b9fabe9a9e3376a5c74988083749b66dffd3737bb90e0acf82e6707c6ee24f7522fbefdc12d5a2fed2eae91b09db43c67688ba5ad520d1d6f6b294f7ef3c3442efbc0a4ff34b6c60edb3ff06d5e120b4a2376474bd59208bc08755ec54934cb80;
|
||||||
|
x-web-secsdk-uid=9d7866f1-5873-4d35-8b7d-7d0117b45b3f; s_v_web_id=verify_mm4ital2_ERFXSBBL_FxRH_4tEN_A3jj_V3VIL6WSh4u6;
|
||||||
|
=douyin.com; device_web_cpu_core=20; device_web_memory_size=8; architecture=amd64;
|
||||||
|
hevc_supported=true; IsDouyinActive=true; home_can_add_dy_2_desktop=%220%22; dy_swidth=1280;
|
||||||
|
dy_sheight=800; stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1280%2C%5C%22screen_height%5C%22%3A800%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A20%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A0%7D%22
|
||||||
|
cookies:
|
||||||
|
msToken: my7nuKyrpTVEWOX-n62wR8I5EcvoMKBmvsBMnODLOtG3sn6AsR7q_jEM5jmEenyuwmHpsL25b84VhGcR4nUgv0PepA2zrSUOGHCmZVzpauYpRgbR9svMKjt2-AgNRz
|
||||||
|
ttwid: 1%7CxZrCypV7044-lvm6_oK7nlsTEtEn-H_yJXdZRYjRQg0%7C1772174285%7C38825b7026cf7c8724e4070f81748a477168eb58988b8e09b67142bc6441a676
|
||||||
|
s_v_web_id: verify_mm4ital2_ERFXSBBL_FxRH_4tEN_A3jj_V3VIL6WSh4u6
|
||||||
|
odin_tt: 6f33402fa0952cdea7eaa5226bfe0a2a45ee10bbb138835da6a5383e9eef092f7ad0a1790c0271a090f72c8112875fef3665d50460b79ec302ba56c2b91f52b3bcab4b209cce3f4b7378f995b01a5cce
|
||||||
|
path: ./Downloaded/
|
||||||
|
thread: 5
|
||||||
|
number:
|
||||||
|
post: 10
|
||||||
1935
DouYin/Test/user_data_MS4wLjAB.json
Normal file
1935
DouYin/Test/user_data_MS4wLjAB.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,4 +2,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'
|
ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36'
|
||||||
@@ -9,10 +9,10 @@ douyin_headers = {
|
|||||||
'referer': 'https://www.douyin.com/',
|
'referer': 'https://www.douyin.com/',
|
||||||
'accept': 'application/json, text/plain, */*',
|
'accept': 'application/json, text/plain, */*',
|
||||||
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
||||||
'accept-encoding': 'gzip, deflate, br',
|
'accept-encoding': 'gzip, deflate',
|
||||||
'sec-ch-ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
'sec-ch-ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
||||||
'sec-ch-ua-mobile': '?0',
|
'sec-ch-ua-mobile': '?0',
|
||||||
'sec-ch-ua-platform': '"macOS"',
|
'sec-ch-ua-platform': '"Windows"',
|
||||||
'sec-fetch-dest': 'empty',
|
'sec-fetch-dest': 'empty',
|
||||||
'sec-fetch-mode': 'cors',
|
'sec-fetch-mode': 'cors',
|
||||||
'sec-fetch-site': 'same-origin'
|
'sec-fetch-site': 'same-origin'
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ class Douyin(object):
|
|||||||
# 单作品接口返回 'aweme_detail'
|
# 单作品接口返回 'aweme_detail'
|
||||||
# 主页作品接口返回 'aweme_list'->['aweme_detail']
|
# 主页作品接口返回 'aweme_list'->['aweme_detail']
|
||||||
# 更新API参数以适应最新接口要求
|
# 更新API参数以适应最新接口要求
|
||||||
detail_params = f'aweme_id={aweme_id}&device_platform=webapp&aid=6383&channel=channel_pc_web&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=MacIntel&browser_name=Chrome&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Mac&os_version=10.15.7&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&update_version_code=170400'
|
detail_params = f'aweme_id={aweme_id}&device_platform=webapp&aid=6383&channel=channel_pc_web&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Windows&os_version=10&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&update_version_code=170400'
|
||||||
jx_url = self.urls.POST_DETAIL + utils.getXbogus(detail_params)
|
jx_url = self.urls.POST_DETAIL + utils.getXbogus(detail_params)
|
||||||
|
|
||||||
response = requests.get(url=jx_url, headers=douyin_headers, timeout=10)
|
response = requests.get(url=jx_url, headers=douyin_headers, timeout=10)
|
||||||
@@ -280,7 +280,15 @@ class Douyin(object):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
# 构建请求URL - 添加更多必需参数
|
# 构建请求URL - 添加更多必需参数
|
||||||
base_params = f'sec_user_id={sec_uid}&count={count}&max_cursor={max_cursor}&device_platform=webapp&aid=6383&channel=channel_pc_web&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=MacIntel&browser_name=Chrome&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Mac&os_version=10.15.7&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50'
|
base_params = f'sec_user_id={sec_uid}&count={count}&max_cursor={max_cursor}&device_platform=webapp&aid=6383&channel=channel_pc_web&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Windows&os_version=10&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50'
|
||||||
|
|
||||||
|
# 尝试从 cookie 中提取 msToken
|
||||||
|
cookie_str = douyin_headers.get('Cookie', '')
|
||||||
|
if 'msToken=' in cookie_str:
|
||||||
|
import re
|
||||||
|
ms_token_match = re.search(r'msToken=([^;]+)', cookie_str)
|
||||||
|
if ms_token_match:
|
||||||
|
base_params += f"&msToken={ms_token_match.group(1)}"
|
||||||
|
|
||||||
if mode == "post":
|
if mode == "post":
|
||||||
url = self.urls.USER_POST + utils.getXbogus(base_params)
|
url = self.urls.USER_POST + utils.getXbogus(base_params)
|
||||||
@@ -415,7 +423,7 @@ class Douyin(object):
|
|||||||
while True:
|
while True:
|
||||||
# 接口不稳定, 有时服务器不返回数据, 需要重新获取
|
# 接口不稳定, 有时服务器不返回数据, 需要重新获取
|
||||||
try:
|
try:
|
||||||
live_params = f'aid=6383&device_platform=web&web_rid={web_rid}&channel=channel_pc_web&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=MacIntel&browser_name=Chrome&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Mac&os_version=10.15.7&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50'
|
live_params = f'aid=6383&device_platform=web&web_rid={web_rid}&channel=channel_pc_web&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Windows&os_version=10&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50'
|
||||||
live_api = self.urls.LIVE + utils.getXbogus(live_params)
|
live_api = self.urls.LIVE + utils.getXbogus(live_params)
|
||||||
|
|
||||||
response = requests.get(live_api, headers=douyin_headers)
|
response = requests.get(live_api, headers=douyin_headers)
|
||||||
@@ -870,19 +878,39 @@ class Douyin(object):
|
|||||||
while True:
|
while True:
|
||||||
# 接口不稳定, 有时服务器不返回数据, 需要重新获取
|
# 接口不稳定, 有时服务器不返回数据, 需要重新获取
|
||||||
try:
|
try:
|
||||||
user_detail_params = f'sec_user_id={sec_uid}&device_platform=webapp&aid=6383&channel=channel_pc_web&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=MacIntel&browser_name=Chrome&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Mac&os_version=10.15.7&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50'
|
user_detail_params = f'sec_user_id={sec_uid}&device_platform=webapp&aid=6383&channel=channel_pc_web&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1920&screen_height=1080&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=122.0.0.0&browser_online=true&engine_name=Blink&engine_version=122.0.0.0&os_name=Windows&os_version=10&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50'
|
||||||
|
|
||||||
|
# 尝试从 cookie 中提取 msToken
|
||||||
|
cookie_str = douyin_headers.get('Cookie', '')
|
||||||
|
if 'msToken=' in cookie_str:
|
||||||
|
import re
|
||||||
|
ms_token_match = re.search(r'msToken=([^;]+)', cookie_str)
|
||||||
|
if ms_token_match:
|
||||||
|
user_detail_params += f"&msToken={ms_token_match.group(1)}"
|
||||||
|
|
||||||
url = self.urls.USER_DETAIL + utils.getXbogus(user_detail_params)
|
url = self.urls.USER_DETAIL + utils.getXbogus(user_detail_params)
|
||||||
|
|
||||||
res = requests.get(url=url, headers=douyin_headers)
|
res = requests.get(url=url, headers=douyin_headers, timeout=10)
|
||||||
datadict = json.loads(res.text)
|
|
||||||
|
if not res.text.strip():
|
||||||
if datadict is not None and datadict["status_code"] == 0:
|
logger.warning(f"getUserDetailInfo: Empty response (Status: {res.status_code})")
|
||||||
return datadict
|
else:
|
||||||
|
try:
|
||||||
|
datadict = json.loads(res.text)
|
||||||
|
if datadict is not None and datadict.get("status_code") == 0:
|
||||||
|
return datadict
|
||||||
|
else:
|
||||||
|
logger.warning(f"getUserDetailInfo: API error (Status: {datadict.get('status_code')}, Msg: {datadict.get('status_msg')})")
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
logger.error(f"getUserDetailInfo: JSON decode error (Status: {res.status_code})")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
end = time.time() # 结束时间
|
logger.error(f"getUserDetailInfo: Exception: {e}")
|
||||||
if end - start > self.timeout:
|
|
||||||
print("[ 提示 ]:重复请求该接口" + str(self.timeout) + "s, 仍然未获取到数据")
|
end = time.time() # 结束时间
|
||||||
return datadict
|
if end - start > self.timeout:
|
||||||
|
print("[ 提示 ]:重复请求该接口" + str(self.timeout) + "s, 仍然未获取到数据")
|
||||||
|
return datadict
|
||||||
|
time.sleep(1) # 增加小延迟避免请求过快
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
BIN
Tools/Excel/20260210_115509/新电途_20260210_115509.xlsx
Normal file
BIN
Tools/Excel/20260210_115509/新电途_20260210_115509.xlsx
Normal file
Binary file not shown.
BIN
Tools/Excel/20260210_115509/特来电_20260210_115509.xlsx
Normal file
BIN
Tools/Excel/20260210_115509/特来电_20260210_115509.xlsx
Normal file
Binary file not shown.
Reference in New Issue
Block a user