Загрузка данных
import builtins
import json
import os
import sys
import logging
import traceback
import requests
import uuid
from datetime import datetime, timedelta
from calendar import monthrange
from io import StringIO
import csv
import time
from lxml.builder import E
from lxml import etree
from umdap_config import LOG_FOLDER, ENV_FOLDER, EROUTER_HOST, PRIMARY_MADAB, UMDAP_ETL_URL_LIST
APPLICATION_NAME = 'externalGTT'
LOG_FILE = os.path.join(LOG_FOLDER, "externalGTT_test.log")
CREDENTIALS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.json")
BASE_URL = 'https://www.globaltradetracker.com/api/rest'
builtins.BASE_URL = BASE_URL
builtins.XML_DATE_FMT = '%d.%m.%Y %H:%M:%S'
builtins.DELIMITER = ','
# === НАСТРОЙКИ ===
TARGET_ROWS = 100000
OUTPUT_XML = 'test.xml'
CSV_TEMP = 'test_batch.csv'
session = requests.Session()
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
})
def log(msg=''):
str_with_time = f'{datetime.now().strftime("%Y/%m/%d %H:%M:%S")} {msg}'
print(str_with_time)
with open(LOG_FILE, "a", encoding="utf-8") as file:
file.write(f'{str_with_time}\n')
builtins.log = log
def generate_id():
return uuid.uuid4().hex
def get_token():
try:
with open(CREDENTIALS_FILE, 'r') as f:
credentials = json.load(f)
link = f"{BASE_URL}/gettoken?userid={credentials['user_id']}&password={credentials['password']}"
response = session.get(link, timeout=30)
if response.status_code == 200:
token = response.content.decode().strip()
if token:
log("Token received")
return token
return None
except Exception as e:
log(f"ERROR get_token: {e}")
return None
def get_subscription_countries(token):
try:
response = session.get(f"{BASE_URL}/countries?token={token}", timeout=30)
if response.status_code == 200:
data = response.json()
countries = []
if isinstance(data, list):
for item in data:
if isinstance(item, dict):
country_data = item.get('country', item)
if country_data.get('reportingcountry') == 'true' and country_data.get('defaultReporter') == True:
code = country_data.get('reportercode', '')
if code:
countries.append(code)
countries = list(dict.fromkeys(countries))
log(f"Available reporters: {len(countries)}")
return countries
return []
except Exception as e:
log(f"ERROR get_countries: {e}")
return []
def parse_period(year, month):
try:
year = int(year)
month = int(month)
last_day = monthrange(year, month)[1]
return datetime(year, month, last_day).strftime('%Y-%m-%d')
except:
return '2000-01-01'
def parse_record_to_dict(record, reporter_code="", trade_flow=""):
try:
if not isinstance(record, dict):
return None
year = record.get('year', 2000)
month = record.get('month', 1)
return {
'ID': generate_id(),
'Reporter_Code': record.get('reporterCode', reporter_code),
'Trade_Flow': record.get('tradeFlow', trade_flow),
'Is_Mirror_Data': record.get('isMirror', ''),
'Period': parse_period(year, month),
'Reporter_Name': record.get('reporterName', ''),
'Reporter_Description': record.get('reporterDescription', '')[:120],
'Reporter_Source': record.get('reporterSource', '')[:120],
'Incoterm': record.get('incoterm', '')[:60],
'Partner_Code': record.get('partnerCode', '')[:60],
'Partner_Name': record.get('partnerName', '')[:120],
'Commodity_HS_Code': record.get('hsCode', '')[:60],
'Commodity_Description': record.get('commodityDescriptionOriginal', '')[:250],
'HS6_Code': record.get('hs6Code', '')[:60],
'HS6_Code_Description': record.get('hs6DescriptionOriginal', '')[:250],
'Subdivision': record.get('subdivision', '')[:120],
'Port': record.get('port', '')[:120],
'Transport': record.get('transport', '')[:120],
'Foreign_Port': record.get('foreignPort', '')[:120],
'US_State': record.get('usState', '')[:120],
'Customs_Regime': record.get('customsRegime', '')[:120],
'Suppression': record.get('suppression', '')[:3900],
'Monetary_Value': record.get('value', 0),
'Currency': record.get('currency', 'USD')[:60],
'Secondary_Monetary_Value': record.get('value2', 0),
'Secondary_Currency': record.get('currency2', '')[:60],
'Primary_Quantity': record.get('quantity1', 0),
'Primary_Quantity_Unit': record.get('unit1', '')[:60],
'Secondary_Quantity': record.get('quantity2', 0),
'Secondary_Quantity_Unit': record.get('unit2', '')[:60],
'Primary_Quantity_Price': record.get('price1', 0),
'Primary_Quantity_Price_Unit': record.get('priceunit1', '')[:60],
'Secondary_Quantity_Price': record.get('price2', 0),
'Secondary_Quantity_Price_Unit': record.get('priceunit2', '')[:60],
}
except Exception as e:
log(f"ERROR parse: {e}")
return None
def parse_data_to_rows(data, reporter_code="", trade_flow=""):
rows = []
if isinstance(data, list):
records = data
elif isinstance(data, dict):
if 'reportData' in data:
records = data['reportData']
elif 'data' in data:
records = data['data']
else:
return rows
else:
return rows
for record in records:
if isinstance(record, dict):
parsed = parse_record_to_dict(record, reporter_code, trade_flow)
if parsed:
rows.append(parsed)
return rows
def save_csv(rows, filepath):
if not rows:
return
with open(filepath, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=rows[0].keys())
writer.writeheader()
writer.writerows(rows)
log(f"CSV saved: {filepath} ({len(rows)} rows)")
def generate_xml(rows):
"""Генерация XML как etl_common.py"""
xml_rows = []
for row in rows:
row_elems = []
for key, value in row.items():
tag = str(key).replace(' ', '_')
if value is None:
value = ''
row_elems.append(E(tag, str(value)))
xml_rows.append(E.row(*row_elems))
root = E.madabContent(
E.type('GTT'),
*xml_rows
)
return etree.tostring(root, encoding='utf-8', pretty_print=True)
def get_historical_data(token, countries, target_rows=100000):
log("=" * 60)
log(f"Starting test parsing: {target_rows} rows")
log("=" * 60)
all_rows = []
total_requests = 0
hs_filter = '31,25'
fields = 'reporterCode,tradeFlow,isMirror,year,month,reporterName,reporterDescription,reporterSource,incoterm,partnerCode,partnerName,hsCode,commodityDescriptionOriginal,hs6Code,hs6DescriptionOriginal,value,currency,value2,currency2,quantity1,unit1,quantity2,unit2,price1,priceunit1,price2,priceunit2,port,transport,subdivision'
trade_details = 'PORT,SUBDIVISION,TRANSPORT,CUSTOMS_REGIME,FOREIGN_PORT,FOREIGN_SUBDIVISION'
for country in countries:
if len(all_rows) >= target_rows:
log(f"Reached target rows: {len(all_rows)}")
break
for impexp in ['E', 'I']:
if len(all_rows) >= target_rows:
break
try:
params = {
'token': token,
'hscode': hs_filter,
'reporter': country,
'impexp': impexp,
'from': '2013-01',
'to': '2026-08',
'layout': 'brief',
'hslevel': '6',
'field': fields,
'tradedetails': trade_details,
'currency2': 'EUR',
'decimalscale': '2',
'format': 'json'
}
total_requests += 1
start = time.time()
response = session.get(f"{BASE_URL}/getreport", params=params, timeout=600)
end = time.time()
log(f"[{total_requests}] {country} {impexp} Status={response.status_code} Time={end-start:.1f}s Total rows={len(all_rows)}")
if response.status_code == 200:
data = response.json()
new_rows = parse_data_to_rows(data, country, impexp)
remaining = target_rows - len(all_rows)
if len(new_rows) > remaining:
new_rows = new_rows[:remaining]
all_rows.extend(new_rows)
log(f" Added {len(new_rows)} rows, total: {len(all_rows)}")
except Exception as e:
log(f"✗ {str(e)}")
continue
return all_rows
def main():
log('--------------------- TEST SCRIPT started ------------------------------')
try:
token = get_token()
if not token:
log("ERROR: Failed to get token")
sys.exit(1)
countries = get_subscription_countries(token)
if not countries:
log("ERROR: Failed to get countries")
sys.exit(1)
log(f"Parsing {TARGET_ROWS} rows...")
rows = get_historical_data(token, countries, TARGET_ROWS)
if not rows:
log("ERROR: No rows parsed")
sys.exit(1)
log(f"Parsed {len(rows)} rows")
save_csv(rows, CSV_TEMP)
log("Generating XML...")
xml_bytes = generate_xml(rows)
with open(OUTPUT_XML, 'wb') as f:
f.write(xml_bytes)
size_mb = len(xml_bytes) / 1024 / 1024
log(f"XML saved: {OUTPUT_XML}")
log(f"XML size: {size_mb:.2f} MB")
log(f"Rows in XML: {len(rows)}")
log('--------------------- TEST SCRIPT finished -----------------------------')
log(f"Try: curl -X POST 'https://e-router.eurochem.ru/procedure/WHDEV/umdap.etl.content/call?application=externalGTT' --data-binary @{OUTPUT_XML} -k -v")
except Exception as e:
log(f'Error: {traceback.format_exception(*sys.exc_info())}')
sys.exit(1)
if __name__ == "__main__":
main()