利用Python實現批量下載上市公司財務報表

導語

用VBA做瞭個小工具,可以批量把某網站上的上市公司的財報下下來。

制作思路非常簡單:

1、從該網站上的下載鏈接中找到規律:都是一段@#¥%……&開頭加上想要下載的報表類型(BS,ER,SCF),加上會計期間(按年度、按報告期、按季度),再加上上市公司代碼。

2、然後用Excel表格排列組合生成那些下載鏈接,並訪問。這裡沒有直接用get/post,因為會被網站識別出來並拒絕訪問,下載下來的文件就是空的。然後我就用瞭個比較笨的辦法,調用IE去訪問這些網址,然後用VBA的Sendkeys方法模擬手工點擊下載按鈕。

運行之後沒有被block掉,可行

感覺像是在用手榴彈炸直升機,而且用VBA有個很大的缺陷:如果IE不能正確地出現在桌面的最前臺(比如微信突然彈出個消息……),這樣會導致application.sendkeys方法失效。

這裡用Python再做一個,但還是避免不瞭要借用一下VBA裡面的一些功能……

思路和上面是一樣的,根據網站規則組裝好下載鏈接後調用IE去下載。

不一樣的是,這次沒有模擬快捷鍵,而是用pyautogui的圖像識別功能去調用鼠標點擊下載按鈕。用這種方法的好處是不容易被彈窗打斷,命中率更高。

Python代碼:

"""
運行前提
 1、確保“從THS批量下載上市公司財報.py”、“從THS批量下載上市公司財報.xlsm”、“capture.png”三個文件存放在同一目錄下
 2、確保安裝瞭以下幾個第三方庫:pyautogui、pywin32、pandas、xlwings
 3、確保把IE的默認下載路徑改成本文件所在目錄
 4、下載後立即最小化運行窗口,避免遮擋屏幕導致pyautogui無法定位圖像位置
沒有安裝的話可以在命令提示符裡面輸入“pip install 庫名”進行安裝:
    pip install pyautogui
    pip install pywin32
    pip install pandas
    pip install xlwings
"""
 
import pyautogui
from win32com.client import DispatchEx
import pandas
import xlwings
import time
import os
 
# 同花順網站下載{鏈接的固定字段:文件名固定字段}
ref = {'main&type=report': 'main_report.xls',
       'main&type=year': 'main_year.xls',
       'main&type=simple': 'main_simple.xls',
       'debt&type=report': 'debt_report.xls',
       'debt&type=year': 'debt_year.xls',
       'benefit&type=report': 'benefit_report.xls',
       'benefit&type=year': 'benefit_year.xls',
       'benefit&type=simple': 'benefit_simple.xls',
       'cash&type=report': 'cash_report.xls',
       'cash&type=year': 'cash_year.xls',
       'cash&type=simple': 'cash_simple.xls'}
 
df = pandas.read_excel(r'./從THS批量下載上市公司財報.xlsm', sheet_name='Main', dtype='str', header=0)
 
# 把表格中不足6位的公司代碼補全成6位,比如把'2'補全成'000002'
df['公司代碼'] = df['公司代碼'].apply(lambda x: str('000000')[:(6 - len(x))] + str(x))
 
# 創建一個{下載文件名:下載鏈接}的字典
urls = {}
for i in ref.keys():
    for j in df['公司代碼']:
        # 如果原來下載過就略過以節約時間
        if not os.path.exists(f'{j}_{ref[i]}'):
            urls[f'{j}_{ref[i]}'] = str(f'http://basic.10jqka.com.cn/api/stock/export.php?export={i}&code={j}')
 
wb = xlwings.App(visible=False, add_book=False).books.open(r'./從THS批量下載上市公司財報.xlsm')
 
# 這裡用Excel宏的一個退出IE功能,比win32com的功能更好用
# 也是因為本人技術太渣,不知道怎麼用Python完全退出IE
# QuitIE的宏代碼在後面
QuitIE = wb.macro('QuitIE')
 
# 這裡用Excel宏的XMLHTTP功能,下載效率更高
# XMLHTTP的宏代碼在後面
XMLHTTP = wb.macro('XMLHTTP')
 
# IE瀏覽器下載button的截圖
img = r'./capture.png'
 
 
def IEDownload(url):
    ie = DispatchEx('InternetExplorer.Application')
    ie.Navigate(url)
 
    # 最多嘗試查找5次,避免死循環
    times = 0
    while times < 5:
        location = pyautogui.locateCenterOnScreen(img, confidence=0.9)
        if location is not None:
            pyautogui.click(location.x, location.y, clicks=1, button='left', duration=0.01, interval=0.01)
            break
        times += 1
 
 
windows = 0
for filename in urls:
    # 每7次調用一次xmlhttp,膽子大可以把這個值設小點
    if windows % 7 == 0:
        XMLHTTP(filename, urls[filename])
        if not os.path.exists(f'./{filename}'):
            IEDownload(urls[filename])
        windows += 1
    else:
        IEDownload(urls[filename])
        windows += 1
        # 每7次關閉IE的所有窗口,釋放內存
        if windows % 7 == 0:
            time.sleep(0.05)
            QuitIE()
            time.sleep(0.05)
 
QuitIE()
wb.close()
xlwings.App().quit()
 
# 以下是可選功能,把xls格式的文件轉成最新的xlsx格式
# if not os.path.exists('./xlsx格式文件'):
#   os.mkdir('./xlsx格式文件')
# for i in os.listdir('.'):
#   if not os.path.exists(f'./xlsx格式文件/{i}x') and i.endswith('xls'):
#          df=pandas.read_excel(f'./{i}',header=1,index_col=0)
#          df.to_excel(f'./xlsx格式文件/{i}x')

QuitIE宏代碼:

Sub QuitIE() 
 
    Dim winmgmts As Object
    Dim ieprc As Object
    Dim ieprcs As Object
 
    Set winmgmts = GetObject("winmgmts://.")
    Set ieprcs = winmgmts.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'iexplore.exe'")
 
    For Each ieprc In ieprcs
        On Error Resume Next
        Call ieprc.Terminate
    Next
   
    Set ieprcs = Nothing
    Set winmgmts = Nothing
 
End Sub

XMLHTTP宏代碼:

'傳進來的兩個參數分別是文件名和下載鏈接
Sub XMLHTTP(FileName, url)  
Dim h, s, fpath
fpath = ThisWorkbook.Path & "\"
'先判斷下文件是不是已經下載過瞭
If Dir(fpath & FileName) = "" Then
 
    Set h = CreateObject("Microsoft.XMLHTTP")
    h.Open "GET", url, False   '網絡中的文件URL
    h.send
    Set s = CreateObject("ADODB.Stream")
    s.Type = 1
    s.Open
    s.write h.responseBody
    s.savetofile fpath & FileName, 2 '本地保存文件名
    s.Close
 
    '萬一被網站反爬瞭下載下來的就是空文件,刪掉
    If FileLen(fpath & FileName) < 600 Then 
        Kill fpath & FileName
    End If
    
End If
End Sub

以上就是利用Python實現批量下載上市公司財務報表的詳細內容,更多關於Python下載報表的資料請關註WalkonNet其它相關文章!

推薦閱讀: