午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

使用Selenium爬取網(wǎng)站表格類數(shù)據(jù)

 北方的白樺林 2021-04-14

本文轉(zhuǎn)載自一下網(wǎng)站:Python爬蟲(5):Selenium 爬取東方財(cái)富網(wǎng)股票財(cái)務(wù)報(bào)表 https://www./web_scraping_withpython5.html

需要學(xué)習(xí)的地方:

1.Selenium的安裝,配置

2.Selenium的初步使用(自動(dòng)翻頁)

利用Selenium爬取東方財(cái)富網(wǎng)各上市公司歷年的財(cái)務(wù)報(bào)表數(shù)據(jù)。

摘要: 現(xiàn)在很多網(wǎng)頁都采取JavaScript進(jìn)行動(dòng)態(tài)渲染,其中包括Ajax技術(shù)。上一篇文章通過分析Ajax接口數(shù)據(jù),順利爬取了澎湃新聞網(wǎng)動(dòng)態(tài)網(wǎng)頁中的圖片。但有的網(wǎng)頁雖然也Ajax技術(shù),但接口參數(shù)可能是加密的無法直接獲得,比如淘寶;有的動(dòng)態(tài)網(wǎng)頁也采用JavaScript,但不是Ajax技術(shù),比如Echarts官網(wǎng)。所以,當(dāng)遇到這兩類網(wǎng)頁時(shí),上一篇文章中的方法便不再奏效,需要新的采取新的方法,這其中包括干脆、直接、好用的的Selenium大法。東方財(cái)富網(wǎng)的財(cái)務(wù)報(bào)表網(wǎng)頁也是通過JavaScript動(dòng)態(tài)加載的,本文利用Selenium方法爬取該網(wǎng)站上市公司的財(cái)務(wù)報(bào)表數(shù)據(jù)。

[TOC]

1. 實(shí)戰(zhàn)背景

很多網(wǎng)站都提供上市公司的公告、財(cái)務(wù)報(bào)表等金融投資信息和數(shù)據(jù),比如:騰訊財(cái)經(jīng)、網(wǎng)易財(cái)經(jīng)、新浪財(cái)經(jīng)、東方財(cái)富網(wǎng)等。這之中,發(fā)現(xiàn)東方財(cái)富網(wǎng)的數(shù)據(jù)非常齊全。

東方財(cái)富網(wǎng)有一個(gè)數(shù)據(jù)中心:http://data.eastmoney.com/center/,該數(shù)據(jù)中心提供包括特色數(shù)據(jù)、研究報(bào)告、年報(bào)季報(bào)等在內(nèi)的大量數(shù)據(jù)(見下圖)。

以年報(bào)季報(bào)類別為例,我們點(diǎn)開該分類查看一下2018年中報(bào)(見下圖),可以看到該分類下又包括:業(yè)績報(bào)表、業(yè)績快報(bào)、利潤表等7個(gè)報(bào)表的數(shù)據(jù)。以業(yè)績報(bào)表為例,報(bào)表包含全部3000多只股票的業(yè)績報(bào)表數(shù)據(jù),一共有70多頁。

假如,我們想獲取所有股票2018年中的業(yè)績報(bào)表數(shù)據(jù),然后對該數(shù)據(jù)進(jìn)行一些分析。采取手動(dòng)復(fù)制的方法,70多頁可以勉強(qiáng)完成。但如果想獲取任意一年、任意季度、任意報(bào)表的數(shù)據(jù),要再通過手動(dòng)復(fù)制的方法,工作量會(huì)非常地大。舉個(gè)例子,假設(shè)要獲取10年間(40個(gè)季度)、所有7個(gè)報(bào)表的數(shù)據(jù),那么手動(dòng)復(fù)制的工作量大約將是:40×7×70(每個(gè)報(bào)表大約70頁),差不多要重復(fù)性地復(fù)制2萬次!?。】梢哉f是人工不可能完成的任務(wù)。所以,本文的目標(biāo)就是利用Selenium自動(dòng)化技術(shù),爬取年報(bào)季報(bào)類別下,任意一年(網(wǎng)站有數(shù)據(jù)至今)、任意財(cái)務(wù)報(bào)表數(shù)據(jù)。我們所需要做的,僅是簡單輸入幾個(gè)字符,其他就全部交給電腦,然后過一會(huì)兒打開excel,就可以看到所需數(shù)據(jù)”靜靜地躺在那里”,是不是挺酷的?

