本文轉載自一下網站:Python爬蟲(5):Selenium 爬取東方財富網股票財務報表 https://www.makcyun.top/web_scraping_withpython5.html
需要學習的地方:
1.Selenium的安裝,配置
2.Selenium的初步使用(自動翻頁)
利用Selenium爬取東方財富網各上市公司歷年的財務報表數據。
摘要: 現在很多網頁都采取JavaScript進行動態渲染,其中包括Ajax技術。上一篇文章通過分析Ajax接口數據,順利爬取了澎湃新聞網動態網頁中的圖片。但有的網頁雖然也Ajax技術,但接口參數可能是加密的無法直接獲得,比如淘寶;有的動態網頁也采用JavaScript,但不是Ajax技術,比如Echarts官網。所以,當遇到這兩類網頁時,上一篇文章中的方法便不再奏效,需要新的采取新的方法,這其中包括干脆、直接、好用的的Selenium大法。東方財富網的財務報表網頁也是通過JavaScript動態加載的,本文利用Selenium方法爬取該網站上市公司的財務報表數據。
[TOC]
1. 實戰背景
很多網站都提供上市公司的公告、財務報表等金融投資信息和數據,比如:騰訊財經、網易財經、新浪財經、東方財富網等。這之中,發現東方財富網的數據非常齊全。
東方財富網
有一個數據中心:http://data.eastmoney.com/center/,該數據中心提供包括特色數據、研究報告、年報季報等在內的大量數據(見下圖)。
以年報季報類別為例,我們點開該分類查看一下2018年中報(見下圖),可以看到該分類下又包括:業績報表、業績快報、利潤表等7個報表的數據。以業績報表為例,報表包含全部3000多只股票的業績報表數據,一共有70多頁。
假如,我們想獲取所有股票2018年中的業績報表數據,然后對該數據進行一些分析。采取手動復制的方法,70多頁可以勉強完成。但如果想獲取任意一年、任意季度、任意報表的數據,要再通過手動復制的方法,工作量會非常地大。舉個例子,假設要獲取10年間(40個季度)、所有7個報表的數據,那么手動復制的工作量大約將是:40×7×70(每個報表大約70頁),差不多要重復性地復制2萬次!!!可以說是人工不可能完成的任務。所以,本文的目標就是利用Selenium自動化技術,爬取年報季報類別下,任意一年(網站有數據至今)、任意財務報表數據。我們所需要做的,僅是簡單輸入幾個字符,其他就全部交給電腦,然后過一會兒打開excel,就可以看到所需數據”靜靜地躺在那里”,是不是挺酷的?
好,下面我們就開始實操一下。首先,需要分析要爬取的網頁對象。
2. 網頁分析
之前,我們已經爬過表格型的數據,所以對表格數據的結構應該不會太陌生,如果忘了,可以再看一下這篇文章:https://www.makcyun.top/web_scraping_withpython2.html
我們這里以上面的2018年中報的業績報表為例,查看一下表格的形式。
網址url:http://data.eastmoney.com/bbsj/201806/lrb.html,bbsj
代表年報季報,201803
代表2018年一季報
,類似地,201806表示年中報;lrb
是利潤表
的首字母縮寫,同理,yjbb
表示業績報表
。可以看出,該網址格式很簡單,便於構造url。
接着,我們點擊下一頁
按鈕,可以看到表格更新后,url沒有發生改變,可以判定是采用了Javscript。那么,我們首先判斷是不是采用了Ajax加載的。方法也很簡單,右鍵檢查或按F12,切換到network並選擇下面的XHR,再按F5刷新。可以看到只有一個Ajax請求,點擊下一頁也並沒有生成新的Ajax請求,可以判斷該網頁結構不是常見的那種點擊下一頁或者下拉會源源不斷出現的Ajax請求類型,那么便無法構造url來實現分頁爬取。
XHR選項里沒有找到我們需要的請求,接下來試試看能不能再JS里找到表格的數據請求。將選項選為JS,再次F5刷新,可以看到出現了很多JS請求,然后我們點擊幾次下一頁,會發現彈出新的請求來,然后右邊為響應的請求信息。url鏈接非常長,看上去很復雜。好,這里我們先在這里打住不往下了。
可以看到,通過分析后台元素來爬取該動態網頁的方法,相對比較復雜。那么有沒有干脆、直截了當地就能夠抓取表格內容的方法呢?有的,就是本文接下來要介紹的Selenium大法。
3. Selenium知識
Selenium 是什么?一句話,自動化測試工具。它是為了測試而出生的,但在近幾年火熱的爬蟲領域中,它搖身一變,變成了爬蟲的利器。直白點說, Seleninm能控制瀏覽器, 像人一樣”上網”。比如,可以實現網頁自動翻頁、登錄網站、發送郵件、下載圖片/音樂/視頻等等。舉個例子,寫幾行python代碼就可以用Selenium實現登錄IT桔子,然后瀏覽網頁的功能。
怎么樣,僅用幾行代碼就能實現自動上網操作,是不是挺神奇的?當然,這僅僅是Selenium最簡單的功能,還有很多更加豐富的操作,可以參考以下幾篇教程:
參考網站:
Selenium官網: https://selenium-python.readthedocs.io/
SeleniumPython文檔(英文版):http://selenium-python.readthedocs.org/index.html
SeleniumPython文檔(中文版):https://selenium-python-zh.readthedocs.io/en/latest/faq.html
Selenium 基本操作:https://www.yukunweb.com/2017/7/python-spider-Selenium-PhantomJS-basic/
Selenium爬取淘寶信息實戰:https://cuiqingcai.com/2852.html
只需要記住重要的一點就是:Selenium能做到"可見即可爬"
。也就是說網頁上你能看到的東西,Selenium基本上都能爬取下來。包括上面我們提到的東方財富網的財務報表數據,它也能夠做到,而且非常簡單直接,不用去后台查看用了什么JavaScript技術或者Ajax參數。下面我們就實際來操練下吧。
4. 編碼實現
4.1. 思路
- 安裝配置好Selenium運行的相關環境,瀏覽器可以用Chrome、Firefox、PhantomJS等,我用的是Chrome;
- 東方財富網的財務報表數據不用登錄可直接獲得,Selenium更加方便爬取;
- 先以單個網頁中的財務報表為例,表格數據結構簡單,可先直接定位到整個表格,然后一次性獲取所有td節點對應的表格單元內容;
- 接着循環分頁爬取所有上市公司的數據,並保存為csv文件。
- 重新構造靈活的url,實現可以爬取任意時期、任意一張財務報表的數據。
根據上述思路,下面就用代碼一步步來實現。
4.2. 爬取單頁表格
我們先以2018年中報的利潤表
為例,抓取該網頁的第一頁表格數據,網頁url:http://data.eastmoney.com/bbsj/201806/lrb.html
快速定位到表格所在的節點:id = dt_1,然后可以用Selenium進行抓取了,方法如下:
from selenium import webdriver |
這里,使用Chrome瀏覽器構造一個Webdriver對象,賦值給變量browser,browser調用get()方法請求想要抓取的網頁。接着使用find_element_by_css_selector
方法查找表格所在的節點:‘#dt_1’。
這里推薦一款小巧、快速定位css/xpath的Chrome插件:SelectorGadget,使用這個插件就不用再去源代碼中手動定位節點那么麻煩了。
插件地址:https://chrome.google.com/webstore/detail/selectorgadget/mhjhnkcfbdhnjickkkdbjoemdmbfginb
緊接着再向下定位到td節點,因為網頁中有很多個td節點,所以要用find_elements方法。然后,遍歷數據節點存儲到list中。打印查看一下結果:
# list形式: |
是不是很方便,幾行代碼就能抓取下來這一頁表格,除了速度有點慢。
為了便於后續存儲,我們將list轉換為DataFrame。首先需要把這一個大的list分割為多行多列的子list,實現如下:
import pandas as pd |
這里,要將list分割為子list,只需要確定表格有多少列即可,然后將每相隔這么多數量的值划分為一個子list。如果我們數一下該表的列數,可以發現一共有16列。但是這里不能使用這個數字,因為除了利潤表,其他報表的列數並不是16,所以當后期爬取其他表格可能就會報錯。這里仍然通過find_elements_by_css_selector方法,定位首行td節點的數量,便可獲得表格的列數,然后將list拆分為對應列數的子list。同時,原網頁中打開”詳細”列的鏈接可以查看更詳細的數據,這里我們把url提取出來,並增加一列到DataFrame中,方便后期查看。打印查看一下輸出結果:
可以看到,表格所有的數據我們都抓取到了,下面只需要進行分頁循環爬取就行了。
這里,沒有抓取表頭是因為表頭有合並單元格,處理起來就非常麻煩。建議表格抓取下來后,在excel中復制表頭進去就行了。如果,實在想要用代碼完成,可以參考這篇文章:https://blog.csdn.net/weixin_39461443/article/details/75456962
4.3. 分頁爬取
上面完成了單頁表格的爬取,下面我們來實現分頁爬取。
首先,我們先實現Selenium模擬翻頁跳轉操作,成功后再爬取每頁的表格內容。
from selenium import webdriver |
這里,我們先加載了相關包,使用WebDriverWait對象,設置最長10s的顯式等待時間,以便網頁加載出表格。判斷表格是否加載出來,用到了EC.presence_of_element_located條件。表格加載出來后,設置一個頁面判斷,如果在第1頁就等待頁面加載完成,如果大於第1頁就開始跳轉。
要完成跳轉操作,我們需要通過獲取輸入框input節點,然后用clear()方法清空輸入框,再通過send_keys()方法填寫相應的頁碼,接着通過submit.click()方法擊下一頁完成翻頁跳轉。
這里,我們測試一下前4頁跳轉效果,可以看到網頁成功跳轉了。下面就可以對每一頁應用第一頁爬取表格內容的方法,抓取每一頁的表格,轉為DataFrame然后存儲到csv文件中去。
4.4. 通用爬蟲構造
上面,我們完成了2018年中報利潤表: http://data.eastmoney.com/bbsj/201806/lrb.html,一個網頁表格的爬取。但如果我們想爬取任意時期、任意一張報表的表格,比如2017年3季度的利潤表、2016年全年的業績報表、2015年1季度的現金流量表等等。上面的代碼就行不通了,下面我們對代碼進行一下改造,變成更通用的爬蟲。從圖中可以看到,東方財富網年報季報有7張表格,財務報表最早從2007年開始每季度一次。基於這兩個維度,可重新構造url的形式,然后爬取表格數據。下面,我們用代碼進行實現:
# 重構url |
經過上面的設置,我們通過輸入想要獲得指定時期、制定財務報表類型的數值,就能返回相應的url鏈接。將該鏈接應用到前面的爬蟲中,就可以爬取相應的報表內容了。
另外,除了從第一頁開始爬取到最后一頁的結果以外,我們還可以自定義設置想要爬取的頁數。比如起始頁數從第1頁開始,然后爬取10頁。
# 4 選擇爬取頁數范圍 |
經過上面的設置,我們就可以實現自定義時期和財務報表類型的表格爬取了,將代碼再稍微整理一下,可實現下面的爬蟲效果:
視頻截圖:
視頻地址:https://v.qq.com/x/page/y07335thsn2.html
背景中類似黑客帝國的代碼雨效果,其實是動態網頁效果。素材來源於下面這個網站,該網站還有很多酷炫的動態背景可以下載下來。
http://wallpaper.upupoo.com/store/paperDetail-1783830052.htm
4.5. 完整代碼
整個爬蟲的完整代碼如下所示:
from selenium import webdriver |
這里,我下載了所有上市公司的部分報表。
2018年中報業績報表:
2017年報的利潤表:
如果你想下載更多的報表,可以使用文中的代碼,代碼和素材資源可以在下面的鏈接中獲取:
https://github.com/makcyun/eastmoney_spider
另外,爬蟲還可以再完善一下,比如增加爬取上市公司的公告信息,設置可以爬任意一家(數家/行業)的公司數據而不用全部。
還有一個問題是,Selenium爬取的速度很慢而且很占用內存,建議盡量先嘗試采用Requests請求的方法,抓不到的時候再考慮這個。文章開頭在進行網頁分析的時候,我們初步分析了表格JS的請求數據,是否能從該請求中找到我們需要的表格數據呢? 后續文章,我們換一個思路再來嘗試爬取一次。