当前位置:   article > 正文

Python数据分析之证券之星沪深A股基本信息爬取与分析_如何在批量a股中提取沪深a股公司

如何在批量a股中提取沪深a股公司

Python数据分析之证券之星沪深A股基本信息爬取与分析

上周爬取了证券之星上沪深A股的信息,我对股票完全是小白,对流通市值这些完全不了解,是上网先了解了一下,老实说虽然有了基本概念,但在数据分析时还是一头雾水,所以今天只说一下我在爬取和分析时遇到的问题(不涉及股票方面知识,只是分析数据只是分析数据只是分析数据),希望能对大家有帮助,也希望得到大家的意见!

爬取数据

获取网页内容

爬取方面依旧是我常用的结构,使用的pyquery,因为要爬取的内容直接就在html中,所以我只加了一个User-Agent的头。定义多个具有不同功能的函数,在这里需要注意一点,证券之星上是gbk编码,所以获取网页内容是需要添加encoding="gbk"

def get_page(url):
    try:
        doc = pq(url, headers=headers, encoding="gbk")
        # print(doc)
        return doc
    except:
        pass
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

通过在console中输入document.charset可查看网页的编码格式

解析网页内容

爬取过程总是有漏爬一页或两页数据的,找了好几次也没发现问题,所以希望知道的各位也能提点一下。因为网页打开总是很慢,有时候响应时间太长就自动断开,就加了try…except。

def parse_page(doc):
    try:
        tr_list = doc(".con #datalist").find("tr")
        # print(tr_list)
        for item in tr_list.items():
            try:
                coding = item(".select").text()
                name = item(".align_center").text().strip("0123456789")
                other_info = item(".align_right").text().split()
                nmc = other_info[0]
                mc = other_info[1]
                nc = other_info[2]
                cs = other_info[-1]
                yield {
                    "代码": coding,
                    "简称": name,
                    "流通市值(万元)": nmc,
                    "总市值(万元)": mc,
                    "流通股本(万元)": nc,
                    "总股本(万元)": cs
                }
            except:
                print("\033[1;30;47m此数据爬取中出现错误!\033[0m")
                break
        else:
            print("此页爬取完毕")
    except Exception as e:
        print("\033[1;30;41m错误为:\033[0m" + repr(e))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

接下来就是翻页代码了,其实大同小异,没什么问题。

def next_page():
    for p in range(1, 126):
        print("第%d页开始爬取" % p)
        url_page = "https://quote.stockstar.com/stock/ranklist_a_1_0_" + str(p) + ".html"
        doc = get_page(url_page)
        for item in parse_page(doc):
            print(item)
            write_to_csv(item)
        else:
            print("%d页爬取完毕" % p)
        time.sleep(2)
    else:
        print("所有页面爬取完毕")


def write_to_csv(item):
    writer.writerow([item["代码"], item["简称"], item["流通市值(万元)"], item["总市值(万元)"], item["流通股本(万元)"], item["总股本(万元)"]])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

注意一下,因为获取的网页是gbk编码,所以在保存文件时要注意文件也是gbk编码。


if __name__ == "__main__":
    # with open("证券之星沪深A股信息.csv", "w", encoding="gbk") as f:
    #     writer = csv.writer(f)
    #     writer.writerow(["代码", "简称", "流通市值(万元)", "总市值(万元)", "流通股本(万元)", "总股本(万元)"])

    file = open("证券之星沪深A股信息.csv", "a", encoding="gbk")
    writer = csv.writer(file)
    next_page()
    file.close()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

数据分析

获取完数据就开始对数据的分析了,通过网上搜索,我新建的一列股价是通过总市值/总股本计算的。

忘记说了,读取文件时也要加上encoding=gbk(原因不再说), 同时也遇到另一个问题,对各公司的代码都是00000X,所以在导入时pandas自动把前面的0都省略了,这时候在读取时再添加converters={"代码": str},代码如下。

data = pd.read_csv("证券之星沪深A股信息.csv", encoding="gbk", converters={"代码": str})
  • 1