好,下面我們就開始實(shí)操一下。首先,需要分析要爬取的網(wǎng)頁對象。

2. 網(wǎng)頁分析

之前,我們已經(jīng)爬過表格型的數(shù)據(jù),所以對表格數(shù)據(jù)的結(jié)構(gòu)應(yīng)該不會(huì)太陌生,如果忘了,可以再看一下這篇文章:https://www./web_scraping_withpython2.html

我們這里以上面的2018年中報(bào)的業(yè)績報(bào)表為例,查看一下表格的形式。

網(wǎng)址url:http://data.eastmoney.com/bbsj/201806/lrb.html,bbsj代表年報(bào)季報(bào),201803代表2018年一季報(bào),類似地,201806表示年中報(bào);lrb利潤表的首字母縮寫,同理,yjbb表示業(yè)績報(bào)表。可以看出,該網(wǎng)址格式很簡單,便于構(gòu)造url。

接著,我們點(diǎn)擊下一頁按鈕,可以看到表格更新后,url沒有發(fā)生改變,可以判定是采用了Javscript。那么,我們首先判斷是不是采用了Ajax加載的。方法也很簡單,右鍵檢查或按F12,切換到network并選擇下面的XHR,再按F5刷新??梢钥吹街挥幸粋€(gè)Ajax請求,點(diǎn)擊下一頁也并沒有生成新的Ajax請求,可以判斷該網(wǎng)頁結(jié)構(gòu)不是常見的那種點(diǎn)擊下一頁或者下拉會(huì)源源不斷出現(xiàn)的Ajax請求類型,那么便無法構(gòu)造url來實(shí)現(xiàn)分頁爬取。

XHR選項(xiàng)里沒有找到我們需要的請求,接下來試試看能不能再JS里找到表格的數(shù)據(jù)請求。將選項(xiàng)選為JS,再次F5刷新,可以看到出現(xiàn)了很多JS請求,然后我們點(diǎn)擊幾次下一頁,會(huì)發(fā)現(xiàn)彈出新的請求來,然后右邊為響應(yīng)的請求信息。url鏈接非常長,看上去很復(fù)雜。好,這里我們先在這里打住不往下了。

可以看到,通過分析后臺(tái)元素來爬取該動(dòng)態(tài)網(wǎng)頁的方法,相對比較復(fù)雜。那么有沒有干脆、直截了當(dāng)?shù)鼐湍軌蜃ト”砀駜?nèi)容的方法呢?有的,就是本文接下來要介紹的Selenium大法。

3. Selenium知識(shí)

Selenium 是什么?一句話,自動(dòng)化測試工具。它是為了測試而出生的,但在近幾年火熱的爬蟲領(lǐng)域中,它搖身一變,變成了爬蟲的利器。直白點(diǎn)說, Seleninm能控制瀏覽器, 像人一樣”上網(wǎng)”。比如,可以實(shí)現(xiàn)網(wǎng)頁自動(dòng)翻頁、登錄網(wǎng)站、發(fā)送郵件、下載圖片/音樂/視頻等等。舉個(gè)例子,寫幾行python代碼就可以用Selenium實(shí)現(xiàn)登錄IT桔子,然后瀏覽網(wǎng)頁的功能。

怎么樣,僅用幾行代碼就能實(shí)現(xiàn)自動(dòng)上網(wǎng)操作,是不是挺神奇的?當(dāng)然,這僅僅是Selenium最簡單的功能,還有很多更加豐富的操作,可以參考以下幾篇教程:

參考網(wǎng)站:

Selenium官網(wǎng): https://selenium-python./

SeleniumPython文檔(英文版):http://selenium-python./index.html

SeleniumPython文檔(中文版):https://selenium-python-zh./en/latest/faq.html

Selenium 基本操作:https://www./2017/7/python-spider-Selenium-PhantomJS-basic/

