参考文献:
6小时爬完上交所和深交所的年报问询函
Python爬取上交所年报并下载
一、任务描述
从上交所官网上爬取年报并转成TXT
二、解决思路
1、解析网页,结合日期获取全部的年报链接,下载PDF
2、读取第一步获取的PDF,并直接转成 TXT 格式的文字
三、网页分析
点进去年报所在的网页,点击查看源码,该页面下的URL就是对应年报PDF下载地址;
观察URL其实可以看到不同的PDF是对应不同的日期的,根据这个特点,自主规定要下载的日期范围
四、PDF转TXT
1、PDF转PDF的库是pdfminer3k,代码直接参考第一个链接的。
2、我是mac版本,PDF转TXT的时候有一个坑
贴一个知乎的解决方案
MAC版本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)