Python爬虫Ajax系列——批量下载巨潮资讯网上市公司年报

公众号:Python for Finance

巨潮资讯网是中国证监会指定的上市公司信息披露网站,平台提供上市公司公告、公司资讯、公司互动、股东大会网络投票等内容功能,一站式服务资本市场投资者。在本文,我将展示如何批量下载上市公司年报,如果大家想下载其他类型报告也是一样的方法。

巨潮资讯网沪深公告网址:

http://www.cninfo.com.cn/new/commonUrl/pageOfSearch?url=disclosure/list/search

我们在右方的“公告速查”的“分类”中勾选“年报”,即可筛选出上市公司年报。那我们的目标是下载这些pdf,如何实现呢?

image

基本思路:

1、获取巨潮资讯网上市公司年报pdf的网址及公司公告标题、公司代码、公司名称等信息

2、通过访问pdf地址进行下载,按照公司公告标题、公司代码、公司名称进行命名

一、观察网页

1.判断网页是静态网页还是动态网页

(1)我们翻页后,发现网址栏的网址没有发生变化,说明这是ajax动态网页。

image

(2)我们右键“查看源代码”,搜索第一个公司名称“紫晶存储”,发现公司名字不在源代码里,说明我们想要的信息没有存储在我们当前打开的网页上,所以我们需要找到我们需要的数据存在哪个网页。

image

2.找到数据的真实的网页地址

(1)谷歌浏览器右键“检查”,点击“Network”,在出现的界面中选择“Fetch/XHR”按钮,刷新页面。

(2)点击名为“query”的链接

(3)点击“Preview”或者“Response”,可以发现我们需要的数据在这里。

image

二、请求数据

requests-post请求

我们查看“Headers”发现请求方法为post请求,我们拉到最下面,找到“Form Data”,即为post请求的数据参数。

image

我们请求数据的时候,有时候需要携带请求头,请求头信息如下:

image

代码如下:

#定义下载单页年报pdf的函数
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)

三、存储数据

json数据解析

由于网页返回的是json格式数据,获取我们需要的公司名称、公司代码、公司公告,我们通过字典访问即可。其中公司公告pdf的网页链接如何拿到?我们点击第一条公司年报观察,发现其网址后缀存储在adjunctUrl里,我们可以提取此后缀,再将前缀加上,就可以拿到年报pdf的完整链接。

拿到pdf链接后,我们如何下载pdf呢,需要用response.content来写入文件信息。在此我们补充一个知识点:

response.text 与 response.content的区别

response.text 与 response.content 都是来获取response中的数据信息,那么response.text 和 response.content 到底有哪些差别?

(1)返回的数据类型

response.text 返回的是一个 unicode 型的文本数据;

response.content 返回的是 bytes 型的二进制数据;

也就是说如果想取文本数据可以通过response.text;如果想取文件等,则可以通过 response.content。

(2)数据编码

response.content 返回的是二进制响应内容,可通过response.content.decode()进行解码。

response.text 则是默认”iso-8859-1”编码,服务器不指定的话是根据网页的响应来猜测编码。

代码如下:

result=r.json()['announcements']#获取单页年报的数据,数据格式为json。获取json中的年报信息。
#2.对数据信息进行提取
    for i in result:
        if re.search('摘要',i['announcementTitle']):#避免下载一些年报摘要等不需要的文件
            pass
        else:
            title=i['announcementTitle']
            secName=i['secName']
            secName=secName.replace('*','')#下载前要将文件名中带*号的去掉,因为文件命名规则不能带*号,否则程序会中断
            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}下载完毕')#设置进度条

四、通过循环,批量下载公司年报

寻找翻页规律。

我们分别点击第1页、第2页、第3页,发现不同页码的动态网页一致,只是post参数不一致,第1页的“pageNum”是1,第2页的“pageNum”是2,第3页的“pageNum”是3,以此类推。

image
image

因此我们嵌套循环即可,代码如下:

for pageNum in range(1,3):#为演示,下载1-2页的年报
    get_and_download_pdf_flie(pageNum) #执行以上定义的下载单页年报pdf的函数

全套代码如下:


import requests
import re
#定义爬取函数
#1、对单个页面进行请求,返回数据信息——以第一页为例
saving_path='C:\\Users\\chenwei\\Desktop\\巨潮资讯年报'#设置存储年报的文件夹,把文件夹改成你自己的
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']#获取单页年报的数据,数据格式为json。获取json中的年报信息。
#2.对数据信息进行提取
    for i in result:
        if re.search('摘要',i['announcementTitle']):#避免下载一些年报摘要等不需要的文件
            pass
        else:
            title=i['announcementTitle']
            secName=i['secName']
            secName=secName.replace('*','')#下载前要将文件名中带*号的去掉,因为文件命名规则不能带*号,否则程序会中断
            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}下载完毕')#设置进度条
#3.设置循环,下载多页的年报
for pageNum in range(1,3):#为演示,下载1-2页的年报
    get_and_download_pdf_flie(pageNum)

代码效果:

进度条效果(可不设置)

image

文件下载效果:

image

以上就是今天的分享,每天进步一点点。

©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容