温馨提示: 定期 清理浏览器缓存,可以获得最佳浏览体验。
New!
lianxh
命令发布了:
随时搜索推文、Stata 资源。安装命令如下:
. ssc install lianxh
详情参见帮助文件 (有惊喜):
. help lianxh
⛳ Stata 系列推文:
作者:秦利宾 (厦门大学)
邮箱:qlb150@63.com
编者按:关于「Python:爬取上市公司公告-Wind-CSMAR」这篇推文,经常会有人反映不能正常下载公告,这可能和一些不可控的因素有关。因此,作者重新写了一篇能够从「巨潮网」批量下载所有公告的推文,以供大家参考。不过,本推文相对比较基础,很多细节并没有考虑到,读者在使用过程中需要根据具体的需要和问题进行修改。
目录
以任意几个公告的 PDF 链接为例,我们可以发现区别仅仅在 finalpage 后面的部分,即日期和公告 ID。
打开「沪市公告」页面,通过右键检查,可以发现公告地址以 JSON 格式存储在 disclosure 文件下。
一个简单的思路,就是直接循环页码,来获取每页公告的地址。但是,当循环到 100 页时,我们会发现后面的页码禁止访问,且每次只能访问 3 年公告。此时,不妨换个思路,由于单个股票的公告页数几乎不可能超过 100 页,即
根据以上分析,我们要获取所有公告地址,大致需要以下三步:
关于股票代码,我们可以通过多种途径获取,比如 CSMAR 和 Wind 这类数据库,也可以直接从相关网站获取。在这里,本文以「巨潮网」为例。同样地,打开「沪市公告」页面,通过右键检查,可以发现股票代码以 JSON 格式存储在 szse_stock.json 文件下。
通过点击 Headers,可以发现该文件的链接如下:
将其复制粘贴到浏览器,可以发现股票代码如下:
接着,我们通过编写如下程序,获取 A 股股票信息:
#导入必要的包
import os #实现系统功能
import xlrd #读取excel
import xlwt #写入excel
import json #解析json
import requests #获取网页内容
import math #数学函数
import re #正则表达
from urllib.request import urlretrieve #下载网络文件到本地
#获取股票信息
url = "http://www.cninfo.com.cn/new/data/szse_stock.json"
ret = requests.get(url=url)
ret = ret.content
stock_list = json.loads(ret)["stockList"]
stock_list[:2]
[{'orgId': 'gssz0000001',
'category': 'A股',
'code': '000001',
'pinyin': 'payh',
'zwjc': '平安银行'},
{'orgId': 'gssz0000002',
'category': 'A股',
'code': '000002',
'pinyin': 'wka',
'zwjc': '万科A'}]
#只保留A股
stock_list_new = []
for stock in stock_list:
if stock["category"] == "A股":
stock_list_new.append(stock)
#添加column和plate信息,后续需要用到
i = 0
for stock in stock_list_new:
if stock["code"][0] == "0" or stock["code"][0] == "3":
stock_list_new[i]["column"] = "szse"
stock_list_new[i]["plate"] = "sz"
else:
stock_list_new[i]["column"] = "sse"
stock_list_new[i]["plate"] = "sh"
i = i + 1
stock_list_new[:2]
[{'orgId': 'gssz0000001',
'category': 'A股',
'code': '000001',
'pinyin': 'payh',
'zwjc': '平安银行',
'column': 'szse',
'plate': 'sz'},
{'orgId': 'gssz0000002',
'category': 'A股',
'code': '000002',
'pinyin': 'wka',
'zwjc': '万科A',
'column': 'szse',
'plate': 'sz'}]
以「平安银行」为例,右键检查可以发现,公告地址存储在 query 文件夹。
通过 Headers 和 Preview,我们可以发现,每页有 30 条公告,总共有 51 页,总记录数为
通过以上分析可知,循环的变量有两个,即股票代码和股票页数。股票代码在前一小节已经获取,接下来我们要获取每个股票总页数。
#获取股票公告页数
stock_list_new = stock_list_new[:10] #以前10个为例,直接删除这行
url = "http://www.cninfo.com.cn/new/hisAnnouncement/query"
i = 0
for stock in stock_list_new:
data = {
"stock": stock["code"]+","+stock["orgId"],
"tabName": "fulltext",
"pageSize": 30,
"pageNum": 1,
"column": stock["column"],
"plate": stock["plate"],
"isHLtitle": "true",
}
ret = requests.post(url=url, data=data)
if ret.status_code == 200:
ret = ret.content
ret = str(ret,encoding="utf-8")
total_ann = json.loads(ret)["totalAnnouncement"]
stock_list_new[i]["pages"] = math.ceil(total_ann/30)
print(f"成功获取第{i}个股票页数!")
i = i+1
else:
break
在以上步骤的基础上,我们就可以对股票代码和页数进行循环,以获所有公告地址。
#将stock_list信息写入excel
w = xlwt.Workbook()
ws = w.add_sheet("股票信息")
title_list = ["orgId","category","code","pinyin", \
"zwjc","pages","column","plate"]
j = 0
for title in title_list:
ws.write(0,j,title)
j = j+1
i = 1
for stock in stock_list_new[:10]:
content_list = [stock["orgId"],stock["category"], \
stock["code"],stock["pinyin"], \
stock["zwjc"],stock["pages"], \
stock["column"],stock["plate"]]
j = 0
for content in content_list:
ws.write(i,j,content)
j = j+1
i = i+1
w.save("股票信息.xls")
#读入excel
w = xlrd.open_workbook("股票信息.xls")
ws = w.sheet_by_name("股票信息")
nor = ws.nrows
nol = ws.ncols
stock_list = []
for i in range(1, nor):
dict = {}
for j in range(nol):
title = ws.cell_value(0, j)
value = ws.cell_value(i, j)
dict[title] = value
stock_list.append(dict)
#获取公告地址
for stock in stock_list:
url = "http://www.cninfo.com.cn/new/hisAnnouncement/query"
name = stock["code"]
w = xlwt.Workbook()
ws = w.add_sheet(name)
title_list = ["secCode","secName","announcementTitle", \
"adjunctUrl","columnId"]
j = 0
for title in title_list:
ws.write(0,j,title)
j = j+1
i = 1
for page in range(1,int(stock["pages"])+1):
data = {
"stock": stock["code"]+","+stock["orgId"],
"tabName": "fulltext",
"pageSize": 30,
"pageNum": page,
"column": stock["column"],
"plate": stock["plate"],
"isHLtitle": "true",
}
ret = requests.post(url, data=data)
ret = ret.content
ret = str(ret,encoding="utf-8")
ann_list = json.loads(ret)["announcements"]
for ann in ann_list:
content_list = [ann["secCode"],ann["secName"], \
ann["announcementTitle"], \
ann["adjunctUrl"],ann["columnId"]]
j = 0
for content in content_list:
ws.write(i,j,content)
j = j+1
i = i+1
print(f"成功写入{name}!")
w.save(f"{name}.xls")
下图展示了部分结果。其中,每个股票的所有公告单独存在一个 Excel 文件夹下。股票公告地址则存放在 adjunctUrl 变量下。由于这里是所有公告,若是要细分公告类型,可依据 announcementTitle 和 columnld 变量划分。
需要注意的是,理论上单个股票只能获取前 100 页公告地址。若想避免这个问题,有以下两个方法:
#判断股票页数是否超过 100
i = 0
for stock in stock_list:
if stock["pages"] >= 100:
print(i, stock["code"], stock["pages"])
i = i + 1
最后,我们就可以根据公告地址下载所有公告了。需要注意的是,在文件命名过程中不要有特殊字符,否则会报错。并且,有些公告链接是 html 格式的,因此可以根据链接直接将网页内容保存,这里不再过多赘述。
if not os.path.exists("PDF"): #不存在,创建pdf子文件夹
os.mkdir("PDF")
files =[f for f in os.listdir() if re.match("\d{6}",f)]
for file in files:
w = xlrd.open_workbook(file)
ws = w.sheet_by_name(file.replace(".xls", ""))
nor = ws.nrows
nol = ws.ncols
for i in range(1, nor):
url = "http://static.cninfo.com.cn/"+ ws.cell_value(i, 3)
print(url)
name = ws.cell_value(i, 2) + ".pdf"
urlretrieve(url, filename = "./PDF/" + name)
print(f"成功下载{name}!")
同时,本文附上 Stata 数据整理代码,之后可以用 copy
命令批量下载公告。
cd D:\A股公告
cap fs *.xls
foreach xls in `r(files)'{
if "`xls'" != "股票信息.xls"{
import excel using `xls', firstrow clear
local name = subinstr("`xls'", ".xls", "",.)
save `name'.dta, replace
}
}
cap fs *.dta
use 000001.dta, clear
foreach dta in `r(files)'{
if "`dta'" != "000001.dta"{
append using `dta', force
}
}
save A股公告整理.dta, replace
cap fs *.dta
foreach dta in `r(files)'{
if "`dta'" != "a股公告整理.dta"{
erase `dta'
}
}
cap mkdir "./PDF"
use A股公告整理.dta, clear
replace adjunctUrl = "http://static.cninfo.com.cn/" + adjunctUrl
replace announcementTitle = announcementTitle + ".pdf"
cap dis _N
forvalues i = 1(1)`r(N)'{
local u1 = adjunctUrl[`i']
local u2 = announcementTitle[`i']
copy "`u1'" "./PDF/`u2'", replace
}
Note:产生如下推文列表的 Stata 命令为:
lianxh lianxh 公告 爬虫 文本, m
安装最新版lianxh
命令:
ssc install lianxh, replace
免费公开课
最新课程-直播课
专题 | 嘉宾 | 直播/回看视频 |
---|---|---|
⭐ 最新专题 | 文本分析、机器学习、效率专题、生存分析等 | |
研究设计 | 连玉君 | 我的特斯拉-实证研究设计,-幻灯片- |
面板模型 | 连玉君 | 动态面板模型,-幻灯片- |
面板模型 | 连玉君 | 直击面板数据模型 [免费公开课,2小时] |
⛳ 课程主页
⛳ 课程主页
关于我们
课程, 直播, 视频, 客服, 模型设定, 研究设计, stata, plus, 绘图, 编程, 面板, 论文重现, 可视化, RDD, DID, PSM, 合成控制法
等
连享会小程序:扫一扫,看推文,看视频……
扫码加入连享会微信群,提问交流更方便
✏ 连享会-常见问题解答:
✨ https://gitee.com/lianxh/Course/wikis
New!
lianxh
命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh