参考博客:
6小时爬完上交所和深交所的年报问询函
Python爬取上交所年报并下载
一、任务描述
从上交所的官网上爬取年报PDF文档,并且转成TXT。
二、解决思路
1、解析网页获取年报的文件链接,并下载PDF
2、读取第一步的PDF 数据,并直接转成 TXT 格式的文字
三、网页分析
1、 数据包位置
进入要下载年报的界面,点击查看源码
2、结合日期获得不同的URL链接,但这一步得到的并不是PDF的下载链接,解析这个URL链接
3、结合第二步解析URL链接获得的网页内容,查找该日期对应的PDF下载链接
四、PDF转TXT
1、代码
这个直接搬运了第一篇参考博客的代码啦!
2、MAC系统GB编码的坑
PDF转TXT后得到的TXT为下图所示
解决方案是知乎上的一个回答:
Python解析pdf得到的中文CID字库如何变成utf-8
五、核心代码
1、下载PDF
import json
import requests
import re
import datetime
import csv
from urllib.request import urlopen
from urllib.request import Request
from urllib.request import quote
import requests
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LTTextBoxHorizontal, LAParams
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfinterp import PDFTextExtractionNotAllowed
from pdfminer.pdfparser import PDFParser, PDFDocument
f=open ('stkcd.csv',mode='w',encoding='gbk',newline='')
writer = csv.writer(f)
head=['stkcd']
writer.writerow(head)
#要下载的年报日期可以根据需要调整,开始日期和结束日期间隔最好不要超过30日#
begin = datetime.date(2019,12,1)
end = datetime.date(2019,12,30)
for i in range((end - begin).days+1):
searchDate = str(begin + datetime.timedelta(days=i))
response=requests.get(
'http://query.sse.com.cn/infodisplay/queryLatestBulletinNew.do?&jsonCallBack=jsonpCallback43752&productId=&reportType2=DQGG&reportType=YEARLY&beginDate='+searchDate+'&endDate='+searchDate+'&pageHelp.pageSize=25&pageHelp.pageCount=50&pageHelp.pageNo=1&pageHelp.beginPage=1&pageHelp.cacheSize=1&pageHelp.endPage=5&_=1561094157400'
,
headers={'User-Agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' ,'Referer':'http://www.sse.com.cn/disclosure/listedinfo/regular/'}
)#传送请求时把headers传入Request参数里,应付防盗链了;referer:将请求的的浏览器设置成本网站的
json_str = response.text[19:-1]
data = json.loads(json_str)# 把Json格式字符串解码转换成Python对象,得到dict格式
for report in data['result']:
download_url = 'http://www.sse.com.cn/' + report['URL']
if re.search('年度报告',report['title'],re.S):#使 . 匹配包括换行在内的所有字符
if re.search('摘要',report['title'],re.S):###避免下载一些年报摘要等不需要的文件###
pass #do nothing
else:
filename = report['security_Code']+report['title'] +searchDate+ '.pdf'
print(filename)
writer.writerow([report['security_Code']])###将公司代码写进csv文件,便于计数,非必须步骤###
if re.search('ST',report['title'],re.S):###下载前要将文件名中带*号的去掉,因为文件命名规则不能带*号,否则程序会中断###
filename=report['security_Code']+'-ST' +searchDate+ '.pdf'
download_url = 'http://static.sse.com.cn/' + report['URL']
resource = requests.get(download_url, stream=True)
with open(filename, 'wb') as fd:
for y in resource.iter_content(102400): #把PDF文档写入
fd.write(y)
print(filename, '完成下载')
else:
download_url = 'http://static.sse.com.cn/' + report['URL']
resource = requests.get(download_url, stream=True)
with open(filename, 'wb') as fd:
for y in resource.iter_content(102400):
fd.write(y)
print(filename, '完成下载')
2、PDF转TXT
# fp = open('600193-ST2019-12-17.pdf','rb')
praser_pdf = PDFParser(fp)
# 创建一个PDF文档
doc = PDFDocument()
# 连接分析器 与文档对象
praser_pdf.set_document(doc)
doc.set_parser(praser_pdf)
# 提供初始化密码doc.initialize("123456")
# 如果没有密码 就创建一个空的字符串
doc.initialize()
# 检测文档是否提供txt转换,不提供就忽略
if not doc.is_extractable:
raise PDFTextExtractionNotAllowed
else:
# 创建PDf资源管理器 来管理共享资源
rsrcmgr = PDFResourceManager()
# 创建一个PDF参数分析器
laparams = LAParams()
# 创建聚合器
device = PDFPageAggregator(rsrcmgr, laparams=laparams)
# 创建一个PDF页面解释器对象
interpreter = PDFPageInterpreter(rsrcmgr, device)
# 循环遍历列表,每次处理一页的内容
# doc.get_pages() 获取page列表
for page in doc.get_pages():
# 使用页面解释器来读取
interpreter.process_page(page)
# 使用聚合器获取内容
layout = device.get_result()
# 这里layout是一个LTPage对象 里面存放着 这个page解析出的各种对象 一般包括LTTextBox, LTFigure, LTImage, LTTextBoxHorizontal 等等 想要获取文本就获得对象的text属性,
for out in layout:
# 判断是否含有get_text()方法,图片之类的就没有
# if ``hasattr(out,"get_text"):
docname = "上交所列表.txt"
with open(docname,'a') as f:
if isinstance(out, LTTextBoxHorizontal):
results = out.get_text()
print(results)
f.write(results)