Python爬虫尝试

您所在的位置:网站首页 爬虫抓取股票数据 Python爬虫尝试

Python爬虫尝试

2023-08-09 01:15| 来源: 网络整理| 查看: 265

Python爬虫 爬取财务报表(东方财富网) 爬取指定股票的财务报表需求确认思考实现获取所有报告的url地址根据获取的url地址下载文件或者输出正文内容

爬取指定股票的财务报表 需求确认

最经接到一个需求,要爬取两支股票公示的财务报表,虽然爬到的内容作用不打,但是这开发的过程的确是挺有学习意义的。 那么在爬取数据之前呢,老生常谈的一个问题就是,先 审查 一下我们要爬取的界面,看看哪些东西是我们需要的。 我呢就根据需求中提到的网址进行数据的爬取 财务报告列表 其实看到这个界面,就感觉有戏,毕竟这一个个的列表谁不喜欢呢? 后端请求 点击下一页能看到这个请求发送出来,应该是最开心的一件事情了。 整理一下Url

http://data.eastmoney.com/notices/getdata.ashx?StockCode=600570&CodeType=1&PageIndex=1&PageSize=99999999&jsObj=xuFcpxdt&SecNodeType=0&FirstNodeType=1&rt=51886903

显而易见的几个参数浮现在眼前 PageIndex -> 当前页 PageSize -> 当前页面显示条数 StockCode -> 股票的编号

这样有了这么一个剖析好的url 还怕爬不到数据么 那么我们来看一下这个url返回的结果

varxuFcpxdt={ "data": [ { "NOTICEDATE": "2019-04-19T00:00:00+08:00", "ATTACHTYPE": "0", "ATTACHSIZE": 119, "ENDDATE": "2019-04-19T00:00:00+08:00", "NOTICETITLE": "科大讯飞:第四届董事会第十九次会议决议公告", "INFOCODE": "AN201904181320674323", "CDSY_SECUCODES": [ { "SECURITYVARIETYCODE": "1000005584", "SECURITYTYPECODE": "058001001", "SECURITYCODE": "002230", "SECURITYFULLNAME": "科大讯飞", "SECURITYSHORTNAME": "科大讯飞", "SECURITYTYPE": "A股", "TRADEMARKETCODE": "069001002003", "TRADEMARKET": "深交所中小板", "LISTINGSTATE": "0", "COMPANYCODE": "80027093", "Eid": 0 } ], "ANN_RELCOLUMNS": [ { "COLUMNCODE": "001002009", "COLUMNNAME": "董事会决议公告", "NodeName": null, "Eid": 0, "Order": 999 }, { "COLUMNCODE": "001002002001001", "COLUMNNAME": "分配预案", "NodeName": null, "Eid": 0, "Order": 12 } ], "ANN_RELCODES": [ { "CODETYPE": "058001001", "CODEMARKET": "069001002003", "SECURITYCODE": "002230", "COMPANYCODE": null, "Eid": 0 }, { "CODETYPE": "058001001", "CODEMARKET": "069001002003", "SECURITYCODE": "002230", "COMPANYCODE": null, "Eid": 0 } ], "EUTIME": "2019-04-18T23:05:35+08:00", "TABLEID": 207000006216882112, "Order": 12, "Url": "http://data.eastmoney.com/notices/detail/002230/AN201904181320674323,JWU3JWE3JTkxJWU1JWE0JWE3JWU4JWFlJWFmJWU5JWEzJTll.html" }, { "NOTICEDATE": "2019-04-19T00:00:00+08:00", "ATTACHTYPE": "0", "ATTACHSIZE": 1363, "ENDDATE": "2019-03-31T00:00:00+08:00", "NOTICETITLE": "科大讯飞:2019年第一季度报告全文", "INFOCODE": "AN201904181320674305", "CDSY_SECUCODES": [ { "SECURITYVARIETYCODE": "1000005584", "SECURITYTYPECODE": "058001001", "SECURITYCODE": "002230", "SECURITYFULLNAME": "科大讯飞", "SECURITYSHORTNAME": "科大讯飞", "SECURITYTYPE": "A股", "TRADEMARKETCODE": "069001002003", "TRADEMARKET": "深交所中小板", "LISTINGSTATE": "0", "COMPANYCODE": "80027093", "Eid": 0 } ], "ANN_RELCOLUMNS": [ { "COLUMNCODE": "001001001003001", "COLUMNNAME": "一季度报告全文", "NodeName": null, "Eid": 0, "Order": 25 } ], "ANN_RELCODES": [ { "CODETYPE": "058001001", "CODEMARKET": "069001002003", "SECURITYCODE": "002230", "COMPANYCODE": null, "Eid": 0 } ], "EUTIME": "2019-04-18T20:14:24+08:00", "TABLEID": 207000006216882109, "Order": 25, "Url": "http://data.eastmoney.com/notices/detail/002230/AN201904181320674305,JWU3JWE3JTkxJWU1JWE0JWE3JWU4JWFlJWFmJWU5JWEzJTll.html" } ], "TotalCount": 138, "pages": 69, "rc": 1, "me": null, "dataUrl": "http://newsnotice.eastmoney.com/webapi/api/Notice?Time=&CodeType=1&StockCode=002230&FirstNodeType=1&SecNodeType=0&PageIndex=1&PageSize=2&Token=WZSJPD161130" };

数据比较多,我就展示了2条如果你不想自己读一下结果呢,我这就直接说一下我用到的几个参数吧

TotalCount 这个是全部的报告条数 data 就是我们需要处理的 数据了 |_ NOTICETITLE 是这个报告的标题 - 我用这个来作为导出的文件的文件名 |_ CDSY_SECUCODES -> SECURITYSHORTNAME 这个股票的短称 - 我用来创建二级目录的 Url 就是报告详细内容的url地址了

思考实现

主要的参数都已经准备妥当,那么接下来就是考虑如何实现这个功能了 打开报表详细内容 报表详细内容 在这份报表中呢 有已经转成文本的数据 展示在网页中,我最初是考虑直接爬这边的数据的 但是 遇到了一个坑 这个我会在之后说

看到这个界面中还有一个叫查看PDF原文。Emmm…原来还有PDF原文啊,那好说反正是个a标签,这还不好处理么。

那么现在处理第一个步骤,获取所有报告的url

获取所有报告的url地址

这个其实一点问题都没有,根据我们前文提到的内容,很方便就能实现 直接上代码了

from urllib import request from bs4 import BeautifulSoup import re import os import json #构建get对象的访问函数 def getResponse(url): url_request = request.Request(url) #print("这个对象的方法是:",url_request.get_method()) url_response = request.urlopen(url) return url_response #设置股票代码 StockCode = "002230" PageSize = "999999" #设置获取所有Url的地址 getUrlsRespon = "http://data.eastmoney.com/notices/getdata.ashx?StockCode="+StockCode+"&CodeType=1&PageIndex=1&PageSize="+PageSize+"&jsObj=xuFcpxdt&SecNodeType=0&FirstNodeType=1&rt=51886903" #先 通过 请求获取所有的链接 去掉 var xuFcpxdt = 就是json字符串 getUrlReturn = getResponse(getUrlsRespon).read().decode('GB2312') #简单处理一下 去除 var xuFcpxdt 和 最后的 ; getUrlReturn = getUrlReturn.replace("var xuFcpxdt = ","").replace(";","") getUrlReturn_json = json.loads(getUrlReturn)

我认为我的 备注已经写的足够明白了 要是再看不懂,就是在过不去了 这几乎就是我从什么 都不会一点点理解 到 实施出来的理解 和想法

方法肯定不够好,但这是一个必经过程,我希望的是,等我半年后再看到这博客的时候,会嘲笑现在的我。

好了 扯远了 现在getUrlReturn_json就是格式化后的内容了 这样就能获取我们需要的数据了

