背景
爬虫小练习:从新浪财经网站上爬取上市公司海螺水泥的利润表数据,以 JSON 文件与 MySQL 作为两种持久化方式,并实现对公司近10年的营业总收入和营业总成本的数据可视化。eg: https://money.finance.sina.com.cn/corp/go.php/vFD_ProfitStatement/stockid/600585/ctrl/2013/displaytype/4.phtml
爬虫、保存为JSON、作图
为简化问题的难度,分步来处理:
数据抓取:爬取原始数据,保存为JSON;
数据预处理:将每一个元素的第一个值作为属性名,剩余元素作为值(便于下一步的JSON合并);
数据合并:将10年的数据合并为一个JSON。
数据可视化:使用
数据抓取
先爬取1年的数据。
import requests
from bs4 import BeautifulSoup
import json
# 发送HTTP请求获取网页内容
url = "https://money.finance.sina.com.cn/corp/go.php/vFD_ProfitStatement/stockid/600585/ctrl/2013/displaytype/4.phtml"
response = requests.get(url)
html_content = response.text
# 使用BeautifulSoup解析HTML内容
soup = BeautifulSoup(html_content, "html.parser")
# 找到表格元素
table = soup.find("table", {"id": "ProfitStatementNewTable0"})
# 提取表格数据
data = []
for row in table.find_all("tr"):
row_data = []
for cell in row.find_all("td"):
row_data.append(cell.text.strip())
# 过滤掉空行
if len(row_data) != 0:
data.append(row_data)
print(data)
# 将JSON数据保存到文件
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False)
10年的数据
import requests
from bs4 import BeautifulSoup
import json
# 近10年的利润表
years = 10
for i in range(years):
# 发送HTTP请求获取网页内容
url = "https://money.finance.sina.com.cn/corp/go.php/vFD_ProfitStatement/stockid/600585/ctrl/{}/displaytype/4.phtml".format(2013 + i)
response = requests.get(url)
html_content = response.text
# 使用BeautifulSoup解析HTML内容
soup = BeautifulSoup(html_content, "html.parser")
# 找到表格元素
table = soup.find("table", {"id": "ProfitStatementNewTable0"})
# 提取表格数据
data = []
for row in table.find_all("tr"):
row_data = []
for cell in row.find_all("td"):
row_data.append(cell.text.strip())
# 过滤掉空行与不完整的数据行
if len(row_data) > 1:
data.append(row_data)
print(data)
# 将JSON数据保存到文件
with open("data-{}.json".format(2013 + i), "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False)
数据预处理
将每一年的数据,转换为 JSON 格式的 key:value 形式,方便后续的合并操作。
import json
# 循环读取JSON文件
years = 10
for i in range(years):
with open('data-{}.json'.format(2013+i), 'r', encoding="utf-8") as f:
first_data = json.load(f)
result = {}
for item in first_data:
# 转换:将每一个元素的第一个值作为属性名,剩余元素作为值
result.update([(item[0], item[1:])])
# 将数据保存为JSON格式
json_data = json.dumps(result)
# 将JSON数据保存到文件
with open("data-transform-{}.json".format(2013 + i), "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False)
数据合并
将预处理后10年的数据合并为一个大的 JSON 文件。
import json
# 循环读取合并JSON文件
years = 10
merged_data = {}
transformed = {}
for i in range(years):
with open('data-transform-{}.json'.format(2013+i), 'r', encoding="utf-8") as f:
first_data = json.load(f)
transformed[2013 + i] = first_data
merged_data = {**merged_data, **transformed}
# 将合并后的JSON文件写入磁盘
with open('data-merged.json', 'w', encoding="utf-8") as f:
json.dump(merged_data, f, indent=4, ensure_ascii=False)
数据可视化
获取 JSON 数据中海螺水泥公司近10年的营业收入与营业成本数据,使用 matplotlib 绘制折线图与柱状图。如果需要做大屏可视化,可以使用AJ-Report开源数据可视化引擎入门实践。
import json
import matplotlib.pyplot as plt
with open('data-merged.json', 'r', encoding='utf-8') as f:
data = json.load(f)
x_data = []
y1_data = []
y2_data = []
for key,value in data.items():
# print(key)
print(float(data[key]['营业收入'][0].replace(',', '')))
print()
print(float(data[key]['营业成本'][0].replace(',', '')))
x_data.append(key)
y1_data.append(float(data[key]['营业收入'][0].replace(',', '')))
y2_data.append(float(data[key]['营业成本'][0].replace(',', '')))
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
plt.bar(x_data,y1_data, label='营业收入')
plt.plot(x_data,y2_data, label='营业成本', color='cyan', linestyle='--')
plt.title('海螺水泥近10年营业收入与营业成本')
plt.xlabel('年份')
plt.ylabel('营业收入与营业成本/万元')
# 关闭纵轴的科学计数法
axis_y = plt.gca()
axis_y.ticklabel_format(axis='y', style='plain')
# 图例
plt.legend()
# 显示图表
plt.show()
爬虫、写库
根据我们看到网页中的实际表格进行数据表设计。
数据爬取与数据存储
与上面爬虫的方式不同,这里使用 pandas 的 read_html 方法直接获取网页中的表格数据,这里注意目标表格的编号,需要到浏览器做检查与定位。
以单个链接为例,爬虫的结果为一个二维表格,通过转置、将第一行设置为 header 、替换列名(方便与数据表字段对应)、删除整行都为 NaN 的行、单个 NaN 替换为0等一系列的数据预处理操作后,直接连接 MySQL 数据库完成数据落库。