Selenium爬取淘寶信息實(shí)戰(zhàn):https:///2852.html

只需要記住重要的一點(diǎn)就是:Selenium能做到'可見即可爬'。也就是說網(wǎng)頁上你能看到的東西,Selenium基本上都能爬取下來。包括上面我們提到的東方財(cái)富網(wǎng)的財(cái)務(wù)報(bào)表數(shù)據(jù),它也能夠做到,而且非常簡單直接,不用去后臺(tái)查看用了什么JavaScript技術(shù)或者Ajax參數(shù)。下面我們就實(shí)際來操練下吧。

4. 編碼實(shí)現(xiàn)

4.1. 思路

  • 安裝配置好Selenium運(yùn)行的相關(guān)環(huán)境,瀏覽器可以用Chrome、Firefox、PhantomJS等,我用的是Chrome;
  • 東方財(cái)富網(wǎng)的財(cái)務(wù)報(bào)表數(shù)據(jù)不用登錄可直接獲得,Selenium更加方便爬??;
  • 先以單個(gè)網(wǎng)頁中的財(cái)務(wù)報(bào)表為例,表格數(shù)據(jù)結(jié)構(gòu)簡單,可先直接定位到整個(gè)表格,然后一次性獲取所有td節(jié)點(diǎn)對應(yīng)的表格單元內(nèi)容;
  • 接著循環(huán)分頁爬取所有上市公司的數(shù)據(jù),并保存為csv文件。
  • 重新構(gòu)造靈活的url,實(shí)現(xiàn)可以爬取任意時(shí)期、任意一張財(cái)務(wù)報(bào)表的數(shù)據(jù)。

根據(jù)上述思路,下面就用代碼一步步來實(shí)現(xiàn)。

4.2. 爬取單頁表格

我們先以2018年中報(bào)的利潤表為例,抓取該網(wǎng)頁的第一頁表格數(shù)據(jù),網(wǎng)頁url:http://data.eastmoney.com/bbsj/201806/lrb.html

快速定位到表格所在的節(jié)點(diǎn):id = dt_1,然后可以用Selenium進(jìn)行抓取了,方法如下:

from selenium import webdriver
browser = webdriver.Chrome()
# 當(dāng)測試好能夠順利爬取后,為加快爬取速度可設(shè)置無頭模式,即不彈出瀏覽器
# 添加無頭headlesss 1使用chrome headless,2使用PhantomJS
# 使用 PhantomJS 會(huì)警告高不建議使用phantomjs,建議chrome headless
# chrome_options = webdriver.ChromeOptions()
# chrome_options.add_argument('--headless')
# browser = webdriver.Chrome(chrome_options=chrome_options)
# browser = webdriver.PhantomJS()
# browser.maximize_window() # 最大化窗口,可以選擇設(shè)置

browser.get('http://data.eastmoney.com/bbsj/201806/lrb.html')
element = browser.find_element_by_css_selector('#dt_1') # 定位表格,element是WebElement類型
# 提取表格內(nèi)容td
td_content = element.find_elements_by_tag_name('td') # 進(jìn)一步定位到表格內(nèi)容所在的td節(jié)點(diǎn)
lst = [] # 存儲(chǔ)為list
for td in td_content:
lst.append(td.text)
print(lst) # 輸出表格內(nèi)容

這里,使用Chrome瀏覽器構(gòu)造一個(gè)Webdriver對象,賦值給變量browser,browser調(diào)用get()方法請求想要抓取的網(wǎng)頁。接著使用find_element_by_css_selector方法查找表格所在的節(jié)點(diǎn):'#dt_1’。

這里推薦一款小巧、快速定位css/xpath的Chrome插件:SelectorGadget,使用這個(gè)插件就不用再去源代碼中手動(dòng)定位節(jié)點(diǎn)那么麻煩了。

插件地址:https://chrome.google.com/webstore/detail/selectorgadget/mhjhnkcfbdhnjickkkdbjoemdmbfginb