继续上代码

#获取全部条数 totalCount = getUrlReturn_json['TotalCount'] #获取data 其中存储了报告的完整名称 股票代码与名称 以及正文Url (该Url 可能会被重定向至pdf文档 ) #目前 如果是网页的 获取网页中的 报告主体内容 如果是 pdf的 下载pdf data = getUrlReturn_json['data']

这个注释在这其实有点早,我是发现问题再加上去的 但是马上就会涉及了

#循环data 获取所需内容 for val in data: #获取报告标题-用于存储文件时作为文件名 reportTitle = val['NOTICETITLE'] #获取股票短称-用户存储文件时作为目录名 shortName = str(val['CDSY_SECUCODES'][0]['SECURITYSHORTNAME']) #获取报告url url = val['Url']

ok 到这需要的东西都获取到了 下一步就是根据这些数据获取我们需要的文件了

根据获取的url地址下载文件或者输出正文内容

虽然我有想把完整代码贴上来 但是我感觉这个是对于我自己劳动成果的 亵渎 也是 剥夺了 正在看本文,希望能了解到、自己学到些东西的 一种 障碍

之后的操作是我花了很长时间完成的,我并不想让任何人随意的就复制拿去使用了,所以我会解剖出来,部分部分的解读一下

好了 现在既然获取到了 报告的url 那我们就能根据这个url获取我们需要的 内容了 当然 首先呢 还是要做一下准备的 用代码 展示一下吧

#文件保存目录名 report/股票短称 baseAddress = "report/"+shortName #文件名 fileAddress = reportTitle + ".txt" fileAddress_pdf = reportTitle + ".pdf"

在准备文件名这边我额外添加了一个 pdf 的 最开始是没想到的,后来遇到问题才加上的

一直在说问题问题,那么现在终于要面对他了!

#请求获得的对象用GBK编码转义一下 该操作需要 捕获一下异常 try: report_html = getResponse(url).read().decode('gbk') #通过bs修饰一下页面代码并找到主要的报告部分-mainInfo soup = BeautifulSoup(report_html, 'html.parser') mainInfo = soup.find_all('div', class_='detail-body')

这边的mainInfo呢 就是在打开的url中显示的正文内容 find_all方法就是 找到指定的载体 通过find_all是可以找到任何在界面中有的内容的 bs就是这么让人放心

那么讲一下问题 decode(‘gbk’)的确可以解决绝大部分的 文字编码 但是 如果这个 网页被重定向到了 某个 pdf文件上呢 直接报错 毫不留情! 为什么 要 try except 目的就是捕获这个错误 然后好好处理一下

好在这个重定向只会重定向到pdf文件 如果解码出错了 直接下载当前文件就好了

那么来处理一下吧

except Exception as e: print("解码出错!!尝试试用其他编码") try : if os.path.exists(baseAddress) == False: os.makedirs(baseAddress) #如果不能用bgk解析出来的 就默认直接下载该文件 大概率为pdf源文件 file_pdf = request.urlopen(url).read() with open(baseAddress + "/" + fileAddress_pdf , "wb") as file: file.write(file_pdf) print("直接写入pdf文件"+ baseAddress + "/" + fileAddress_pdf) except Exception as e2: print(e2) return False

捕获到异常后处理一下 而常规的文件操作 也是需要 捕获异常的 反正就正规操作呗

这边已经有了一个文件写入的例子了,至于你要写入什么数据 就可以自己发挥了啊

mainInfo 就可以直接写入到文件中了 如果对于其中的html标签有点烦 那就自己replace或者用正则删一下吧

那之前提到过一个查看PDF原文,当然也是可以很好的利用起来的

pdfDownloadUrl = soup.find_all('a',string = re.compile('点击查看PDF原文'))[0].get('href')

这个方法就是获取一下 点击查看PDF原文 这个的 href 链接 拿到了这个url 下载文件 就又是很简单的一件事情了

这边就不再多说了 写了这么久 脖子酸

去走走…



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3