在检查数据有无重复值data[""].duplicated().value_counts()后,就开始分析了:在这里代码和公司名称没有做任何分析(没办法,都是独立值,也不存在分类什么的),所以重点就是对五个数值型字段的分析(总市值(万元)、总股本(万元)、流通市值(万元)、流通股本(万元)、股价(元)

首先,我分别对每个数值型字段(以下皆简称为字段)做降序排序后,对排行前20做了条形图(不要问我为什么,在一头雾水的情况下,我把我能想到的都画出来了><)

mp.subplot(331)
mp.bar(data["简称"].head(20), data["股价(元)"].head(20))         # 画股价排行前20柱形图
mp.xticks(range(20), data["简称"].head(20), rotation=90)
mp.title("股价(元)排行前20")
# mp.show()

mp.subplot(332)
df1 = data[["简称", "流通市值(万元)"]].copy()
df1.sort_values("流通市值(万元)", ascending=False, inplace=True)
df1["流通市值(万元)"].head(20).plot(kind="bar", color="orangered")           # 画流通市值排行前20条形图
# mp.bar(data["简称"].head(20), data["流通市值(万元)"].head(20), color="orangered")
mp.xticks(range(20), data["简称"].head(20), rotation=90)
mp.title("流通市值(万元)排行前20")


mp.subplot(333)
df2 = data[["简称", "总市值(万元)"]].copy()
df2.sort_values("总市值(万元)", ascending=False, inplace=True)
df2["总市值(万元)"].head(20).plot(kind="bar")
mp.xticks(range(20), df2["简称"].head(20))
mp.title("总市值(万元)排行前20")


mp.subplot(334)
df3 = data[["简称", "流通股本(万元)"]].copy()
df3.sort_values("流通股本(万元)", ascending=False, inplace=True)
df3["流通股本(万元)"].head(20).plot(kind="bar")
mp.xticks(range(20), df3["简称"].head(20))
mp.title("流通股本(万元)排行前20")


mp.subplot(335)
df4 = data[["简称", "总股本(万元)"]].copy()
df4.sort_values("总股本(万元)", ascending=False, inplace=True)
df4["总股本(万元)"].head(20).plot(kind="bar")
mp.xticks(range(20), df4["简称"].head(20))
mp.title("总股本(万元)排行前20")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

然后是将前四个单位一样的字段拿出来做了箱图,股价(元)单独做了箱图。

ax6 = mp.subplot(347)
df5 = data[["流通市值(万元)", "总市值(万元)", "流通股本(万元)", "总股本(万元)", "股价(元)"]].copy()
df5_a, df5_b, df5_c, df5_d, df5_e = data["流通市值(万元)"], data["总市值(万元)"], data["流通股本(万元)"], data["总股本(万元)"], data["股价(元)"]
labels = ["流通市值(万元)", "总市值(万元)", "流通股本(万元)", "总股本(万元)"]
ax6.boxplot([df5_a, df5_b, df5_c, df5_d], showfliers=False)
# df4.plot.box()
ax6.set_title("五种值整体比较")
ax6.set_xticklabels(labels=labels, rotation=45)
ax6.grid(linestyle="--", alpha=0.8)

mp.subplot(348)
mp.boxplot(df5_e, showfliers=False)
mp.title("股价(元)箱体图")
mp.xticks([1], ["股价(元)"])
mp.grid(linestyle="--", alpha=0.5)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

再往后就是把刚才做的每个字段排名里前20的公司名称取出来合并并计数和降序排列,然后取前五名画了个饼图。

mp.subplot(325)
name_dic = {
    "股价(元)_简称": data["简称"].head(20),
    "流通市值(万元)_简称": df1["简称"].head(20),
    "总市值(万元)_简称": df2["简称"].head(20),
    "流通股本(万元)_简称": df3["简称"].head(20),
    "总股本(万元)_简称": df4["简称"].head(20)
}
name_top20 = pd.DataFrame(name_dic).apply(pd.value_counts)
name_top20["计数"] = name_top20.sum(axis=1)
name_top20.sort_values("计数", ascending=False, inplace=True)
# print(name_top20)
label = name_top20.head(5).index
mp.pie(name_top20["计数"].head(5), labels=label, autopct="%d%%")
mp.title("所有排行榜中出现公司名称排行前5")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

最后在对股价字段求对数后用直方图查看了其分布。

mp.subplot(326)
mp.hist(data["股价_log"], bins=20, density=True)
mp.plot([np.mean(data["股价_log"]), np.mean(data["股价_log"])], [0, 1], color="r")
log = np.mean(data["股价_log"]).round(1)
mp.xticks([-2, 0, 2, 4, 6], [-2, 0, 2, 4, 6])
# mp.annotate(log, xy=(0, np.mean(data["股价_log"])), xycoords="data", xytext=(4, 4), textcoords="axes points", arrowprops={"arrowstyle": "->"})
mp.text(log, 0, log, ha="center", va="center", bbox=dict(boxstyle="square,pad=0.3", fc="yellow", ec="blue", lw=1, alpha=0.5), wrap=True)
mp.title("股价对数值分布")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

附上图片

这些都做完,并没多少有价值信息,以下是我总结:

1、股价分布呈正态分布,并没有明显极端值,说明股票市场整体还是挺正常的;
2、从箱体图中能看出,不论是股本还是市值,亦或是股价,其总体还是值大的占得多;
3、从不同排行的对比中,各方面均排在前面的可以说还是咱们国家非常知名的。

最后,我分析了一下各字段间的相关关系。废话不多说,直接上代码和图。

fig_scatter = mp.figure("Scatter", figsize=(20, 10))            # 新建名为"Scatter"的figure

mp.subplot(241)
mp.scatter(data["流通股本(万元)"], data["总股本(万元)"])               # 画散点图
mp.title("流通股本 VS 总股本")
mp.xlabel("流通股本(万元)", fontsize=12)
mp.ylabel("总股本(万元)", fontsize=12)
mp.legend([data["流通股本(万元)"].corr(data["总股本(万元)"])])

mp.subplot(242)
mp.scatter(data["流通市值(万元)"], data["总市值(万元)"])
mp.title("流通市值 VS 总市值")
mp.xlabel("流通市值(万元)", fontsize=12)
mp.ylabel("总市值(万元)", fontsize=12)
mp.legend([data["流通市值(万元)"].corr(data["总市值(万元)"])])

mp.subplot(243)
mp.scatter(data["流通股本(万元)"], data["流通市值(万元)"])
mp.title("流通股本 VS 流通市值")
mp.xlabel("流通股本(万元)", fontsize=12)
mp.ylabel("流通市值(万元)", fontsize=12)
mp.legend([data["流通股本(万元)"].corr(data["流通市值(万元)"])])

mp.subplot(244)
mp.scatter(np.log(data["总股本(万元)"]), np.log(data["总市值(万元)"]))
mp.title("总股本 VS 总市值")
mp.xlabel("总股本(万元)", fontsize=12)
mp.ylabel("总市值(万元)", fontsize=12)
mp.legend([data["总股本(万元)"].corr(data["总市值(万元)"])])

mp.subplot(212)
corr1 = data["股价(元)"].corr(data["流通市值(万元)"]*10000)                          # 求相关系数
corr2 = data["股价(元)"].corr(data["总市值(万元)"]*10000)
corr3 = data["股价(元)"].corr(data["流通股本(万元)"]*10000)
corr4 = data["股价(元)"].corr(data["总股本(万元)"]*10000)
mp.scatter(data["股价(元)"], data["流通市值(万元)"]*10000, marker="o")               # 画散点图
mp.scatter(data["股价(元)"], data["总市值(万元)"]*10000, marker="s", alpha=0.2)
mp.scatter(data["股价(元)"],  data["流通股本(万元)"]*10000, marker="*", alpha=0.3)
mp.scatter(data["股价(元)"], data["总股本(万元)"]*10000, marker="+", alpha=0.5)

# mp.scatter(np.log(data["股价(元)"]), np.log(data["流通市值(万元)"]), marker="o")
# mp.scatter(np.log(data["股价(元)"]),  np.log(data["流通股本(万元)"]), marker="*", alpha=0.3)       # 求对数后的散点图
mp.title("股价(元)与其它属性比较")
mp.xlabel("股价(元)", fontsize=12)

# 散点图图例
mp.legend(["流通市值(元)"+str("%.2f" % corr1), "总市值(元)"+str("%.2f" % corr2), "流通股本(元)"+str("%.2f" % corr3), "总股本(元)"+str("%.2f" % corr4)])

# 调整子图间间距
mp.subplots_adjust(hspace=0.4, wspace=0.3)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

注:图4是求对数后的散点图,相关系数是求对数前算的

单说分析,我总觉得有些苍白无力:

1、拿流通股本和总股本、流通市值和总市值来讲,确实是正比关系,相关也在0.9,流通类的高确实会让总体也高;
2、对于流通股本和流通市值、总股本和总市值间,我觉得因为股价的存在,让他们都会在一定范围内有一些波动,但总体来说波动范围固定,所以其相关也不低;

以上就是对于证券之星获取到数据进行分析的全部内容,请大家当个娱乐就好,毕竟是金融+数据分析的双小白模式,在对各类数据进行分析这一方面我还需要很多练习。
同时,也希望能够和更多朋友探讨数据分析方面的相关知识!!谢谢大家观看!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/540438
推荐阅读
相关标签
  

闽ICP备14008679号