緊接著再向下定位到td節(jié)點(diǎn),因?yàn)榫W(wǎng)頁中有很多個(gè)td節(jié)點(diǎn),所以要用find_elements方法。然后,遍歷數(shù)據(jù)節(jié)點(diǎn)存儲(chǔ)到list中。打印查看一下結(jié)果:

# list形式:
['1', '002161', '遠(yuǎn)望谷', ...'-7960萬', '09-29',
'2','002316', '亞聯(lián)發(fā)展', ...'1.79億', '09-29',
'3',...
'50', '002683', '宏大爆破',...'1.37億', '09-01']

是不是很方便,幾行代碼就能抓取下來這一頁表格,除了速度有點(diǎn)慢。

為了便于后續(xù)存儲(chǔ),我們將list轉(zhuǎn)換為DataFrame。首先需要把這一個(gè)大的list分割為多行多列的子list,實(shí)現(xiàn)如下:

import pandas as pd
# 確定表格列數(shù)
col = len(element.find_elements_by_css_selector('tr:nth-child(1) td'))
# 通過定位一行td的數(shù)量,可獲得表格的列數(shù),然后將list拆分為對應(yīng)列數(shù)的子list
lst = [lst[i:i + col] for i in range(0, len(lst), col)]
# 原網(wǎng)頁中打開'詳細(xì)'鏈接可以查看更詳細(xì)的數(shù)據(jù),這里我們把url提取出來,方便后期查看
lst_link = []
links = element.find_elements_by_css_selector('#dt_1 a.red')
for link in links:
url = link.get_attribute('href')
lst_link.append(url)
lst_link = pd.Series(lst_link)
# list轉(zhuǎn)為dataframe
df_table = pd.DataFrame(lst)
# 添加url列
df_table['url'] = lst_link
print(df_table.head()) # 查看DataFrame

這里,要將list分割為子list,只需要確定表格有多少列即可,然后將每相隔這么多數(shù)量的值劃分為一個(gè)子list。如果我們數(shù)一下該表的列數(shù),可以發(fā)現(xiàn)一共有16列。但是這里不能使用這個(gè)數(shù)字,因?yàn)槌死麧櫛恚渌麍?bào)表的列數(shù)并不是16,所以當(dāng)后期爬取其他表格可能就會(huì)報(bào)錯(cuò)。這里仍然通過find_elements_by_css_selector方法,定位首行td節(jié)點(diǎn)的數(shù)量,便可獲得表格的列數(shù),然后將list拆分為對應(yīng)列數(shù)的子list。同時(shí),原網(wǎng)頁中打開”詳細(xì)”列的鏈接可以查看更詳細(xì)的數(shù)據(jù),這里我們把url提取出來,并增加一列到DataFrame中,方便后期查看。打印查看一下輸出結(jié)果:

可以看到,表格所有的數(shù)據(jù)我們都抓取到了,下面只需要進(jìn)行分頁循環(huán)爬取就行了。

這里,沒有抓取表頭是因?yàn)楸眍^有合并單元格,處理起來就非常麻煩。建議表格抓取下來后,在excel中復(fù)制表頭進(jìn)去就行了。如果,實(shí)在想要用代碼完成,可以參考這篇文章:https://blog.csdn.net/weixin_39461443/article/details/75456962

4.3. 分頁爬取

上面完成了單頁表格的爬取,下面我們來實(shí)現(xiàn)分頁爬取。

首先,我們先實(shí)現(xiàn)Selenium模擬翻頁跳轉(zhuǎn)操作,成功后再爬取每頁的表格內(nèi)容。

from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time

browser = webdriver.Chrome()
browser.maximize_window() # 最大化窗口,可以選擇設(shè)置
wait = WebDriverWait(browser, 10)
def index_page(page):
try:
browser.get('http://data.eastmoney.com/bbsj/201806/lrb.html')
print('正在爬取第: %s 頁' % page)
wait.until(
EC.presence_of_element_located((By.ID, 'dt_1')))
# 判斷是否是第1頁,如果大于1就輸入跳轉(zhuǎn),否則等待加載完成。
if page > 1:
# 確定頁數(shù)輸入框
input = wait.until(EC.presence_of_element_located(
(By.XPATH, '//*[@id='PageContgopage']')))
input.click()
input.clear()
input.send_keys(page)
submit = wait.until(EC.element_to_be_clickable(
(By.CSS_SELECTOR, '#PageCont > a.btn_link')))
submit.click()
time.sleep(2)
# 確認(rèn)成功跳轉(zhuǎn)到輸入框中的指定頁
wait.until(EC.text_to_be_present_in_element(
(By.CSS_SELECTOR, '#PageCont > span.at'), str(page)))
except Exception:
return None

def main():
for page in range(1,5): # 測試翻4頁
index_page(page)
if __name__ == '__main__':
main()

這里,我們先加載了相關(guān)包,使用WebDriverWait對象,設(shè)置最長10s的顯式等待時(shí)間,以便網(wǎng)頁加載出表格。判斷表格是否加載出來,用到了EC.presence_of_element_located條件。表格加載出來后,設(shè)置一個(gè)頁面判斷,如果在第1頁就等待頁面加載完成,如果大于第1頁就開始跳轉(zhuǎn)。

要完成跳轉(zhuǎn)操作,我們需要通過獲取輸入框input節(jié)點(diǎn),然后用clear()方法清空輸入框,再通過send_keys()方法填寫相應(yīng)的頁碼,接著通過submit.click()方法擊下一頁完成翻頁跳轉(zhuǎn)。

這里,我們測試一下前4頁跳轉(zhuǎn)效果,可以看到網(wǎng)頁成功跳轉(zhuǎn)了。下面就可以對每一頁應(yīng)用第一頁爬取表格內(nèi)容的方法,抓取每一頁的表格,轉(zhuǎn)為DataFrame然后存儲(chǔ)到csv文件中去。

http://media2./selenium%E5%88%86%E9%A1%B5%E5%8E%8B%E7%BC%A9.gif

4.4. 通用爬蟲構(gòu)造

上面,我們完成了2018年中報(bào)利潤表: http://data.eastmoney.com/bbsj/201806/lrb.html,一個(gè)網(wǎng)頁表格的爬取。但如果我們想爬取任意時(shí)期、任意一張報(bào)表的表格,比如2017年3季度的利潤表、2016年全年的業(yè)績報(bào)表、2015年1季度的現(xiàn)金流量表等等。上面的代碼就行不通了,下面我們對代碼進(jìn)行一下改造,變成更通用的爬蟲。從圖中可以看到,東方財(cái)富網(wǎng)年報(bào)季報(bào)有7張表格,財(cái)務(wù)報(bào)表最早從2007年開始每季度一次。基于這兩個(gè)維度,可重新構(gòu)造url的形式,然后爬取表格數(shù)據(jù)。下面,我們用代碼進(jìn)行實(shí)現(xiàn):

# 重構(gòu)url
# 1 設(shè)置財(cái)務(wù)報(bào)表獲取時(shí)期
year = int(float(input('請輸入要查詢的年份(四位數(shù)2007-2018): ')))
# int表示取整,里面加float是因?yàn)檩斎氲氖莝tr,直接int會(huì)報(bào)錯(cuò),float則不會(huì)
while (year < 2007 or year > 2018):
year = int(float(input('年份數(shù)值輸入錯(cuò)誤,請重新輸入:')))
quarter = int(float(input('請輸入小寫數(shù)字季度(1:1季報(bào),2-年中報(bào),3:3季報(bào),4-年報(bào)): ')))
while (quarter < 1 or quarter > 4):
quarter = int(float(input('季度數(shù)值輸入錯(cuò)誤,請重新輸入: ')))
# 轉(zhuǎn)換為所需的quarter 兩種方法,2表示兩位數(shù),0表示不滿2位用0補(bǔ)充
quarter = '{:02d}'.format(quarter * 3)
# quarter = '%02d' %(int(month)*3)
date = '{}{}' .format(year, quarter)

# 2 設(shè)置財(cái)務(wù)報(bào)表種類
tables = int(
input('請輸入查詢的報(bào)表種類對應(yīng)的數(shù)字(1-業(yè)績報(bào)表;2-業(yè)績快報(bào)表:3-業(yè)績預(yù)告表;4-預(yù)約披露時(shí)間表;5-資產(chǎn)負(fù)債表;6-利潤表;7-現(xiàn)金流量表): '))
dict_tables = {1: '業(yè)績報(bào)表', 2: '業(yè)績快報(bào)表', 3: '業(yè)績預(yù)告表',
4: '預(yù)約披露時(shí)間表', 5: '資產(chǎn)負(fù)債表', 6: '利潤表', 7: '現(xiàn)金流量表'}
dict = {1: 'yjbb', 2: 'yjkb/13', 3: 'yjyg',
4: 'yysj', 5: 'zcfz', 6: 'lrb', 7: 'xjll'}
category = dict[tables]

# 3 設(shè)置url
url = 'http://data.eastmoney.com/{}/{}/{}.html' .format('bbsj', date, category)
print(url) # 測試輸出的url

經(jīng)過上面的設(shè)置,我們通過輸入想要獲得指定時(shí)期、制定財(cái)務(wù)報(bào)表類型的數(shù)值,就能返回相應(yīng)的url鏈接。將該鏈接應(yīng)用到前面的爬蟲中,就可以爬取相應(yīng)的報(bào)表內(nèi)容了。

另外,除了從第一頁開始爬取到最后一頁的結(jié)果以外,我們還可以自定義設(shè)置想要爬取的頁數(shù)。比如起始頁數(shù)從第1頁開始,然后爬取10頁。

# 4 選擇爬取頁數(shù)范圍
start_page = int(input('請輸入下載起始頁數(shù):\n'))
nums = input('請輸入要下載的頁數(shù),(若需下載全部則按回車):\n')
# 確定網(wǎng)頁中的最后一頁
browser.get(url)
# 確定最后一頁頁數(shù)不直接用數(shù)字而是采用定位,因?yàn)椴煌瑫r(shí)間段的頁碼會(huì)不一樣
try:
page = browser.find_element_by_css_selector('.next+ a') # next節(jié)點(diǎn)后面的a節(jié)點(diǎn)
except:
page = browser.find_element_by_css_selector('.at+ a')
else:
print('沒有找到該節(jié)點(diǎn)')
# 上面用try.except是因?yàn)榻^大多數(shù)頁碼定位可用'.next+ a',但是業(yè)績快報(bào)表有的只有2頁,無'.next+ a'節(jié)點(diǎn)
end_page = int(page.text)

if nums.isdigit():
end_page = start_page + int(nums)
elif nums == '':
end_page = end_page
else:
print('頁數(shù)輸入錯(cuò)誤')
# 輸入準(zhǔn)備下載表格類型
print('準(zhǔn)備下載:{}-{}' .format(date, dict_tables[tables]))

經(jīng)過上面的設(shè)置,我們就可以實(shí)現(xiàn)自定義時(shí)期和財(cái)務(wù)報(bào)表類型的表格爬取了,將代碼再稍微整理一下,可實(shí)現(xiàn)下面的爬蟲效果:

視頻截圖:

視頻地址:https://v.qq.com/x/page/y07335thsn2.html

背景中類似黑客帝國的代碼雨效果,其實(shí)是動(dòng)態(tài)網(wǎng)頁效果。素材來源于下面這個(gè)網(wǎng)站,該網(wǎng)站還有很多酷炫的動(dòng)態(tài)背景可以下載下來。

http://wallpaper./store/paperDetail-1783830052.htm

4.5. 完整代碼

整個(gè)爬蟲的完整代碼如下所示:

from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time
import pandas as pd
import os

# 先chrome,后phantomjs
# browser = webdriver.Chrome()
# 添加無頭headlesss
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
browser = webdriver.Chrome(chrome_options=chrome_options)

# browser = webdriver.PhantomJS() # 會(huì)報(bào)警高提示不建議使用phantomjs,建議chrome添加無頭
browser.maximize_window() # 最大化窗口
wait = WebDriverWait(browser, 10)

def index_page(page):
try:
print('正在爬取第: %s 頁' % page)
wait.until(
EC.presence_of_element_located((By.ID, 'dt_1')))
# 判斷是否是第1頁,如果大于1就輸入跳轉(zhuǎn),否則等待加載完成。
if page > 1:
# 確定頁數(shù)輸入框
input = wait.until(EC.presence_of_element_located(
(By.XPATH, '//*[@id='PageContgopage']')))
input.click()
input.clear()
input.send_keys(page)
submit = wait.until(EC.element_to_be_clickable(
(By.CSS_SELECTOR, '#PageCont > a.btn_link')))
submit.click()
time.sleep(2)
# 確認(rèn)成功跳轉(zhuǎn)到輸入框中的指定頁
wait.until(EC.text_to_be_present_in_element(
(By.CSS_SELECTOR, '#PageCont > span.at'), str(page)))
except Exception:
return None

def parse_table():
# 提取表格第一種方法
# element = wait.until(EC.presence_of_element_located((By.ID, 'dt_1')))
# 第二種方法
element = browser.find_element_by_css_selector('#dt_1')

# 提取表格內(nèi)容td
td_content = element.find_elements_by_tag_name('td')
lst = []
for td in td_content:
# print(type(td.text)) # str
lst.append(td.text)

# 確定表格列數(shù)
col = len(element.find_elements_by_css_selector('tr:nth-child(1) td'))
# 通過定位一行td的數(shù)量,可獲得表格的列數(shù),然后將list拆分為對應(yīng)列數(shù)的子list
lst = [lst[i:i + col] for i in range(0, len(lst), col)]

# 原網(wǎng)頁中打開'詳細(xì)'鏈接,可以查看更詳細(xì)的數(shù)據(jù),這里我們把url提取出來,方便后期查看
lst_link = []
links = element.find_elements_by_css_selector('#dt_1 a.red')
for link in links:
url = link.get_attribute('href')
lst_link.append(url)

lst_link = pd.Series(lst_link)
# list轉(zhuǎn)為dataframe
df_table = pd.DataFrame(lst)
# 添加url列
df_table['url'] = lst_link

# print(df_table.head())
return df_table

# 寫入文件
def write_to_file(df_table, category):
# 設(shè)置文件保存在D盤eastmoney文件夾下
file_path = 'D:\\eastmoney'
if not os.path.exists(file_path):
os.mkdir(file_path)
os.chdir(file_path)
df_table.to_csv('{}.csv' .format(category), mode='a',
encoding='utf_8_sig', index=0, header=0)

# 設(shè)置表格獲取時(shí)間、類型
def set_table():
print('*' * 80)
print('\t\t\t\t東方財(cái)富網(wǎng)報(bào)表下載')
print('作者:高級(jí)農(nóng)民工 2018.10.6')
print('--------------')

# 1 設(shè)置財(cái)務(wù)報(bào)表獲取時(shí)期
year = int(float(input('請輸入要查詢的年份(四位數(shù)2007-2018):\n')))
# int表示取整,里面加float是因?yàn)檩斎氲氖莝tr,直接int會(huì)報(bào)錯(cuò),float則不會(huì) # https:///questions/1841565/valueerror-invalid-literal-for-int-with-base-10 while (year < 2007 or year > 2018): year = int(float(input('年份數(shù)值輸入錯(cuò)誤,請重新輸入:\n'))) quarter = int(float(input('請輸入小寫數(shù)字季度(1:1季報(bào),2-年中報(bào),3:3季報(bào),4-年報(bào)):\n'))) while (quarter < 1 or quarter > 4): quarter = int(float(input('季度數(shù)值輸入錯(cuò)誤,請重新輸入:\n'))) # 轉(zhuǎn)換為所需的quarter 兩種方法,2表示兩位數(shù),0表示不滿2位用0補(bǔ)充, # http://www.runoob.com/python/att-string-format.html quarter = '{:02d}'.format(quarter * 3) # quarter = '%02d' %(int(month)*3) date = '{}{}' .format(year, quarter) # print(date) 測試日期 ok # 2 設(shè)置財(cái)務(wù)報(bào)表種類 tables = int( input('請輸入查詢的報(bào)表種類對應(yīng)的數(shù)字(1-業(yè)績報(bào)表;2-業(yè)績快報(bào)表:3-業(yè)績預(yù)告表;4-預(yù)約披露時(shí)間表;5-資產(chǎn)負(fù)債表;6-利潤表;7-現(xiàn)金流量表): \n')) dict_tables = {1: '業(yè)績報(bào)表', 2: '業(yè)績快報(bào)表', 3: '業(yè)績預(yù)告表', 4: '預(yù)約披露時(shí)間表', 5: '資產(chǎn)負(fù)債表', 6: '利潤表', 7: '現(xiàn)金流量表'} dict = {1: 'yjbb', 2: 'yjkb/13', 3: 'yjyg', 4: 'yysj', 5: 'zcfz', 6: 'lrb', 7: 'xjll'} category = dict[tables] # 3 設(shè)置url # url = 'http://data.eastmoney.com/bbsj/201803/lrb.html' eg. url = 'http://data.eastmoney.com/{}/{}/{}.html' .format( 'bbsj', date, category) # # 4 選擇爬取頁數(shù)范圍 start_page = int(input('請輸入下載起始頁數(shù):\n')) nums = input('請輸入要下載的頁數(shù),(若需下載全部則按回車):\n') print('*' * 80) # 確定網(wǎng)頁中的最后一頁 browser.get(url) # 確定最后一頁頁數(shù)不直接用數(shù)字而是采用定位,因?yàn)椴煌瑫r(shí)間段的頁碼會(huì)不一樣 try: page = browser.find_element_by_css_selector('.next+ a') # next節(jié)點(diǎn)后面的a節(jié)點(diǎn) except: page = browser.find_element_by_css_selector('.at+ a') # else: # print('沒有找到該節(jié)點(diǎn)') # 上面用try.except是因?yàn)榻^大多數(shù)頁碼定位可用'.next+ a',但是業(yè)績快報(bào)表有的只有2頁,無'.next+ a'節(jié)點(diǎn) end_page = int(page.text) if nums.isdigit(): end_page = start_page + int(nums) elif nums == '': end_page = end_page else: print('頁數(shù)輸入錯(cuò)誤') # 輸入準(zhǔn)備下載表格類型 print('準(zhǔn)備下載:{}-{}' .format(date, dict_tables[tables])) print(url) yield{ 'url': url, 'category': dict_tables[tables], 'start_page': start_page, 'end_page': end_page }def main(category, page): try: index_page(page) # parse_table() #測試print df_table = parse_table() write_to_file(df_table, category) print('第 %s 頁抓取完成' % page) print('--------------') except Exception: print('網(wǎng)頁爬取失敗,請檢查網(wǎng)頁中表格內(nèi)容是否存在')# 單進(jìn)程if __name__ == '__main__': for i in set_table(): # url = i.get('url') category = i.get('category') start_page = i.get('start_page') end_page = i.get('end_page') for page in range(start_page, end_page): # for page in range(44,pageall+1): # 如果下載中斷,可以嘗試手動(dòng)更改網(wǎng)頁繼續(xù)下載 main(category, page) print('全部抓取完成')

這里,我下載了所有上市公司的部分報(bào)表。

2018年中報(bào)業(yè)績報(bào)表:

2017年報(bào)的利潤表:

如果你想下載更多的報(bào)表,可以使用文中的代碼,代碼和素材資源可以在下面的鏈接中獲?。?/p>

https://github.com/makcyun/eastmoney_spider

另外,爬蟲還可以再完善一下,比如增加爬取上市公司的公告信息,設(shè)置可以爬任意一家(數(shù)家/行業(yè))的公司數(shù)據(jù)而不用全部。

還有一個(gè)問題是,Selenium爬取的速度很慢而且很占用內(nèi)存,建議盡量先嘗試采用Requests請求的方法,抓不到的時(shí)候再考慮這個(gè)。文章開頭在進(jìn)行網(wǎng)頁分析的時(shí)候,我們初步分析了表格JS的請求數(shù)據(jù),是否能從該請求中找到我們需要的表格數(shù)據(jù)呢? 后續(xù)文章,我們換一個(gè)思路再來嘗試爬取一次。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多