关于企查查处理数据的问题都可以私信我哦。 还可以整理分支机构、主要人员、投资信息、附属子公司等。
1、批量提取数据
由于需要区分工商登记数据还是最新公示数据,所以选择将这两部分数据分开存放,当然也可以放在一起。(本文认为最新公示的企业属于上市企业,但是也存在一些未上市却即将上市的企业,工商登记属于未上市企业)。
源数据截图示例:
代码:
import os
import re
import pandas as pd
folder_path = r"C:\股东信息解压"
latest_announcement_data = []
business_registration_data = []
for filename in os.listdir(folder_path):
if filename.endswith(".csv"):
file_path = os.path.join(folder_path, filename)
df = pd.read_csv(file_path, sep='\t', engine='python', skip_blank_lines=True)
df=df.astype(str)
df = df.applymap(lambda x: x.replace('=', '') if isinstance(x, str) else x)
df = df.applymap(lambda x: x.replace(',', '') if isinstance(x, str) else x)
df = df.applymap(lambda x: x.replace('""', '"') if isinstance(x, str) else x)
df = df.applymap(lambda x: x.strip() if isinstance(x, str) else x)
df = df[df['查企业 上企查查 , 联系电话:400-928-2212,'] != '" "']
current_state = None
current_company = None
for index, row in df.iterrows():
line = row[df.columns[0]]
company_match = re.match(r'"(.*)(公司|厂|大学|研究)(.*)', line)
if company_match:
current_company = company_match.group(1)+company_match.group(2)
if line.startswith('"股东信息-最新公示'):
current_state = "latest_announcement"
continue
elif line.startswith('"股东信息-工商登记'):
current_state = "business_registration"
continue
if current_state == "latest_announcement":
if line.startswith('"股东信息-工商登记'):
current_state = None
continue
latest_announcement_data.append([current_company] + row.tolist())
elif current_state == "business_registration":
if line.startswith('"(.*)(公司|厂|大学|研究)(.*)') or pd.isnull(line):
current_state = None
continue
business_registration_data.append([current_company] + row.tolist())
latest_announcement_df = pd.DataFrame(latest_announcement_data, columns=["企业名称"] + df.columns.tolist())
business_registration_df = pd.DataFrame(business_registration_data, columns=["企业名称"] + df.columns.tolist())
latest_announcement_df.to_csv("ods钛材上市公司股东表.csv", index=False, encoding='utf-8')
business_registration_df.to_csv("ods钛材未上市公司股东表.csv", index=False, encoding='utf-8')
由于企查查上的企业数据时间线较长,关于最新公示部分的数据列有两种形式,本文选择提取年代较新的部分列,列开头为:序号 股东名称 持股比例 XXX。另一个数据信息较久远的列开头为:序号 股东名称 股份类型XXX,弃用。
import pandas as pd
df1 = pd.read_csv("ods钛材上市公司股东表.csv")
current_state = None
filtered_data = []
preserve_data = False
for index, row in df1.iterrows():
line = row[df1.columns[1]]
if line.startswith('"序号"股东名称"持股比例"'):
current_state = "持股比例"
preserve_data = True
filtered_data.append(row)
elif line.startswith('"序号"股东名称"股份类型"'):
current_state = "股份类型"
preserve_data = False
elif not line:
preserve_data = False
if preserve_data:
filtered_data.append(row)
df_filtered = pd.DataFrame(filtered_data, columns=df1.columns)
df_filtered.to_csv("ods钛材上市公司股东表1.csv", index=False)
2、数据处理部分
这部分主要是对列进行拆除,并统一数据格式。提醒:企查查导出的数据列名随时都存在变化的可能,可能会新增列也可能改变列名,需要对导出的数据进行一个检查。
import pandas as pd
# 读取两个CSV文件为DataFrame
df1 = pd.read_csv("ods储能上市公司股东表1.csv")
df2 = pd.read_csv("ods储能未上市公司股东表.csv")
df1 = df1.applymap(lambda x: x.replace('"', '##') if isinstance(x, str) else x)
df2 = df2.applymap(lambda x: x.replace('"', '##') if isinstance(x, str) else x)
for i in range(1, len(df1)):
if df1.loc[i, '企业名称'][0].isdigit():
df1.loc[i, '企业名称'] = df1.loc[i - 1, '企业名称']
for i in range(1, len(df2)):
if df2.loc[i, '企业名称'][0].isdigit():
df2.loc[i, '企业名称'] = df2.loc[i - 1, '企业名称']
pattern = r'^##\d+'
df1 = df1[df1['查企业 上企查查 , 联系电话:400-928-2212,'].str.match(pattern)]
df2 = df2[df2['查企业 上企查查 , 联系电话:400-928-2212,'].str.match(pattern)]
split_columns1 = df1['查企业 上企查查 , 联系电话:400-928-2212,'].str.split('##', expand=True)
df1 = pd.concat([df1, split_columns1], axis=1)
df1.rename(columns={0: '空值', 1: '序号', 2: '股东名称', 3: '持股比例', 4: '认缴出资额', 5: '认缴出资日期', 6: '实缴出资额', 7: '实缴出资日期', 8: '最终受益股份',9:'关联产品/机构'}, inplace=True)
df1.drop('查企业 上企查查 , 联系电话:400-928-2212,', axis=1, inplace=True)
df1['持股比例'] = df1['持股比例'].str.replace(r'^(0%)$', '-', regex=True)
df1['最终受益股份'] = df1['最终受益股份'].str.replace(r'^0%$', '-', regex=True)
df1 = df1[['企业名称', '股东名称', '持股比例', '最终受益股份', '关联产品/机构']]
df1 = df1.dropna(subset=['股东名称'])
df1.drop_duplicates()
df1.reset_index(drop=True, inplace=True)
split_columns = df2['查企业 上企查查 , 联系电话:400-928-2212,'].str.split('##',expand=True)
df2 = pd.concat([df2, split_columns], axis=1)
df2.rename(columns={0: '空值', 1: '序号', 2: '股东名称', 3: '持股比例', 4: '认缴出资额', 5: '认缴出资日期', 6: '实缴出资额', 7: '实缴出资日期', 8: '最终受益股份',9:'首次持股日期',10:'关联产品/机构'}, inplace=True)
df2.drop('查企业 上企查查 , 联系电话:400-928-2212,', axis=1, inplace=True)
df2['认缴出资日期'] = df2['认缴出资日期'].str.replace('最新:', '')
df2['实缴出资日期'] = df2['实缴出资日期'].str.replace('最新:', '')
df2['持股比例'] = df2['持股比例'].str.replace(r'^(0%)$', '-', regex=True)
df2['最终受益股份'] = df2['最终受益股份'].str.replace(r'^(0%)$', '-', regex=True)
df2 = df2[['企业名称', '股东名称', '持股比例', '认缴出资额', '认缴出资日期', '实缴出资额', '实缴出资日期', '最终受益股份', '首次持股日期', '关联产品/机构']]
df2 = df2[(df2['股东名称'].notna()) & ~df2['股东名称'].str.match(r'\d{4}年\d{1,2}月\d{1,2}日')]
df2.drop_duplicates()
df2.reset_index(drop=True, inplace=True)
df1.to_csv("ods储能上市公司股东表2.csv", index=False,encoding='utf-8')
df2.to_csv("ods储能未上市公司股东表2.csv", index=False,encoding='utf-8')
3、上传mysql数据库
功能:删除数据库中的原有数据,再进行导入。并加上导入进度条,打印上传时间。提醒:我的数据库中有一个自增列,列名为:id。但是若多次导入数据不设置自增列,导入的数据可能id不为1开始。这里选择脚本控制。
import pandas as pd
from sqlalchemy import create_engine
import time
from tqdm import tqdm
csv_file_path = r"D:\ods未上市公司股东表.csv"
df = pd.read_csv(csv_file_path)
column_mapping = {
'企业名称': 'enterprise_name',
'股东名称': 'shareholder',
'持股比例': 'shareholding_ratio',
'认缴出资额':'subscribed_capital_contribution',
'认缴出资日期': 'subscribed_date',
'实缴出资额':'paid_in_capital_contribution',
'实缴出资日期': 'paid_in_date',
'最终受益股份':'ultimate_beneficiary_shares',
'首次持股日期': 'initial_shareholding_in_date',
'关联产品/机构': 'Related_products_or_institutions'
}
df_mapped = df.rename(columns=column_mapping)
engine = create_engine(
"mysql+mysqlconnector://username:password@host/数据库名"
)
start_time = time.time()
try:
table_name = "数据库中的表名"
total_rows = len(df_mapped)
with engine.connect() as connection:
# 设置自增起始值 increment
set_auto_increment_query = f"ALTER TABLE {table_name} AUTO_INCREMENT = 1"
connection.execute(set_auto_increment_query)
# 删除旧数据
delete_query = f"DELETE FROM {table_name}"
connection.execute(delete_query)
with tqdm(total=total_rows, desc="Uploading data") as pbar:
df_mapped.to_sql(table_name, con=engine, if_exists="append", index=False, chunksize=10000)
pbar.update(len(df_mapped))
print("Data uploaded successfully.")
except Exception as e:
print("Error uploading data:", str(e))
finally:
engine.dispose()
end_time = time.time()
elapsed_time = end_time - start_time
print(f"Total time elapsed: {elapsed_time:.2f} seconds")