为减少重复性的下载动作,以爬取某网站相关数据/文件的项目为例进行代码实战的学习记录。本博客内容主要以学习交流为主,故在涉及到具体网站的地方将进行模糊处理。
项目:爬取基金/股票相关文件
1 项目简介
1.1 项目背景
在进行数据的收集时,往往要用到相关材料和文件。关于同一个关键词/主题下的相关公告文件有很多,通常要执行者手动下载。当所需文件数量过多或同一关键词下的涵盖的数据/文件过多时,手动下载会造成时间浪费,导致效率低下。使用爬虫代替重复下载的工作,能够有效减少所花费的时间,提高工作效率。
1.2 项目功能
对某金融网站的相关公告文件/数据信息进行定位获取,并批量下载至根目录。其中,能够执行以下功能:
(1)与执行者的互动,根据执行者的需求进行不同文件的爬取;
(2)交互内容可根据执行者的需求进行修改;
(3)可爬取多页内容。
1.3 项目目的
获取制定股票/基金的相关数据或文件,包含如下内容:年报、半年报、季报、业绩报告、权益分派、中介报告、公司债、股权变动等。
2 代码思路
2.1 功能思路
由于基金/股票类金融网站多为动态网站,因此本项目的代码功能思路主要围绕动态爬取为主。按照我们平时手动搜索文件并下载的过程,代码的功能思路可分为三个思路:①根据输入的搜索关键词得到一个反馈结果;②在得到的反馈结果中按需求进行文件或数据的筛选(分类选取);③对所选内容进行批量获取并下载,保存到本地。
2.2 执行思路
根据上述功能思路,可将三个思路分别定义三个函数,最终通过调用函数,实现功能的整合,从而达到项目目的。
2.3 用到的库与方法
主要用到的库:requests
主要用到的一些方法:json()、append()
3 代码分解
3.1 获取关键字并向网页发出请求
先打开开发者工具监控,手动在搜索引擎输入股票或基金关键字,这里以黄金为例。
图1 关键词搜索目录内容
在开发者工具中可看到动态生成的文件(以qu开头)的内容:
可知在向网页发出请求时,设置keyWord参数可搜索不同的股票和基金,因此将该参数作为交互参数。通过查阅开发者工具的请求头可知此处为post请求。为了增加代码便捷性和可观性,美化一下input函数中的提示词。
keywords = input('请输入关键词:')
params = {
'keyWord': keywords,
'maxNum': 10
}
res = requests.post('此处为网站的url', params=params)
根据图1可知,搜索包含了A股、港股等内容,因此这里可以根据需求选择是否设立交互参数。当输入关键字后,执行者看到目录内容,会选择其中一只股,为了模拟这个操作,在输入关键字后,需要根据选择内容(A股、港股,或者不设置),进行列表,供执行者选择。因此需要先设置一个空列表,再在上述向网页发送请求的结果中进行局部遍历,在此过程中按需求进行选择。
#设置有一个空列表
list1 = []
#遍历关键词目录,
for i in res.json():
if i['category'] == 'A股':#如果不需要筛选特定股,可省略这一行
list1.append(i)
#创建一个空字典,拿来存放上述信息
result_dict = {}
#设置一个计数器,方便后续输入
a = 1
#遍历列表,获取相关信息并提取,记录到字典中
for m in list1:
result_dict[str(a)] = m
print("【序号-{}】 名称 - {} 代码 - {} ".format(a, m['zwjc'], m['code']))
a += 1
通过以上操作,除了可以通过关键字搜索获得对应股票的代码和名称等内容,还能为执行者提供可视化的交互式输入体验。
3.2 按需求进行分类筛选
在选择了某一股票/基金后,按照需求进行分类选择。为了实现这一功能,需要去开发者工具中查看不同的分类所需要的参数,再将对应参数按编号设定好,从而使爬虫使用者可以通过编号快速获取分类文件/数据。
首先去开发者工具中查看:在手动点击相关分类以及日期选择后,出现的参数变动内容。(本代码以A股某东黄金为例)
此时的开发者工具中,可看到对应的请求参数为:
据此可设置相关参数选项:
category_dict = {
"1": "category_ndbg_szsh;",
"2": "category_bndbg_szsh;",
"3": "category_gddh_szsh;",
"4": "category_zj_szsh;",
"5": "category_gqbd_szsh;",
}
numbers = input('请输入搜索类型序号:1、年报 2、半年报 3、股东大会 4、中介报告 5、股权变动:(输入序号,如:1)')
这里的分类选择可根据个人需求进行选择与改动,通过开发者工具可获取相关内容。
由于日期可以自由设定,因此设置相应交互参数:
start = input('请输入搜索范围起始时间(例如 2022-01-01):')
end = input('请输入搜索范围结束时间(例如 2022-03-31):')
在上述开发者工具的参数截图中,参数column和plate会根据所选股票的信息(深沪或其他)而不一样。
600开头的股票是上证A股,其中6006开头的股票是最早上市的股票,6016开头的股票为大盘蓝筹股;
000开头的股票是深证A股,001、002开头的股票也都属于深证A股,其中002开头的股票是深证A股中小企业股票;
通过查看其他股票可得出规律,使用分支语句进行编写:
if str(code)[0] == '6':
column = 'sse'
plate = 'sh'
else:
column = 'szse'
plate = 'sz'
至此,所有所需参数都获得了
page=1 #设置初始页码
pdf_list=[] #设置一个空列表存放信息
data = {
'stock': '{},{}'.format(code, orgid),#这一步的参数在3.1中可获取
'tabName': 'fulltext',
'pageSize': '30',
'pageNum': str(page_num),
'category': category,
'seDate': '{}~{}'.format(start, end),
'column': column,
'plate': plate,
'searchkey': '',
'secid': '',
'sortName': '',
'sortType': '',
'isHLtitle': ''
}
r = requests.post('此处是网站的url', data=data)
r_json = r.json() #动态网页请求获取
for i in r_json['announcements']:
pdf_list.append([i['announcementTitle'], i['adjunctUrl']]) #获取公告的题目和具体下载链接
3.3 批量获取并下载
这一部分的内容为文件处理部分的内容,直接上代码:
for m in pdf_list:
pdf_r = requests.get('此处输入网址的url' + m[1]) #通过拼接获取下载链接
file_path = m[0] + '.pdf' #通过拼接获取公告文件名字
#打开新的文件进行储存
with open(file_path, 'wb') as f:
f.write(pdf_r.content)
#为了更直观的看到结果所设置的打印函数输出
print('{}已下载完成!'.format(m[0]))
4 运行结果
4.1 交互过程
4.2 输出结果
5 完整代码
在完整代码中对针对交互可能性的部分内容进行了优化,完善了代码的交互性。
python-代码实战-项目:爬取股票/基金文件
6 总结
本次代码实战主要从功能方面对目标进行拆解,最后通过定义函数将操作进行结合,从而达到最终目的。关于动态网站的爬取还有很大的学习空间,还需要学习更多的知识。在学习爬虫的过程中,最重要的还是守住爬虫伦理道德的底线:爬取之前应该浏览爬虫协议,遵守相关约定。
一入爬虫深似海,在代码编写的过程中,也陆续发现了可以进行优化的地方。之后还将继续进行相关代码实战,也会继续优化写作框架。
欢迎留言交流!