本文jupyter notebook资料下载地址百度网盘
爬虫一般步骤:
爬虫解析方法:
# 导库
import requests
from lxml import etree
# 获得响应,解析响应
r = requests.get(url,headers)
html = etree.HTML(r.text)
# 获得xpath路径,输入xpath方法获得元素内容
element = html.xpath('xpath路径')
- BeautifulSoup(css、find...)
# 导库
import requests
from bs4 import BeautifulSoup
# 获得响应,解析响应
r = requests.get(url,headers)
soup = BeautifulSoup(r.text, 'lxml')
# 分步解析获得各元素
# css选择器
# 方法:F12-->选择元素-->右键菜单:复制selector
element = soup.select("CSS选择器")
# find方法
# 方法:F12-->选择元素,观察
element = soup.find("标签",class_= "类名") #等其他选择
实例: 采用xpath获取行业名
# 导入库
import requests
from lxml import etree
# 设置请求头
headers = {
'user-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
'Host':'s.askci.com'
}
# 设置请求url
url = 'https://s.askci.com/data/economy/00001/'
# 获得响应
r = requests.get(url, headers = headers)
# 编码转换,避免乱码
r.encoding = r.apparent_encoding
# 采用etree.HTML解析
html = etree.HTML(r.text)
# 采用xpath获得行业名
html.xpath('/html/body/div[4]/div[2]/div[1]/a[3]/text()')
一般格式
pandas.read_html(io,
match='.+',
flavor=None,
header=None,
index_col=None,
skiprows=None,
attrs=None,
parse_dates=False,
thousands=',',
encoding=None,
decimal='.',
converters=None,
na_values=None,
keep_default_na=True,
displayed_only=True)
输入参数:
io:str、路径对象或 file-like 对象
字符串、路径对象(实现 os.PathLike[str] )或 file-like 对象实现字符串 read() 函数。该字符串可以表示 URL 或 HTML 本身。请注意,lxml 只接受 http、ftp 和文件 url 协议。如果您有一个以 ‘https’ 开头的 URL,您可以尝试删除 ‘s’ 。
match:str 或编译的正则表达式,可选
将返回包含与此正则表达式或字符串匹配的文本的表集。除非 HTML 非常简单,否则您可能需要在此处传递一个非空字符串。默认为“.+”(匹配任何非空字符串)。默认值将返回页面中包含的所有表。此值被转换为正则表达式,以便 Beautiful Soup 和 lxml 之间的行为一致。
flavor:str,可选
要使用的解析引擎。 ‘bs4’ 和 ‘html5lib’ 是同义词,它们都是为了向后兼容。 None 的默认值尝试使用 lxml 进行解析,如果失败,则返回 bs4 + html5lib 。
header:int 或 list-like,可选
用于制作列标题的行(或 MultiIndex 的行列表)。
index_col:int 或 list-like,可选
用于创建索引的列(或列列表)。
skiprows:int, list-like 或切片,可选
解析列整数后要跳过的行数。基于 0。如果给定整数序列或切片,将跳过由该序列索引的行。请注意,单个元素序列表示“跳过第 n 行”,而整数表示“跳过 n 行”。
attrs:字典,可选
这是一个属性字典,您可以通过它来识别 HTML 中的表格。在传递给 lxml 或 Beautiful Soup 之前,不会检查它们的有效性。但是,这些属性必须是有效的 HTML 表格属性才能正常工作。例如,
attrs = {‘id’:‘table’}
是一个有效的属性字典,因为 ‘id’ HTML 标记属性是本文档中任何 HTML 标记的有效 HTML 属性。
attrs = {‘asdf’:‘table’}
不是有效的属性字典,因为 ‘asdf’ 不是有效的 HTML 属性,即使它是有效的 XML 属性。可以在此处找到有效的 HTML 4.01 表格属性。可以在此处找到 HTML 5 规范的工作草案。它包含有关现代 Web 表属性的最新信息。
parse_dates:布尔型,可选
有关详细信息,请参阅read_csv()。
thousands:str,可选
用于解析数千的分隔符。默认为 ‘,’ 。
encoding:str,可选
用于解码网页的编码。默认为 None 。None
保留先前的编码行为,这取决于底层解析器库(例如,解析器库将尝试使用文档提供的编码)。
decimal:str,默认“。”
识别为小数点的字符(例如,对欧洲数据使用“,”)。
converters:字典,默认无
用于转换某些列中的值的函数的字典。键可以是整数或列标签,值是接受一个输入参数、单元格(不是列)内容并返回转换后的内容的函数。
na_values:可迭代,默认无
自定义 NA 值。
keep_default_na:布尔值,默认为真
如果指定了 na_values 并且 keep_default_na 为 False,则默认 NaN 值将被覆盖,否则将附加到它们。
displayed_only:布尔值,默认为真
是否应该解析带有“display:none” 的元素。
返回值:
注意:
在使用此函数之前,您应该阅读有关 HTML 解析库的问题。
调用此函数后,期望进行一些清理。例如,如果在传递 header=0 参数时列名转换为 NaN,则可能需要手动分配列名。我们尝试尽可能少地假设表格的结构,并将表格中包含的 HTML 的特性推送给用户。
这个函数搜索 **< table >**元素并且仅用于 < tr > 和 < th > 行和 < td > 每个内的元素 < tr > 或者表中的元素。 < td > 代表“table data”。该函数试图正确处理colspan和rowspan属性。如果函数有 < thead > 参数,它用于构造标题,否则该函数会尝试在正文中查找标题(通过仅放置行 **< th >**元素到标题中)。
与read_csv() 类似,在应用skiprows 之后应用header 参数。
此函数将始终返回 DataFrame 列表,否则将失败,例如,它不会返回空列表。
DataFrame.to_excel(excel_writer,
sheet_name='Sheet1',
na_rep='',
float_format=None,
columns=None,
header=True,
index=True,
index_label=None,
startrow=0,
startcol=0,
engine=None,
merge_cells=True,
encoding=None,
inf_rep='inf',
verbose=True,
freeze_panes=None)
大家尝试df.to_excel()会发现,多次调用此函数存同一个excel文件的不同sheet时,会把旧文件覆盖掉,无法保存为多个sheet。
其解决办法如下:
if not os.path.exists(excelFileName):
html_tables[0].to_excel(excelFileName,sheet_name=sheet_names[0], index=True)
else:
with pd.ExcelWriter(excelFileName, engine='openpyxl', mode='a') as writer:
html_tables[0].to_excel(writer,sheet_name=sheet_names[0], index=True)
通过查看ExcelWriter的py文件,可以看到该类的定义框架如下所示:
class ExcelWriter(builtins.object):
def ExcelWriter(
path: 'FilePathOrBuffer | ExcelWriter',
engine=None,
date_format=None,
datetime_format=None,
mode: 'str' = 'w',
storage_options: 'StorageOptions' = None,
if_sheet_exists: 'str | None' = None,
engine_kwargs: 'dict | None' = None,
**kwargs):
其中,最基本的应用是:
ExcelWriter(path,
engine=None,
date_format=None,
datetime_format=None,
mode=‘w’)
# 查看DataFrame的基本信息
df.info()
# 查看DataFrame的统计信息
df.describe()
# 查看DataFrame的前n行
df.head(n)
# 查看DataFrame的后n行
df.tail(n)
# 返回DataFrame的列索引
df.columns
# 返回DataFrame的行索引
df.index
获取列
df[columnName]
df.columnName
获取行
df.loc[索引名]
df.iloc[整数相对索引值]
获取标量
df.loc[行索引名称,列索引名称]
方式
df.loc[行索引名称][列索引名称]
方式
df.iloc[行索引值,列索引值]
方式
df.iloc[行索引值][列索引值]
方式
df.at[行索引名称,列索引名称]
方式
df.iat[行索引值,列索引值]
方式
切片
行切片
df[起始行索引名称:终止行索引名称:步长]
df.loc[起始行索引名称:终止行索引名称:步长]
df.iloc[起始行索引值:终止行索引值:步长]
列切片
df[[列索引名1,列索引名2,列索引名3,...]]
df.loc[:,起始列索引名:终止列索引名:步长]
df.iloc[:,起始列索引值:终止列索引值:步长]
花式切片
df.loc[起始行索引名:终止行索引名:行步长, 起始列索引名:终止列索引名:列步长]
df.iloc[起始行索引值:终止行索引值:行步长, 起始列索引值:终止列索引值:列步长]
布尔索引
例如:
# 找出df的A列值最小的那行数据
df[df.A==df.A.min()]
pandas.read_excel(io,
sheet_name=0,
header=0,
names=None,
index_col=None,
usecols=None,
squeeze=False,
dtype=None,
engine=None,
converters=None,
true_values=None,
false_values=None,
skiprows=None,
nrows=None,
na_values=None,
keep_default_na=True,
na_filter=True,
verbose=False,
parse_dates=False,
date_parser=None,
thousands=None,
comment=None,
skipfooter=0,
convert_float=True,
mangle_dupe_cols=True,
storage_options=None)
一般格式:
DataFrame.plot(x=None, y=None, kind='line', ax=None, subplots=False,
sharex=None, sharey=False, layout=None, figsize=None,
use_index=True, title=None, grid=None, legend=True,
style=None, logx=False, logy=False, loglog=False,
xticks=None, yticks=None, xlim=None, ylim=None, rot=None,
fontsize=None, colormap=None, position=0.5, table=False, yerr=None,
xerr=None, stacked=True/False, sort_columns=False,
secondary_y=False, mark_right=True, **kwds)
主要参数解释:
- x : label or position, default None#指数据框列的标签或位置参数
- y : label or position, default None
- kind : str
- ‘line’ : line plot (default)#折线图
- ‘bar’ : vertical bar plot#条形图
- ‘barh’ : horizontal bar plot#横向条形图
- ‘hist’ : histogram#柱状图
- ‘box’ : boxplot#箱线图
- ‘kde’ : Kernel Density Estimation plot#Kernel 的密度估计图,主要对柱状图添加Kernel 概率密度线
- ‘density’ : same as ‘kde’
- ‘area’ : area plot#不了解此图
- ‘pie’ : pie plot#饼图
- ‘scatter’ : scatter plot#散点图 需要传入columns方向的索引
- ‘hexbin’ : hexbin plot#不了解此图
- ax : matplotlib axes object, default None#子图(axes, 也可以理解成坐标轴) 要在其上进行绘制的matplotlib subplot对象。如果没有设置,则使用当前matplotlib subplot其中,变量和函数通过改变figure和axes中的元素(例如:title,label,点和线等等)一起描述figure和axes,也就是在画布上绘图。
- subplots : boolean, default False#判断图片中是否有子图
- Make separate subplots for each column
- sharex : boolean, default True if ax is None else False#如果有子图,子图共x轴刻度,标签
- In case subplots=True, share x axis and set some x axis labels to invisible; defaults to True if ax is None otherwise False if an ax is passed in; Be aware, that passing in both an ax and sharex=True will alter all x axis labels for all axis in a figure!
- sharey : boolean, default False#如果有子图,子图共y轴刻度,标签
- In case subplots=True, share y axis and set some y axis labels to invisible
- layout : tuple (optional)#子图的行列布局
- (rows, columns) for the layout of subplots
- figsize : a tuple (width, height) in inches#图片尺寸大小
- use_index : boolean, default True#默认用索引做x轴
- title : string#图片的标题用字符串
- grid : boolean, default None (matlab style default)#图片是否有网格
- Axis grid lines
- legend : False/True/’reverse’#子图的图例,添加一个subplot图例(默认为True)
- Place legend on axis subplots
- style : list or dict#对每列折线图设置线的类型
- matplotlib line style per column
- logx : boolean, default False#设置x轴刻度是否取对数
- Use log scaling on x axis
- logy : boolean, default False
- Use log scaling on y axis
- loglog : boolean, default False#同时设置x,y轴刻度是否取对数
- Use log scaling on both x and y axes
- xticks : sequence#设置x轴刻度值,序列形式(比如列表)
- Values to use for the xticks
- yticks : sequence#设置y轴刻度,序列形式(比如列表)
- Values to use for the yticks
- xlim : 2-tuple/list#设置坐标轴的范围,列表或元组形式
- ylim : 2-tuple/list
- rot : int, default None#设置轴标签(轴刻度)的显示旋转度数
- Rotation for ticks (xticks for vertical, yticks for horizontal plots)
- fontsize : int, default None#设置轴刻度的字体大小
- Font size for xticks and yticks
- colormap : str or matplotlib colormap object, default None#设置图的区域颜色
- Colormap to select colors from. If string, load colormap with that name from matplotlib.
- colorbar : boolean, optional #图片柱子
- If True, plot colorbar (only relevant for ‘scatter’ and ‘hexbin’ plots)
- position : float
- Specify relative alignments for bar plot layout. From 0 (left/bottom-end) to 1 (right/top-end). Default is 0.5 (center)
- layout : tuple (optional) #布局
- (rows, columns) for the layout of the plot
- table : boolean, Series or DataFrame, default False #如果为正,则选择DataFrame类型的数据并且转换匹配matplotlib的布局。
- If True, draw a table using the data in the DataFrame and the data will be transposed to meet matplotlib’s default layout. If a Series or DataFrame is passed, use passed data to draw a table.
- yerr : DataFrame, Series, array-like, dict and str
- See Plotting with Error Bars for detail.
- xerr : same types as yerr.
- stacked : boolean, default False in line and
- bar plots, and True in area plot. If True, create stacked plot.
- sort_columns : boolean, default False # 以字母表顺序绘制各列,默认使用前列顺序
- secondary_y : boolean or sequence, default False ##设置第二个y轴(右y轴)
- Whether to plot on the secondary y-axis If a list/tuple, which columns to plot on secondary y-axis
- mark_right : boolean, default True
- When using a secondary_y axis, automatically mark the column labels with “(right)” in the legend
- kwds : keywords
- Options to pass to matplotlib plotting method
- Returns:axes : matplotlib.AxesSubplot or np.array of them
Pandas在绘图时,会显示中文为方块,主要原因有二: matplotlib 字体问题,seaborn 字体问题。
没有中文字体,所以我们只要手动添加中文字体的名称就可以了,不过并不是添加我们熟悉的“宋体”或“黑体”这类的名称,而是要添加字体管理器识别出的字体名称,matplotlib自身实现的字体管理器在文件font_manager.py中,自动生成的可用字体信息在保存在文件fontList.cache里,可以搜索这个文件查看对应字体的名称,例如simhei.ttf对应的名称为’SimHei’,simkai.ttf对应的名称为’KaiTi_GB2312’等。因此我们只要把这些名称添加到配置文件中去就可以让matplotlib显示中文。
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] #MAC中设置字体为"Arial Unicode MS"
plt.rcParams['font.serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题,或者转换负号为字符串
3σ原则,又称为拉依达原则,它是先假设一组检测数据只含有随机误差,对该组数据进行计算处理得到标准偏差,按一定概率确定一个区间,凡是超过这个区间的误差不属于随机误差而是粗大误差,含有粗大误差范围内的数据(视为异常值)应予以剔除。
3σ原则异常值检测函数
import numpy as np
import pandas as pd
def three_sigma(ser):
"""
ser参数:被检测的数据,是一个Series
返回值:异常值及其对应的行索引
"""
# 计算平均值
mean_data = ser.mean()
# 计算标准差sigma
std_data = ser.std()
#小于(均值-3倍标准差) 或者 大于 (均值+3倍标准差)的数值都是异常的
rule = ((mean_data-3*std_data)>ser) | ((mean_data+3*std_data)<ser)
# 返回异常值的行索引
index = np.arange(ser.shape[0])[rule]
# 获取异常值
outliers = ser.iloc[index]
return outliers
除了使用3σ原则检测异常值之外,还可以使用箱形图检测异常值。
需要说明的是,箱形图对检测数据没有任何要求,即使不符合正态分布的数据集是能被检测的。
箱形图是一种用于显示一组数据分散情况的统计图,它通常由上边缘、上四分位数、中位数、下四分位数、下边缘和异常值组成。箱形图能直观地反映出一组数据的分散情况,一旦图中出现离群点(远离大多数值的点),就认为该离群点可能为异常值。
箱形图异常值检测函数
import pandas as pd
import numpy as np
def box_outliers(ser):
# 对待检测的数据集进行排序
new_ser = ser.sort_values()
# 判断待检测数据集数的个数数偶数还是奇数
if new_ser.count() %2==0:
#计算Q3,Q1
Q3 = new_ser[int(len(new_ser)/2):].median()
Q1 = new_ser[:int(len(new_ser)/2)].median()
else:
#计算Q3,Q1
Q3 = new_ser[int((len(new_ser)-1)/2):].median()
Q1 = new_ser[:int((len(new_ser)-1)/2)].median()
#计算IQR
IQR = round(Q3-Q1,1)
# 制定异常值规则
rule = (round(Q3+1.5*IQR,1)<ser)|(round(Q1-1.5*IQR,1)>ser)
# 返回异常值的行索引
index = np.arange(ser.shape[0])[rule]
# 获取异常值
outliers = ser.iloc[index]
return outliers
在使用Pandas进行数据库操作之前,先学会如何使用Python+sqlalchemy创建数据库。
其方法有如下两种:(数据库连接用户名: root,密码:123456,本地地址127.0.0.1,端口号:3306,创建数据库:sx1db)
from sqlalchemy import create_engine
# 方法一, 利用sqlalchemy_utils库的create_databse模块
# 需要提前用"pip install sqlalchemy_utils"安装sqlalchemy_utils
from sqlalchemy_utils import database_exists, create_database
engine = create_engine('mysql+pymysql://root:[email protected]:3306/sx1db')
if not database_exists(engine.url):
create_database(engine.url,encoding='gb2312')
print(database_exists(engine.url))
# 方法二 单纯使用sqlalchemy
with create_engine('mysql+pymysql://root:123456@localhost:3306/',
isolation_level='AUTOCOMMIT').connect() as connection:
connection.execute('CREATE DATABASE sx1db charset="gb2312"')
engine = create_engine('dialect+driver://username:password@host:port/database',encoding='gb2312')
?create_engine
.to_sql(name,
con,
flavor=None,
schema=None,
if_exists='fail',
index=True,
index_label=None,
chunksize=None,
dtype=None)
```
- **参数详解**
- name:指定的是将输入接入数据库当做的哪个表
- con:与数据库链接的方式,推荐使用sqlalchemy的engine类型
- schema: 相应数据库的引擎,不设置则使用数据库的默认引擎,如mysql中的innodb引擎
- if_exists: 当数据库中已经存在数据表时对数据表的操作
- replace:替换
- append:追加
- fail:则当表存在时提示ValueError。
- index:对DataFrame的index索引的处理,为True时索引也将作为数据写入数据表
- index_label:当上一个参数index为True时,设置写入数据表时index的列名称
- chunsize:设置整数,如20000,一次写入数据时的数据行数量,当数据量很大时,需要设置,否则会链接超时写入失败。
- dtype:写入数据表时,可以设置列的名称(The keys should be the column names and the values should be the SQLAlchemy types or strings for the sqlite3 legacy mode),需要设置时,类型需要和sqlalchemy的类型保持一致.当不设置时,to_sql生成表时会自动兼容最大的类型。
.to_sql()参数中除 name、con必填外,可选参数index推荐使用False,同时dtype推荐不使用。
#### 1.2.7.3 Pandas从MySQL中获取数据
- **.read_sql()方法的一般格式**
```python
pandas.read_sql(sql,
con,
index_col=None,
coerce_float=True,
params=None,
parse_dates=None,
columns=None,
chunksize=None)
在实训中,要求将不同行业的数据存入到不同的的MySQL数据库中,数据库命名一个自然的想法是采用行业名的英文或汉语拼音为名。
汉语拼音全拼时太长,因此打算用汉语拼音每个字首字母大写+"db"作为数据库的名称。
爬取时,外面获得的行业名为汉语文字,如何将其转换为汉语拼音,网上有很多个共享的工具包可用。
这里用pinyin工具包,使用前先用python pip install pinyin
进行安装。
构建数据库名称的代码如下:
hyName = '煤炭开采和洗选业'
dbName = [''+pinyin.get(x)[0].upper() for x in hyName] # mysql中部区分大小写,所以转换成大写起始没啥用
dbName = "".join(dbName)+'db'
print(dbName)
hyName = '煤炭开采和洗选业'
dbName = [''+pinyin.get(x)[0].upper() for x in hyName] # mysql中部区分大小写,所以转换成大写起始没啥用
dbName = "".join(dbName)+'db'
print(dbName)
MTKCHXXYdb
# 导入库
import requests
from lxml import etree
import pandas as pd
import csv
# 设置请求头
headers = {
'user-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
'Host':'s.askci.com'
}
# 设置请求url
url = 'https://s.askci.com/data/economy/00001/'
# 获得响应
r = requests.get(url, headers = headers)
# 编码转换,避免乱码
r.encoding = r.apparent_encoding
# 采用etree.HTML解析
html = etree.HTML(r.text)
# 采用xpath获得行业名
hyName = html.xpath('/html/body/div[4]/div[2]/div[1]/a[3]/text()')[0]
# 获取表格数据
html_tables = pd.read_html(r.content,header=0,index_col=0)
print("读取的类别:",type(html_tables),"\n表格的个数:",len(html_tables))
读取的类别:
表格的个数: 5
html_tables[0].head()
企业数量(个) | 亏损企业数(个) | 亏损总额(亿元) | 累计增长(%) | 存货(亿元) | 累计增长(%).1 | 产成品(亿元) | 累计增长(%).2 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202203 | 4546 | 1498 | 180.1 | 5.6 | 1244.5 | 4.0 | 617.2 | 12.9 |
202202 | 4539 | 1395 | 116.9 | 3.7 | 1197.8 | 0.1 | 574.1 | 3.3 |
202112 | 4343 | 970 | 560.9 | -8.3 | 1242.4 | 5.0 | 603.5 | 10.4 |
202111 | 4343 | 1024 | 440.1 | -21.5 | 1350.0 | 8.5 | 680.9 | 15.1 |
202110 | 4334 | 1083 | 382.8 | -27.9 | 1300.6 | 3.9 | 627.9 | 5.9 |
html_tables[0].info()
Int64Index: 112 entries, 202203 to 201202
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 企业数量(个) 112 non-null int64
1 亏损企业数(个) 112 non-null int64
2 亏损总额(亿元) 112 non-null float64
3 累计增长(%) 112 non-null float64
4 存货(亿元) 112 non-null float64
5 累计增长(%).1 112 non-null float64
6 产成品(亿元) 112 non-null float64
7 累计增长(%).2 112 non-null float64
dtypes: float64(6), int64(2)
memory usage: 7.9 KB
html_tables[1].head()
流动资产合计(亿元) | 累计增长(%) | 应收帐款(亿元) | 累计增长(%).1 | 资产总计(亿元) | 累计增长(%).2 | 负债合计(亿元) | 累计增长(%).3 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202203 | 32073.7 | 31.5 | 4632.4 | 51.9 | 69195.4 | 13.1 | 43842.2 | 6.7 |
202202 | 30933.3 | 30.6 | 4503.6 | 56.4 | 67953.5 | 13.6 | 43102.2 | 7.9 |
202112 | 31153.2 | 33.7 | 4313.7 | 60.1 | 67994.9 | 13.0 | 44117.8 | 10.1 |
202111 | 31168.1 | 28.5 | 4760.4 | 58.5 | 67961.0 | 13.7 | 43581.5 | 10.5 |
202110 | 30230.8 | 25.0 | 4474.9 | 52.8 | 66818.4 | 12.3 | 43387.3 | 11.3 |
html_tables[2].head()
主营业务收入(亿元) | 累计增长(%) | 利润总额(亿元) | 累计增长(%).1 | 主营业务税金及附加(亿元) | 累计增长(%).2 | 应交增值税(亿元) | 累计增长(%).3 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202203 | -- | -- | 2357.0 | 189 | -- | -- | -- | -- |
202202 | -- | -- | 1484.8 | 155.3 | -- | -- | -- | -- |
202112 | -- | -- | 7023.1 | 212.7 | -- | -- | -- | -- |
202111 | -- | -- | 6473.6 | 222.6 | -- | -- | -- | -- |
202110 | -- | -- | 5435.7 | 210.2 | -- | -- | -- | -- |
html_tables[3].head()
主营业务成本(亿元) | 累计增长(%) | 销售费用(亿元) | 累计增长(%).1 | 管理费用(亿元) | 累计增长(%).2 | 财务费用(亿元) | 累计增长(%).3 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202203 | -- | -- | 120.7 | -16.0 | 498.9 | 29.6 | 213.0 | 3.1 |
202202 | -- | -- | 74.0 | -25.7 | 290.9 | 22.7 | 122.1 | -5.2 |
202112 | -- | -- | 609.2 | 1.6 | 1897.2 | 27.3 | 876.9 | 8.0 |
202111 | -- | -- | 553.1 | 2.4 | 1590.0 | 22.0 | 760.7 | 6.8 |
202110 | -- | -- | 502.0 | 3.1 | 1412.2 | 20.5 | 696.7 | 7.2 |
html_tables[4].head()
增加值同比增长(%) | 增加值累计增长(%) | 出口交货值当月值(亿元) | 同比增长(%) | 出口交货值累计值(亿元) | 累计增长(%) | |
---|---|---|---|---|---|---|
类别年份 | ||||||
202203 | 16.7 | 13.2 | 0 | -95.3 | 0.2 | -95.1 |
202202 | -- | 11.1 | -- | -- | 0.4 | -91.9 |
202112 | 12.2 | 6.7 | 0 | -100 | 0.3 | -93.4 |
202111 | 9.6 | 6.1 | 0 | -100 | 0.5 | -88.1 |
202110 | 9.2 | 5.6 | 0 | -100 | 0.5 | -91.1 |
import os
excelFileName = hyName+".xlsx"
hyParaNames = ["经济指标","资产负债","收入利润","成本费用","产值指标"]
sheet_names = hyParaNames
# 经济指标
if not os.path.exists(excelFileName):
html_tables[0].to_excel(excelFileName,sheet_name=sheet_names[0], index=True)
else:
with pd.ExcelWriter(excelFileName, engine='openpyxl', mode='a',if_sheet_exists='replace') as writer:
html_tables[0].to_excel(writer,sheet_name=sheet_names[0], index=True)
# 资产负债
if not os.path.exists(excelFileName):
html_tables[1].to_excel(excelFileName,sheet_name=sheet_names[1], index=True)
else:
with pd.ExcelWriter(excelFileName, engine='openpyxl', mode='a',if_sheet_exists='replace') as writer:
html_tables[1].to_excel(writer,sheet_name=sheet_names[1], index=True)
# 收入利润
if not os.path.exists(excelFileName):
html_tables[2].to_excel(excelFileName,sheet_name=sheet_names[2], index=True)
else:
with pd.ExcelWriter(excelFileName, engine='openpyxl', mode='a',if_sheet_exists='replace') as writer:
html_tables[2].to_excel(writer,sheet_name=sheet_names[2], index=True)
# 成本费用
if not os.path.exists(excelFileName):
html_tables[3].to_excel(excelFileName,sheet_name=sheet_names[3], index=True)
else:
with pd.ExcelWriter(excelFileName, engine='openpyxl', mode='a',if_sheet_exists='replace') as writer:
html_tables[3].to_excel(writer,sheet_name=sheet_names[3], index=True)
# 产值指标
if not os.path.exists(excelFileName):
html_tables[4].to_excel(excelFileName,sheet_name=sheet_names[4], index=True)
else:
with pd.ExcelWriter(excelFileName, engine='openpyxl', mode='a',if_sheet_exists='replace') as writer:
html_tables[4].to_excel(writer,sheet_name=sheet_names[4], index=True)
df_mt_jj = pd.read_excel("煤炭开采和洗选业.xlsx",sheet_name="经济指标",index_col=0)
# 查看开始5行
df_mt_jj.head()
企业数量(个) | 亏损企业数(个) | 亏损总额(亿元) | 累计增长(%) | 存货(亿元) | 累计增长(%).1 | 产成品(亿元) | 累计增长(%).2 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202203 | 4546 | 1498 | 180.1 | 5.6 | 1244.5 | 4.0 | 617.2 | 12.9 |
202202 | 4539 | 1395 | 116.9 | 3.7 | 1197.8 | 0.1 | 574.1 | 3.3 |
202112 | 4343 | 970 | 560.9 | -8.3 | 1242.4 | 5.0 | 603.5 | 10.4 |
202111 | 4343 | 1024 | 440.1 | -21.5 | 1350.0 | 8.5 | 680.9 | 15.1 |
202110 | 4334 | 1083 | 382.8 | -27.9 | 1300.6 | 3.9 | 627.9 | 5.9 |
# 查看后5行
df_mt_jj.tail()
企业数量(个) | 亏损企业数(个) | 亏损总额(亿元) | 累计增长(%) | 存货(亿元) | 累计增长(%).1 | 产成品(亿元) | 累计增长(%).2 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
201206 | 7690 | 1374 | 102.77 | 85.27 | 1942.58 | 32.30 | 735.24 | 24.20 |
201205 | 7690 | 1316 | 80.04 | 74.19 | 1945.20 | 30.89 | 743.32 | 24.38 |
201204 | 7695 | 1356 | 69.59 | 73.37 | 1888.53 | 30.16 | 713.16 | 25.63 |
201203 | 7696 | 1455 | 56.66 | 61.52 | 1758.56 | 32.47 | 700.50 | 27.54 |
201202 | 7696 | 1453 | 44.88 | 83.41 | 1675.09 | 32.57 | 698.14 | 35.00 |
# 查看总体信息
df_mt_jj.info()
Int64Index: 112 entries, 202203 to 201202
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 企业数量(个) 112 non-null int64
1 亏损企业数(个) 112 non-null int64
2 亏损总额(亿元) 112 non-null float64
3 累计增长(%) 112 non-null float64
4 存货(亿元) 112 non-null float64
5 累计增长(%).1 112 non-null float64
6 产成品(亿元) 112 non-null float64
7 累计增长(%).2 112 non-null float64
dtypes: float64(6), int64(2)
memory usage: 7.9 KB
# 查看统计描述
df_mt_jj.describe()
企业数量(个) | 亏损企业数(个) | 亏损总额(亿元) | 累计增长(%) | 存货(亿元) | 累计增长(%).1 | 产成品(亿元) | 累计增长(%).2 | |
---|---|---|---|---|---|---|---|---|
count | 112.000000 | 112.000000 | 112.000000 | 112.000000 | 112.000000 | 112.000000 | 112.000000 | 112.000000 |
mean | 5696.705357 | 1566.919643 | 311.793661 | 25.219107 | 1880.310804 | 4.312589 | 782.313571 | 3.848750 |
std | 1424.317220 | 371.524983 | 195.253860 | 52.721925 | 446.522572 | 10.319600 | 162.556546 | 12.215957 |
min | 4137.000000 | 970.000000 | 44.880000 | -68.800000 | 1134.700000 | -9.500000 | 511.200000 | -16.200000 |
25% | 4308.500000 | 1227.000000 | 165.500000 | -8.525000 | 1599.250000 | -3.725000 | 630.300000 | -6.700000 |
50% | 5110.500000 | 1494.000000 | 254.750000 | 23.600000 | 1919.635000 | 1.350000 | 788.020000 | 2.600000 |
75% | 7058.250000 | 1943.500000 | 411.800000 | 50.175000 | 2238.575000 | 9.032500 | 915.422500 | 12.277500 |
max | 7975.000000 | 2344.000000 | 972.600000 | 171.070000 | 2559.400000 | 33.350000 | 1053.600000 | 35.400000 |
# 企业个数
data_qygs = df_mt_jj["企业数量(个)"]
data_qygs
类别年份
202203 4546
202202 4539
202112 4343
202111 4343
202110 4334
...
201206 7690
201205 7690
201204 7695
201203 7696
201202 7696
Name: 企业数量(个), Length: 112, dtype: int64
# 亏损企业个数
data_ksqy = df_mt_jj["亏损企业数(个)"]
data_ksqy
类别年份
202203 1498
202202 1395
202112 970
202111 1024
202110 1083
...
201206 1374
201205 1316
201204 1356
201203 1455
201202 1453
Name: 亏损企业数(个), Length: 112, dtype: int64
# 一次获取多列
data_qy = df_mt_jj[["企业数量(个)","亏损企业数(个)"]]
data_qy
企业数量(个) | 亏损企业数(个) | |
---|---|---|
类别年份 | ||
202203 | 4546 | 1498 |
202202 | 4539 | 1395 |
202112 | 4343 | 970 |
202111 | 4343 | 1024 |
202110 | 4334 | 1083 |
... | ... | ... |
201206 | 7690 | 1374 |
201205 | 7690 | 1316 |
201204 | 7695 | 1356 |
201203 | 7696 | 1455 |
201202 | 7696 | 1453 |
112 rows × 2 columns
import matplotlib.pyplot as plt
# 中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
# 绘制亏损企业个数和企业个数折线图
data_ksqy.plot(label="亏损企业数")
data_qygs.plot(label="企业数");
# 添加x标签与y标签
plt.xlabel("年月")
plt.ylabel("个数")
# 添加标题
plt.title("企业个数与亏损企业个数")
# 添加图例
plt.legend(loc="best");
import matplotlib.pyplot as plt
# 中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
# 绘制亏损企业个数和企业个数折线图
data_qy.plot()
# 添加x标签与y标签
plt.xlabel("年月")
plt.ylabel("个数")
# 添加标题
plt.title("企业个数与亏损企业个数")
# 添加图例
plt.legend(loc="best");
plt.rcParams['font.sans-serif'] = ['SimHei']
data_ksqy.plot(kind='bar',label="亏损企业数");
data_qygs.plot.bar("企业数",label="企业数")
# 添加x标签与y标签
plt.xlabel("年月")
plt.ylabel("个数")
# 添加标题
plt.title("企业个数与亏损企业个数")
# 添加图例
plt.legend(loc="best");
柱状图不适合绘制数目过多的数据
下面绘制2021年度的
data_qy.loc["202112":"202101"]
企业数量(个) | 亏损企业数(个) | |
---|---|---|
类别年份 | ||
202112 | 4343 | 970 |
202111 | 4343 | 1024 |
202110 | 4334 | 1083 |
202109 | 4322 | 1224 |
202108 | 4312 | 1234 |
202107 | 4298 | 1305 |
202106 | 4284 | 1407 |
202105 | 4276 | 1358 |
202104 | 4273 | 1455 |
202103 | 4267 | 1589 |
202102 | 4264 | 1380 |
plt.rcParams['font.sans-serif'] = ['SimHei']
data_qy.loc["202112":"202101"].plot(kind='bar')
# 添加x标签与y标签
plt.xlabel("年月")
plt.ylabel("个数")
# 添加标题
plt.title("企业个数与亏损企业个数")
# 添加图例
plt.legend(loc="best");
在plt.legend()函数中加入若干参数:
plt.legend(bbox_to_anchor=(num1, num2), loc=num3, borderaxespad=num4)
bbox_to_anchor(num1,num2)表示legend的位置和图像的位置关系,num1表示水平位置,num2表示垂直位置。num1=0表示legend位于图像的左侧垂直线(这里的其它参数设置:num2=0,num3=3,num4=0)。
plt.rcParams['font.sans-serif'] = ['SimHei']
data_qy.loc["202112":"202101"].plot(kind='bar')
# 添加x标签与y标签
plt.xlabel("年月")
plt.ylabel("个数")
# 添加标题
plt.title("企业个数与亏损企业个数")
# 添加图例到axis外
num1=1.05
num2=0
num3=3
num4=0
plt.legend(bbox_to_anchor=(num1, num2), loc=num3, borderaxespad=num4);
# 取的经济指标中2021年度数据
df_mt_jj_2021 = df_mt_jj.loc["202112":"202101"]
df_mt_jj_2021
企业数量(个) | 亏损企业数(个) | 亏损总额(亿元) | 累计增长(%) | 存货(亿元) | 累计增长(%).1 | 产成品(亿元) | 累计增长(%).2 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202112 | 4343 | 970 | 560.9 | -8.3 | 1242.4 | 5.0 | 603.5 | 10.4 |
202111 | 4343 | 1024 | 440.1 | -21.5 | 1350.0 | 8.5 | 680.9 | 15.1 |
202110 | 4334 | 1083 | 382.8 | -27.9 | 1300.6 | 3.9 | 627.9 | 5.9 |
202109 | 4322 | 1224 | 383.1 | -21.7 | 1223.0 | -1.1 | 565.0 | -5.0 |
202108 | 4312 | 1234 | 358.1 | -15.1 | 1179.9 | -4.1 | 538.4 | -9.4 |
202107 | 4298 | 1305 | 323.6 | -12.6 | 1166.7 | -3.2 | 534.2 | -9.0 |
202106 | 4284 | 1407 | 262.1 | -18.4 | 1145.1 | -3.3 | 522.8 | -8.6 |
202105 | 4276 | 1358 | 232.5 | -19.6 | 1153.9 | -3.5 | 530.5 | -7.5 |
202104 | 4273 | 1455 | 208.0 | -9.2 | 1134.7 | -5.2 | 511.2 | -10.3 |
202103 | 4267 | 1589 | 165.5 | -9.7 | 1163.8 | -0.2 | 530.5 | -5.2 |
202102 | 4264 | 1380 | 110.2 | -30.0 | 1170.0 | -0.4 | 541.4 | 2.9 |
# 查看2021年煤炭开采和洗选业的亏损总额
data_ksze = df_mt_jj.loc["202112":"202101","亏损总额(亿元)"]
data_ksze
类别年份
202112 560.9
202111 440.1
202110 382.8
202109 383.1
202108 358.1
202107 323.6
202106 262.1
202105 232.5
202104 208.0
202103 165.5
202102 110.2
Name: 亏损总额(亿元), dtype: float64
# 亏损总额最大值
data_ksze.max()
560.9
# 亏损总额最大值
# 直接从df_mt_jj_2021中获取
df_mt_jj_2021["亏损总额(亿元)"].max()
560.9
# 亏损总额最小值
data_ksze.min()
110.2
# 查看亏损总额最大的月份的经济指标
df_mt_jj_2021[df_mt_jj_2021["亏损总额(亿元)"]==df_mt_jj_2021["亏损总额(亿元)"].max()]
企业数量(个) | 亏损企业数(个) | 亏损总额(亿元) | 累计增长(%) | 存货(亿元) | 累计增长(%).1 | 产成品(亿元) | 累计增长(%).2 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202112 | 4343 | 970 | 560.9 | -8.3 | 1242.4 | 5.0 | 603.5 | 10.4 |
# 查看亏损总额最少的月份的经济指标
df_mt_jj_2021[df_mt_jj_2021["亏损总额(亿元)"]==df_mt_jj_2021["亏损总额(亿元)"].min()]
企业数量(个) | 亏损企业数(个) | 亏损总额(亿元) | 累计增长(%) | 存货(亿元) | 累计增长(%).1 | 产成品(亿元) | 累计增长(%).2 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202102 | 4264 | 1380 | 110.2 | -30.0 | 1170.0 | -0.4 | 541.4 | 2.9 |
# 绘制出2021年度亏损总额的曲线图,并添加图表题、x标签、y标签
df_mt_jj_2021["亏损总额(亿元)"].plot()
plt.title("2021年度亏损总额")
plt.ylabel("亏损总额(亿元)")
loc=df_mt_jj_2021.index
plt.xticks(loc,[str(x)+"月" for x in range(2,13)])
plt.xlabel("月份");
# 绘制出2021年度亏损总额的条形图,并添加图表题、x标签、y标签
df_mt_jj_2021["亏损总额(亿元)"].plot.bar(label="亏损总额")
# 添加数据标注
for x, y in enumerate(df_mt_jj_2021["亏损总额(亿元)"].values):
plt.text(x+0.4, y+1,y,ha='right',va='bottom')
plt.title("2021年度亏损总额")
plt.ylabel("亏损总额(亿元)")
plt.xlabel("月份")
plt.legend(loc='best');
df_mt_cb = pd.read_excel("煤炭开采和洗选业.xlsx",sheet_name="成本费用",index_col=0)
# 查看开始5行
df_mt_cb.head()
主营业务成本(亿元) | 累计增长(%) | 销售费用(亿元) | 累计增长(%).1 | 管理费用(亿元) | 累计增长(%).2 | 财务费用(亿元) | 累计增长(%).3 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202203 | -- | -- | 120.7 | -16.0 | 498.9 | 29.6 | 213.0 | 3.1 |
202202 | -- | -- | 74.0 | -25.7 | 290.9 | 22.7 | 122.1 | -5.2 |
202112 | -- | -- | 609.2 | 1.6 | 1897.2 | 27.3 | 876.9 | 8.0 |
202111 | -- | -- | 553.1 | 2.4 | 1590.0 | 22.0 | 760.7 | 6.8 |
202110 | -- | -- | 502.0 | 3.1 | 1412.2 | 20.5 | 696.7 | 7.2 |
ser_cb_gl = df_mt_cb["管理费用(亿元)"]
ser_cb_gl
类别年份
202203 498.90
202202 290.90
202112 1897.20
202111 1590.00
202110 1412.20
...
201206 1103.77
201205 921.51
201204 727.64
201203 533.49
201202 331.51
Name: 管理费用(亿元), Length: 112, dtype: float64
import numpy as np
import pandas as pd
def three_sigma(ser):
"""
ser参数:被检测的数据,是一个Series
返回值:异常值及其对应的行索引
"""
# 计算平均值
mean_data = ser.mean()
# 计算标准差sigma
std_data = ser.std()
#小于(均值-3倍标准差) 或者 大于 (均值+3倍标准差)的数值都是异常的
rule = ((mean_data-3*std_data)>ser) | ((mean_data+3*std_data)<ser)
# 返回异常值的行索引
index = np.arange(ser.shape[0])[rule]
# 获取异常值
outliers = ser.iloc[index]
return outliers
three_sigma(ser_cb_gl)
Series([], Name: 管理费用(亿元), dtype: float64)
结果为空值,说明没有异常点出现
import pandas as pd
import numpy as np
def box_outliers(ser):
# 对待检测的数据集进行排序
new_ser = ser.sort_values()
# 判断待检测数据集数的个数数偶数还是奇数
if new_ser.count() %2==0:
#计算Q3,Q1
Q3 = new_ser[int(len(new_ser)/2):].median()
Q1 = new_ser[:int(len(new_ser)/2)].median()
else:
#计算Q3,Q1
Q3 = new_ser[int((len(new_ser)-1)/2):].median()
Q1 = new_ser[:int((len(new_ser)-1)/2)].median()
#计算IQR
IQR = round(Q3-Q1,1)
# 制定异常值规则
rule = (round(Q3+1.5*IQR,1)<ser)|(round(Q1-1.5*IQR,1)>ser)
# 返回异常值的行索引
index = np.arange(ser.shape[0])[rule]
# 获取异常值
outliers = ser.iloc[index]
return outliers
box_outliers(ser_cb_gl)
Series([], Name: 管理费用(亿元), dtype: float64)
# 根据爬取的行业名(hyName)自动构建数据库名
hyName
'煤炭开采和洗选业'
import pinyin
dbName = [''+pinyin.get(x)[0].upper() for x in hyName]
dbName = "".join(dbName)+'db'
dbName
'MTKCHXXYdb'
from sqlalchemy import create_engine
# 方法一, 利用sqlalchemy_utils库的create_databse模块,
# 需要提前用"pip install sqlalchemy_utils"安装sqlalchemy_utils
from sqlalchemy_utils import database_exists, create_database
connection = create_engine(f'mysql+pymysql://root:[email protected]:3306/{dbName}',encoding='gb2312')
if not database_exists(connection.url):
create_database(connection.url,encoding='gb2312')
print(database_exists(connection.url))
True
或采用方法二实现如下:
from sqlalchemy import create_engine
# 方法二 单纯使用sqlalchemyf
with create_engine('mysql+pymysql://root:123456@localhost:3306/',
isolation_level='AUTOCOMMIT').connect() as connection:
connection.execute(f'CREATE DATABASE {dbName} charset="gb2312"')
list('煤炭开采和洗选业')
['煤', '炭', '开', '采', '和', '洗', '选', '业']
hyParaNames
['经济指标', '资产负债', '收入利润', '成本费用', '产值指标']
tableName = hyParaNames[0]
tableName
'经济指标'
# 经济指标
html_tables[0]
企业数量 | 亏损企业数 | 亏损总额 | 累计增长 | 存货 | 累计增长 | 产成品 | 累计增长 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202203 | 4546 | 1498 | 180.10 | 5.60 | 1244.50 | 4.00 | 617.20 | 12.90 |
202202 | 4539 | 1395 | 116.90 | 3.70 | 1197.80 | 0.10 | 574.10 | 3.30 |
202112 | 4343 | 970 | 560.90 | -8.30 | 1242.40 | 5.00 | 603.50 | 10.40 |
202111 | 4343 | 1024 | 440.10 | -21.50 | 1350.00 | 8.50 | 680.90 | 15.10 |
202110 | 4334 | 1083 | 382.80 | -27.90 | 1300.60 | 3.90 | 627.90 | 5.90 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
201206 | 7690 | 1374 | 102.77 | 85.27 | 1942.58 | 32.30 | 735.24 | 24.20 |
201205 | 7690 | 1316 | 80.04 | 74.19 | 1945.20 | 30.89 | 743.32 | 24.38 |
201204 | 7695 | 1356 | 69.59 | 73.37 | 1888.53 | 30.16 | 713.16 | 25.63 |
201203 | 7696 | 1455 | 56.66 | 61.52 | 1758.56 | 32.47 | 700.50 | 27.54 |
201202 | 7696 | 1453 | 44.88 | 83.41 | 1675.09 | 32.57 | 698.14 | 35.00 |
112 rows × 8 columns
html_tables[0].columns#=['企业数量', '亏损企业数', '亏损总额', '累计增长', '存货', '累计增长','产成品', '累计增长']
Index(['企业数量(个)', '亏损企业数(个)', '亏损总额(亿元)', '累计增长(%)', '存货(亿元)', '累计增长(%).1',
'产成品(亿元)', '累计增长(%).2'],
dtype='object')
坑点1:想法是将列索引作为MySQL的列名创建数据表,发现列名含“(”的后续有问题
坑点2:列名有些是相同的,应该想办法更改为不同(最后的解决办法可能最好是直接重新赋值)
解决办法如下
[xx[:xx.find("(")] if xx.find("(")>0 else xx for xx in html_tables[0].columns]
['企业数量', '亏损企业数', '亏损总额', '累计增长', '存货', '累计增长', '产成品', '累计增长']
采用如上方法能够比较方便的取得括号之前的部分,但对于重复列名(如"累计增长")不是很容易处理。
若要用程序处理,可以用循环+判断实现将其与前一列名并入进来予以明确。
但对于本应用,字段是明确的,且并不太繁杂,可以采用下面的方式,直接定义好列名,在存储到数据库前从次取出去替换掉。
columns = [['企业数量', '亏损企业数', '亏损总额', '亏损总额累计增长', '存货', '存货累计增长', '产成品', '产成品累计增长'],
['流动资产合计', '流动资产合计累计增长', '应收帐款', '应收帐款累计增长', '资产总计', '资产总计累计增长', '负债合计', '负债合计累计增长'],
['主营业务收入', '主营业务收入累计增长', '利润总额', '利润总额累计增长', '主营业务税金及附加', '主营业务税金及附加累计增长', '应交增值税', '应交增值税累计增长'],
['主营业务成本', '主营业务成本累计增长', '销售费用', '销售费用累计增长', '管理费用', '管理费用累计增长', '财务费用', '财务费用累计增长'],
['增加值同比增长', '增加值累计增长', '出口交货值当月值', '同比增长', '出口交货值累计值', '累计增长']
]
columns
[['企业数量', '亏损企业数', '亏损总额', '亏损总额累计增长', '存货', '存货累计增长', '产成品', '产成品累计增长'],
['流动资产合计',
'流动资产合计累计增长',
'应收帐款',
'应收帐款累计增长',
'资产总计',
'资产总计累计增长',
'负债合计',
'负债合计累计增长'],
['主营业务收入',
'主营业务收入累计增长',
'利润总额',
'利润总额累计增长',
'主营业务税金及附加',
'主营业务税金及附加累计增长',
'应交增值税',
'应交增值税累计增长'],
['主营业务成本',
'主营业务成本累计增长',
'销售费用',
'销售费用累计增长',
'管理费用',
'管理费用累计增长',
'财务费用',
'财务费用累计增长'],
['增加值同比增长', '增加值累计增长', '出口交货值当月值', '同比增长', '出口交货值累计值', '累计增长']]
columns[0]
['企业数量', '亏损企业数', '亏损总额', '亏损总额累计增长', '存货', '存货累计增长', '产成品', '产成品累计增长']
columns[1]
['流动资产合计',
'流动资产合计累计增长',
'应收帐款',
'应收帐款累计增长',
'资产总计',
'资产总计累计增长',
'负债合计',
'负债合计累计增长']
html_tables[0].columns=columns[0]
html_tables[0].head()
企业数量 | 亏损企业数 | 亏损总额 | 累计增长 | 存货 | 累计增长 | 产成品 | 累计增长 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202203 | 4546 | 1498 | 180.1 | 5.6 | 1244.5 | 4.0 | 617.2 | 12.9 |
202202 | 4539 | 1395 | 116.9 | 3.7 | 1197.8 | 0.1 | 574.1 | 3.3 |
202112 | 4343 | 970 | 560.9 | -8.3 | 1242.4 | 5.0 | 603.5 | 10.4 |
202111 | 4343 | 1024 | 440.1 | -21.5 | 1350.0 | 8.5 | 680.9 | 15.1 |
202110 | 4334 | 1083 | 382.8 | -27.9 | 1300.6 | 3.9 | 627.9 | 5.9 |
# 数据表名以各参数名为表名
hyParaNames
['经济指标', '资产负债', '收入利润', '成本费用', '产值指标']
# 经济指标存入数据库
# 获取数据表名
tableName = hyParaNames[0]
# 更换表中列名
html_tables[0].columns=columns[0]
# 存入数据库
html_tables[0].to_sql(name=tableName, con=connection, if_exists='replace', index=True)
# 资产负债 情况存入数据库
tableName = hyParaNames[1]
html_tables[1].columns=columns[1]
html_tables[1].to_sql(name=tableName, con=connection, if_exists='replace', index=True)
html_tables[2]
主营业务收入 | 累计增长 | 利润总额 | 累计增长 | 主营业务税金及附加 | 累计增长 | 应交增值税 | 累计增长 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202203 | -- | -- | 2357.00 | 189 | -- | -- | -- | -- |
202202 | -- | -- | 1484.80 | 155.3 | -- | -- | -- | -- |
202112 | -- | -- | 7023.10 | 212.7 | -- | -- | -- | -- |
202111 | -- | -- | 6473.60 | 222.6 | -- | -- | -- | -- |
202110 | -- | -- | 5435.70 | 210.2 | -- | -- | -- | -- |
... | ... | ... | ... | ... | ... | ... | ... | ... |
201206 | 16438.57 | 17.55 | 1898.48 | -2.74 | 238.08 | 0.63 | 1078.46 | 4.42 |
201205 | 13813.53 | 19.93 | 1613.58 | 1.69 | 202.93 | 5.77 | 934.56 | 8.03 |
201204 | 10716.44 | 20.24 | 1262.86 | 3.75 | 154.64 | 8.34 | 733.86 | 9.54 |
201203 | 7821.97 | 22.82 | 921.23 | 5.88 | 111.31 | 7.22 | 554.7 | 12.06 |
201202 | 4767 | 23.02 | 574.05 | 11.48 | 68.33 | 11.56 | 343.18 | 19.48 |
112 rows × 8 columns
# 收入利润 情况存入数据库
tableName = hyParaNames[2]
html_tables[2].columns=columns[2]
html_tables[2].to_sql(name=tableName, con=connection, if_exists='replace', index=True)
#成本费用 情况存入数据库
tableName = hyParaNames[3]
html_tables[3].columns=columns[3]
html_tables[3].to_sql(name=tableName, con=connection, if_exists='replace', index=True)
#产值指标 情况存入数据库
tableName = hyParaNames[4]
html_tables[4].columns=columns[4]
html_tables[4].to_sql(name=tableName, con=connection, if_exists='replace', index=True)
import pandas as pd
from sqlalchemy import create_engine
from sqlalchemy_utils import database_exists, create_database
# 创建连接
dbName = 'hsjskcxydb'
connection = create_engine(f'mysql+pymysql://root:[email protected]:3306/{dbName}',encoding='gb2312')
if not database_exists(connection.url):
print(f"数据库{dbNamee}不存在!")
# 读取表中所有列数据sql语句
sqlStr = "SELECT * FROM 经济指标"
# 把sqlStr查询结果读取为数据框
dfAll = pd.read_sql(sqlStr,connection,index_col='类别年份')
dfAll.head()
企业数量 | 亏损企业数 | 亏损总额 | 亏损总额累计增长 | 存货 | 存货累计增长 | 产成品 | 产成品累计增长 | |
---|---|---|---|---|---|---|---|---|
类别年份 | ||||||||
202203 | 1462 | 622 | 16.5 | -60.9 | 388.9 | 10.9 | 222.8 | 14.4 |
202202 | 1459 | 588 | 12.3 | -52.9 | 383.1 | 11.1 | 212.9 | 12.6 |
202112 | 1320 | 254 | 116.1 | 35.3 | 332.1 | 8.7 | 189.5 | 9.3 |
202111 | 1320 | 251 | 110.2 | 105.2 | 338.3 | 14.1 | 194.5 | 13.0 |
202110 | 1315 | 236 | 95.8 | 105.1 | 332.3 | 15.5 | 188.1 | 15.3 |
# 读取表中["企业数量","亏损企业数","亏损总额"]列数据SQL语句
sqlStr = "SELECT 类别年份,企业数量,亏损企业数,亏损总额 FROM 经济指标"
# 把sqlStr查询结果读取为数据框
dfSelect = pd.read_sql(sqlStr,connection,index_col='类别年份')
dfSelect.head()
企业数量 | 亏损企业数 | 亏损总额 | |
---|---|---|---|
类别年份 | |||
202203 | 1462 | 622 | 16.5 |
202202 | 1459 | 588 | 12.3 |
202112 | 1320 | 254 | 116.1 |
202111 | 1320 | 251 | 110.2 |
202110 | 1315 | 236 | 95.8 |
数据采集并存储为excel和mysql数据部分代码汇总如下。
各数据查看及可视化就不再累述。
# 导入库
import requests
from lxml import etree
import pandas as pd
import csv
import os
import pinyin
from sqlalchemy import create_engine
from sqlalchemy_utils import database_exists, create_database
# 设置请求头
headers = {
'user-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
'Host':'s.askci.com'
}
# 各参数名称
hyParaNames = ["经济指标","资产负债","收入利润","成本费用","产值指标"]
# 各参数表头
columns = [['企业数量', '亏损企业数', '亏损总额', '亏损总额累计增长', '存货', '存货累计增长', '产成品', '产成品累计增长'],
['流动资产合计', '流动资产合计累计增长', '应收帐款', '应收帐款累计增长', '资产总计', '资产总计累计增长', '负债合计', '负债合计累计增长'],
['主营业务收入', '主营业务收入累计增长', '利润总额', '利润总额累计增长', '主营业务税金及附加', '主营业务税金及附加累计增长', '应交增值税', '应交增值税累计增长'],
['主营业务成本', '主营业务成本累计增长', '销售费用', '销售费用累计增长', '管理费用', '管理费用累计增长', '财务费用', '财务费用累计增长'],
['增加值同比增长', '增加值累计增长', '出口交货值当月值', '同比增长', '出口交货值累计值', '累计增长']
]
for i in range(0,5):
# 设置请求url
url = f'https://s.askci.com/data/economy/0000{i+1}/'
# 获得响应
r = requests.get(url, headers = headers)
# 编码转换,避免乱码
r.encoding = r.apparent_encoding
# 采用etree.HTML解析
html = etree.HTML(r.text)
# 采用xpath获得行业名
hyName = html.xpath('/html/body/div[4]/div[2]/div[1]/a[3]/text()')[0]
# 获取表格数据
html_tables = pd.read_html(r.content,header=0,index_col=0)
# 将数据存入excel表
excelFileName = hyName+".xlsx"
sheet_names = hyParaNames
for k in range(5):
if not os.path.exists(excelFileName):
html_tables[k].to_excel(excelFileName,sheet_name=sheet_names[k], index=True)
else:
with pd.ExcelWriter(excelFileName, engine='openpyxl', mode='a',if_sheet_exists='replace') as writer:
html_tables[k].to_excel(writer,sheet_name=sheet_names[k], index=True)
# 将数据出如MySQL
# 创建数据库
dbName = [''+pinyin.get(x)[0].upper() for x in hyName]
dbName = "".join(dbName)+'db'
connection = create_engine(f'mysql+pymysql://root:[email protected]:3306/{dbName}',encoding='gb2312')
if not database_exists(connection.url):
create_database(connection.url,encoding='gb2312')
print(f"数据库{dbName}已准备好!" if database_exists(connection.url) else f"数据库{dbName}准备失败!")
# 数据存入MySQL
for m in range(len(hyParaNames)):
tableName = hyParaNames[m]
html_tables[m].columns=columns[m]
html_tables[m].to_sql(name=tableName, con=connection, if_exists='replace', index=True)
print(f"数据库{dbName}已数据已存储!")
数据库MTKCHXXYdb已准备好!
数据库MTKCHXXYdb已数据已存储!
数据库SYHTRQKCYdb已准备好!
数据库SYHTRQKCYdb已数据已存储!
数据库HSJSKCXYdb已准备好!
数据库HSJSKCXYdb已数据已存储!
数据库YSJSKCXYdb已准备好!
数据库YSJSKCXYdb已数据已存储!
数据库FJSKCXYdb已准备好!
数据库FJSKCXYdb已数据已存储!