赞
踩
本文以sse、szse、bse
三家股票交易所的年报爬取为例,简单总结一个朋友使用过的爬虫技术。
本文只总结通用流程和避坑,不涉及爬虫代码
零、默认已经安装好python和相关库
import re # 正则表达式
import requests # 获取网页内容
import json # 解析json数据
from pathlib import Path # 处理文件路径
import datetime # (非必须)用于sse设置时间范围参数
import xlrd # (非必须) 解析xls文件
import openpyxl #(非必须)解析xlsx文件
一,F12 打开 开发者工具
到网络(network)
页,清除日志,点击和自己想要的数据相关的内容,比如说查询、下一页等。在日志里找到包含返回数据的请求,复制cookie、请求URL地址、get/post、Referer,User-Agent,这几个值比较重要。
二、构造url地址
一般是请求URL加上负载里的参数
&
分隔的参数,可以在负载
里点击查看源
,将其复制和URL拼接即可szse
的参数长这样{"seDate":["",""],"channelCode":["listedNotice_disc"],"bigCategoryId":["010301"],"pageSize":50,"pageNum":1}
则需要构造一个json,并进行编码
requestParam = {
'channelCode': ['listedNotice_disc'], # 不清楚这个参数是什么,应该是固定的
'pageNum': 1, # 其他交易所也有这个参数,且bse的页面从0开始,sse和szse从1开始
'pageSize': 50, # 根据需要修改,建议不改
'seDate': ["2024-03-04", "2024-04-14"], # 起止时间,格式yyyy-MM-dd,建议先到网站看看这个时间是否被网站允许
'searchKey': ["2024"], # 代码/简称/拼音/标题关键字
# 'bigIndustryCode': '', # 行业编号A、B、C、D、E
# 'plateCode': '', # 板块,主板11,中小板12,创业板16
'bigCategoryId': ['010305'] # 公告类别,选好类别后可以在负载里看到
}
data = bytes(json.dumps(requestParam), encoding='utf-8') # 编码
resp = requests.post(url, headers=headers, data=data) # 放到data里
构造成功后别急着拿去直接验证访问,网站会拒绝这个请求。我的理解是直接访问会缺少cookie等信息,所以还是得拿去代码中验证。
我们需要把这个URL改造成动态的,方法有很多,可以字符串拼接,也可以format快速拼接参数
url = 'page={page}'
for pageNo in range(10):
url = base.format(page=pageNo)
以上都是举例,目前这位朋友的方法还是从网页上分析请求的request和response,只有网页上合法的请求才有可能被代码顺利访问
三、根据构造的分页请求获取到response,分析数据发现三家交易所都是json格式的数据
四、可以先将json里的url地址存储用作后续低速爬取,也可以直接根据url地址进行请求,下载PDF
1.分离出带有关键字的PDF
以“数据资源”为例,使用PyPDF2提取PDF中的文本,如果其中包含关键字,则用shutil
库将PDF移动到目标文件夹下。不做赘述
2.分离出PDF中的表格中的连锁关键字
如果PDF的一个表格中,左边索引是数据资源,且右边值是数字,也就是该PDF既包含了某个关键字,也包含了这个关键字在表格中对应的值,那么就将PDF移动出来,或者获取其中的值皆可。
因为代码使用了dataframe格式,可能会遇到很多空值。解决方法是先获取每一行前两个非空值,如果第一个值包含关键字,且第二个值包含数字,则满足要求。
这个方法的bug是会将第二个值为0.00的PDF一并获取,这不满足需求,不过应该也能解决
# 需要安装额外的库
import pandas as pd
import pdfplumber # 可以用来提取PDF中的表格,比较准确和方便
各种坑其实仔细观察是可以发现的,但为了避免像我一样下载很多遍还发现文件少了抓耳挠腮,这里分享一些
1.bse
的年报如果有更正,是单独设置了一个值disclosurePostTitle
,所以如果更正前和更正后的文件都想下载的话,可以把原本文件名的disclosureTitle
和disclosurePostTitle
拼接一下,防止文件覆盖
2.szse
在url里有一个random参数,推测是一个小于1的随机值,所以这部分在每次请求的时候带上一个保留到小数点后16-17位的随机数即可
https://www.szse.cn/api/disc/announcement/annList?random=0.6983879461230162
3.sse
其实最麻烦,有些公司的年报不在年报类别里,所以我选择根据文件的名称来判断
我现在是在选择这些分类的前提下,只要文件名称出现在probableNameList
里面,且不含illegalNameList
里面任意一个词,则认为其是年报
probableNameList= ['2023年度报告','2023年年度报告','2023年_年度报告','2023年年报','2023 年年度报告',
'年报全文','2023年年年度报告','2023年报']
illegalNameList = ['摘要', '公告', '说明', '通知', '公示', '督导', '意见', '英文', '审计报告', '保荐书', '工作函',
'回复', '问询函', '纪要', '财务报表']
可以自己搜一搜这些名字就知道为什么要搞得这么复杂了,不过应该有更好的方式完成这个需求。
最后的效果是所有的公司至少获取了一份正确的文件,除了那种命名错误的(把年报命名成“年报摘要”,这种确实根据标题筛不出来)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。