公眾號(hào):Python for Finance
巨潮資訊網(wǎng)是中國(guó)證監(jiān)會(huì)指定的上市公司信息披露網(wǎng)站倘核,平臺(tái)提供上市公司公告、公司資訊即彪、公司互動(dòng)紧唱、股東大會(huì)網(wǎng)絡(luò)投票等內(nèi)容功能,一站式服務(wù)資本市場(chǎng)投資者。在本文隶校,我將展示如何批量下載上市公司年報(bào)漏益,如果大家想下載其他類型報(bào)告也是一樣的方法。
巨潮資訊網(wǎng)滬深公告網(wǎng)址:
http://www.cninfo.com.cn/new/commonUrl/pageOfSearch?url=disclosure/list/search
我們?cè)谟曳降摹肮嫠俨椤钡摹胺诸悺敝泄催x“年報(bào)”深胳,即可篩選出上市公司年報(bào)绰疤。那我們的目標(biāo)是下載這些pdf,如何實(shí)現(xiàn)呢稠屠?
基本思路:
1峦睡、獲取巨潮資訊網(wǎng)上市公司年報(bào)pdf的網(wǎng)址及公司公告標(biāo)題、公司代碼权埠、公司名稱等信息
2榨了、通過(guò)訪問(wèn)pdf地址進(jìn)行下載,按照公司公告標(biāo)題攘蔽、公司代碼龙屉、公司名稱進(jìn)行命名
一、觀察網(wǎng)頁(yè)
1.判斷網(wǎng)頁(yè)是靜態(tài)網(wǎng)頁(yè)還是動(dòng)態(tài)網(wǎng)頁(yè)
(1)我們翻頁(yè)后,發(fā)現(xiàn)網(wǎng)址欄的網(wǎng)址沒(méi)有發(fā)生變化转捕,說(shuō)明這是ajax動(dòng)態(tài)網(wǎng)頁(yè)作岖。
(2)我們右鍵“查看源代碼”,搜索第一個(gè)公司名稱“紫晶存儲(chǔ)”五芝,發(fā)現(xiàn)公司名字不在源代碼里痘儡,說(shuō)明我們想要的信息沒(méi)有存儲(chǔ)在我們當(dāng)前打開(kāi)的網(wǎng)頁(yè)上,所以我們需要找到我們需要的數(shù)據(jù)存在哪個(gè)網(wǎng)頁(yè)枢步。
2.找到數(shù)據(jù)的真實(shí)的網(wǎng)頁(yè)地址
(1)谷歌瀏覽器右鍵“檢查”沉删,點(diǎn)擊“Network”,在出現(xiàn)的界面中選擇“Fetch/XHR”按鈕醉途,刷新頁(yè)面矾瑰。
(2)點(diǎn)擊名為“query”的鏈接
(3)點(diǎn)擊“Preview”或者“Response”,可以發(fā)現(xiàn)我們需要的數(shù)據(jù)在這里隘擎。
二殴穴、請(qǐng)求數(shù)據(jù)
requests-post請(qǐng)求
我們查看“Headers”發(fā)現(xiàn)請(qǐng)求方法為post請(qǐng)求,我們拉到最下面货葬,找到“Form Data”采幌,即為post請(qǐng)求的數(shù)據(jù)參數(shù)。
我們請(qǐng)求數(shù)據(jù)的時(shí)候宝惰,有時(shí)候需要攜帶請(qǐng)求頭植榕,請(qǐng)求頭信息如下:
代碼如下:
#定義下載單頁(yè)年報(bào)pdf的函數(shù)
def get_and_download_pdf_flie(pageNum):
url='http://www.cninfo.com.cn/new/hisAnnouncement/query'
pageNum=int(pageNum)
data={'pageNum':pageNum,
'pageSize':30,
'column':'szse',
'tabName':'fulltext',
'plate':'',
'stock':'',
'searchkey':'',
'secid':'',
'category':'category_ndbg_szsh',
'trade':'',
'seDate':'2021-03-26~2021-09-26',
'sortName':'',
'sortType':'',
'isHLtitle':'true'}
headers={'Accept':'*/*',
'Accept-Encoding':'gzip, deflate',
'Accept-Language':'zh-CN,zh;q=0.9',
'Connection':'keep-alive',
'Content-Length':'181',
'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
'Host':'www.cninfo.com.cn',
'Origin':'http://www.cninfo.com.cn',
'Referer':'http://www.cninfo.com.cn/new/commonUrl/pageOfSearch?url=disclosure/list/search',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36',
'X-Requested-With':'XMLHttpRequest'}
r=requests.post(url,data=data,headers=headers)
三、存儲(chǔ)數(shù)據(jù)
json數(shù)據(jù)解析
由于網(wǎng)頁(yè)返回的是json格式數(shù)據(jù)尼夺,獲取我們需要的公司名稱尊残、公司代碼、公司公告淤堵,我們通過(guò)字典訪問(wèn)即可寝衫。其中公司公告pdf的網(wǎng)頁(yè)鏈接如何拿到?我們點(diǎn)擊第一條公司年報(bào)觀察拐邪,發(fā)現(xiàn)其網(wǎng)址后綴存儲(chǔ)在adjunctUrl里慰毅,我們可以提取此后綴,再將前綴加上扎阶,就可以拿到年報(bào)pdf的完整鏈接汹胃。
拿到pdf鏈接后,我們?nèi)绾蜗螺dpdf呢东臀,需要用response.content來(lái)寫入文件信息着饥。在此我們補(bǔ)充一個(gè)知識(shí)點(diǎn):
response.text 與 response.content的區(qū)別
response.text 與 response.content 都是來(lái)獲取response中的數(shù)據(jù)信息,那么response.text 和 response.content 到底有哪些差別惰赋?
(1)返回的數(shù)據(jù)類型
response.text 返回的是一個(gè) unicode 型的文本數(shù)據(jù)宰掉;
response.content 返回的是 bytes 型的二進(jìn)制數(shù)據(jù);
也就是說(shuō)如果想取文本數(shù)據(jù)可以通過(guò)response.text;如果想取文件等轨奄,則可以通過(guò) response.content孟害。
(2)數(shù)據(jù)編碼
response.content 返回的是二進(jìn)制響應(yīng)內(nèi)容,可通過(guò)response.content.decode()進(jìn)行解碼挪拟。
response.text 則是默認(rèn)”iso-8859-1”編碼挨务,服務(wù)器不指定的話是根據(jù)網(wǎng)頁(yè)的響應(yīng)來(lái)猜測(cè)編碼。
代碼如下:
result=r.json()['announcements']#獲取單頁(yè)年報(bào)的數(shù)據(jù)舞丛,數(shù)據(jù)格式為json耘子。獲取json中的年報(bào)信息。
#2.對(duì)數(shù)據(jù)信息進(jìn)行提取
for i in result:
if re.search('摘要',i['announcementTitle']):#避免下載一些年報(bào)摘要等不需要的文件
pass
else:
title=i['announcementTitle']
secName=i['secName']
secName=secName.replace('*','')#下載前要將文件名中帶*號(hào)的去掉球切,因?yàn)槲募?guī)則不能帶*號(hào),否則程序會(huì)中斷
secCode=i['secCode']
adjunctUrl=i['adjunctUrl']
down_url='http://static.cninfo.com.cn/'+adjunctUrl
filename=f'{secCode}{secName}{title}.pdf'
filepath=saving_path+'\\'+filename
r=requests.get(down_url)
with open(filepath,'wb') as f:
f.write(r.content)
print(f'{secCode}{secName}{title}下載完畢')#設(shè)置進(jìn)度條
四绒障、通過(guò)循環(huán)吨凑,批量下載公司年報(bào)
尋找翻頁(yè)規(guī)律。
我們分別點(diǎn)擊第1頁(yè)户辱、第2頁(yè)鸵钝、第3頁(yè),發(fā)現(xiàn)不同頁(yè)碼的動(dòng)態(tài)網(wǎng)頁(yè)一致庐镐,只是post參數(shù)不一致恩商,第1頁(yè)的“pageNum”是1,第2頁(yè)的“pageNum”是2必逆,第3頁(yè)的“pageNum”是3怠堪,以此類推。
因此我們嵌套循環(huán)即可名眉,代碼如下:
for pageNum in range(1,3):#為演示粟矿,下載1-2頁(yè)的年報(bào)
get_and_download_pdf_flie(pageNum) #執(zhí)行以上定義的下載單頁(yè)年報(bào)pdf的函數(shù)
全套代碼如下:
import requests
import re
#定義爬取函數(shù)
#1、對(duì)單個(gè)頁(yè)面進(jìn)行請(qǐng)求损拢,返回?cái)?shù)據(jù)信息——以第一頁(yè)為例
saving_path='C:\\Users\\chenwei\\Desktop\\巨潮資訊年報(bào)'#設(shè)置存儲(chǔ)年報(bào)的文件夾陌粹,把文件夾改成你自己的
import requests
def get_and_download_pdf_flie(pageNum):
url='http://www.cninfo.com.cn/new/hisAnnouncement/query'
pageNum=int(pageNum)
data={'pageNum':pageNum,
'pageSize':30,
'column':'szse',
'tabName':'fulltext',
'plate':'',
'stock':'',
'searchkey':'',
'secid':'',
'category':'category_ndbg_szsh',
'trade':'',
'seDate':'2021-03-26~2021-09-26',
'sortName':'',
'sortType':'',
'isHLtitle':'true'}
headers={'Accept':'*/*',
'Accept-Encoding':'gzip, deflate',
'Accept-Language':'zh-CN,zh;q=0.9',
'Connection':'keep-alive',
'Content-Length':'181',
'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
'Host':'www.cninfo.com.cn',
'Origin':'http://www.cninfo.com.cn',
'Referer':'http://www.cninfo.com.cn/new/commonUrl/pageOfSearch?url=disclosure/list/search',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36',
'X-Requested-With':'XMLHttpRequest'}
r=requests.post(url,data=data,headers=headers)
result=r.json()['announcements']#獲取單頁(yè)年報(bào)的數(shù)據(jù),數(shù)據(jù)格式為json福压。獲取json中的年報(bào)信息掏秩。
#2.對(duì)數(shù)據(jù)信息進(jìn)行提取
for i in result:
if re.search('摘要',i['announcementTitle']):#避免下載一些年報(bào)摘要等不需要的文件
pass
else:
title=i['announcementTitle']
secName=i['secName']
secName=secName.replace('*','')#下載前要將文件名中帶*號(hào)的去掉,因?yàn)槲募?guī)則不能帶*號(hào)荆姆,否則程序會(huì)中斷
secCode=i['secCode']
adjunctUrl=i['adjunctUrl']
down_url='http://static.cninfo.com.cn/'+adjunctUrl
filename=f'{secCode}{secName}{title}.pdf'
filepath=saving_path+'\\'+filename
r=requests.get(down_url)
with open(filepath,'wb') as f:
f.write(r.content)
print(f'{secCode}{secName}{title}下載完畢')#設(shè)置進(jìn)度條
#3.設(shè)置循環(huán)蒙幻,下載多頁(yè)的年報(bào)
for pageNum in range(1,3):#為演示,下載1-2頁(yè)的年報(bào)
get_and_download_pdf_flie(pageNum)
代碼效果:
進(jìn)度條效果(可不設(shè)置)
文件下載效果:
以上就是今天的分享胞枕,每天進(jìn)步一點(diǎn)點(diǎn)杆煞。