自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

用Python爬取金融市場數(shù)據(jù)

開發(fā) 后端 大數(shù)據(jù)
本文結(jié)合正則表達式和比較流行的beautifulsoup(bs4),對網(wǎng)頁進行解析并提取數(shù)據(jù),因此在正式進行之前,有必要簡單介紹下正則表達式和bs4.

一、寫在前面

由于在平時的工作中,需要對某信托網(wǎng)的信托在售和資管在售數(shù)據(jù)進行統(tǒng)計分析,但是一條一條的輸入,顯然太過耗時耗力,于是萌生了寫個爬蟲的想法。

一門計算機語言,可以當做是在模仿人的目的或意圖來進行一系列行為或動作,所以在寫代碼之前,首先要弄清楚你要干什么,如果是你,你每一步的動作是什么,然后將這一步步的動作通過代碼傳遞給計算機,讓計算機高效的幫你完成即可。

本文結(jié)合正則表達式和比較流行的beautifulsoup(bs4),對網(wǎng)頁進行解析并提取數(shù)據(jù),因此在正式進行之前,有必要簡單介紹下正則表達式和bs4.

二、基礎知識

1、正則表達式

具體的詳細介紹可自行去網(wǎng)上補知識,這里只介紹一些規(guī)則和常用的用法。

  1. # 正則表達式 
  2. 規(guī)則: 
  3.     單字符: 
  4.             .  : 除換行以外所有字符 
  5.             [] : 匹配集合中任意一個字符 
  6.             \d : 數(shù)字 
  7.             \D : 非數(shù)字 
  8.             \w : 數(shù)字、字母、下劃線、中文 
  9.             \W : 非數(shù)字、字母、下劃線、中文 
  10.             \s : 空格 
  11.             \S : 非空格 
  12.     數(shù)量修飾: 
  13.              * : 任意多次 
  14.              + : 至少1次 
  15.              ?: 非貪婪方式,可有可無 
  16.            {m} : 固定m次 
  17.           {m+} : 至少m次 
  18.          {m,n} : m到n次 
  19.     起始: 
  20.              ^ : 以啥啥開頭 
  21.              $ : 以啥啥結(jié)尾 
  22.     常用組合和函數(shù): 
  23.             .* : 貪婪方式任意字符任意次數(shù) 
  24.            .*? : 非貪婪方式任意字符任意次數(shù) 
  25.            r = re.compile(r'正則表達式',re.S) :  
  26.                               最常用:將規(guī)則傳遞給某個參數(shù)以便反復使用 
  27.            re.match\re.search\(字符串) 
  28.            re.findall(字符串) 
  29.            re.sub(正則表達式,替換內(nèi)容,字符串) 

2、bs4

同樣,詳細知識自行補,這里只介紹常用的用法:select結(jié)合選擇器的用法。

  1. # bs4用法 
  2. 首先加載里面的BeautifulSoup: 
  3. from bs4 import BeautifulSoup 
  4. soup = BeautifulSoup('網(wǎng)頁響應回來的東西'

主要有以下幾種提取規(guī)則:

  1. 1、獲取標簽 
  2.     soup.a   獲取a標簽(***個) 
  3. 2、獲取屬性 
  4.     soup.a.attrs   獲取a標簽下所有的屬性和值,返回的是字典 
  5.     soup.a['name'] 獲取a標簽下的name屬性 
  6. 3、獲取內(nèi)容 
  7.     soup.a.string() 
  8.     soup.a.text()   建議使用這個 
  9. 4、find用法 
  10.     soup.find('a')  找到***個a 
  11.     soup.find('a',title='')  附加條件的查找 
  12. 5、find_all用法 
  13.     soup.find_all('a')  找到所有a 
  14.     soup.find_all(['a','b']) 找到所有a和b 
  15.     soup.find_all('a',limit=5) 找到前5個a 
  16. 6、select用法——重點 
  17.     結(jié)合選擇器使用,常用的選擇器如下: 
  18.     標簽選擇器:如div表示為div 
  19.     類選擇器:.表示,如class = 'you'表示為.you 
  20.     id選擇器:#表示,如id = 'me'表示為#me  
  21.    組合選擇器:如div,.you,#me    
  22.    層級選擇器:如div .you #me表示選取div標簽下的you類下的id為me的內(nèi)容 
  23.               再如div > .you > #me,> 則表示只能是下面一級 

三、開始實戰(zhàn)——爬取某信托網(wǎng)的信托在售數(shù)據(jù)

1、爬取前的準備工作——梳理好代碼的邏輯

正如前面所說,寫代碼之前,首先要清楚你想要干什么,如果是你,你是什么樣的動作來達到你的這個目的或意圖。

***,你的目的或意圖是什么,對于本例而言,我需要獲取任意某頁至某頁信托在售產(chǎn)品的下面數(shù)據(jù):產(chǎn)品名稱、發(fā)行機構(gòu)、發(fā)行時間、***收益、產(chǎn)品期限、投資行業(yè)、發(fā)行地、收益分配方式、發(fā)行規(guī)模、***收益、***收益和利率等級劃分情況這12個數(shù)據(jù)。

第二,如果是人,需要哪些動作來達到這個目的。我們來看下網(wǎng)頁。動作就清晰了:

輸入網(wǎng)址/搜索關鍵字 > 進入網(wǎng)站 > 點擊紅色框框里的信托產(chǎn)品和在售 > 錄入下面綠色框框里的相關信息 > 發(fā)現(xiàn)信息不全,再點擊這個產(chǎn)品,在詳情頁(再下一張圖)繼續(xù)錄入。

用Python爬取金融市場數(shù)據(jù)

用Python爬取金融市場數(shù)據(jù)

2、開始爬取

既然動作清晰了,那就可以讓計算機來模擬人的這個動作進行爬取了。

然后就是寫代碼的邏輯了。我們用做數(shù)學題常用的倒推法來梳理這個過程。

要想獲取數(shù)據(jù) < 你得解析網(wǎng)頁給你的響應 < 你得有個響應 < 你得發(fā)送請求 < 你得有個請求request < 你得有個url。

然后我們再正過來解題:獲取url > 構(gòu)建request > 發(fā)送請求 > 獲取響應 > 解析響應 > 獲取所需數(shù)據(jù) > 保存數(shù)據(jù)。

所以按照這個步驟,我們可以先做出一個大框架,然后在框架的基礎上補充血肉。大框架,就是定義個主函數(shù)。

值得注意的是,本例中,每個產(chǎn)品的信息獲取,我們都有二次點擊的動作,即***頁數(shù)據(jù)不全,我們再點擊進入詳情頁進行剩余數(shù)據(jù)的獲取,因此,本例是有兩層的數(shù)據(jù)獲取過程的。***層使用正則表達式,第二層使用bs4。

① 定義主函數(shù)

如下是這個主函數(shù),前面的寫入相關數(shù)據(jù)你可以先不管,這都是在***步的獲取url時,后補過來的。

回到前面的目的:提取任意某頁至任意某頁的數(shù)據(jù),所以寫個循環(huán)是必須的,然后在循環(huán)下方,兩層網(wǎng)頁的數(shù)據(jù)獲取框架就出來了。(由于第二層網(wǎng)頁的url是根據(jù)***層網(wǎng)頁的某個數(shù)據(jù)拼接出來的,而***層網(wǎng)頁是一下子提取整個頁面所有產(chǎn)品的信息,所以第二層網(wǎng)頁的提取也設置了個循環(huán),對***層網(wǎng)頁的所有產(chǎn)品,一個一個點進去進行提取)

  1. # 定義一個主函數(shù) 
  2. def main(): 
  3.  
  4.     # 寫入相關數(shù)據(jù) 
  5.     url_1 = 'http://www.某信托網(wǎng).com/Action/ProductAJAX.ashx?' 
  6.     url_2 = 'http://www.某信托網(wǎng)/Product/Detail.aspx?' 
  7.     size = input('請輸入每頁顯示數(shù)量:'
  8.     start_page = int(input('請輸入起始頁碼:')) 
  9.     end_page = int(input('請輸入結(jié)束頁碼')) 
  10.     type = input('請輸入產(chǎn)品類型(1代表信托,2代表資管):')   
  11.     items = []                # 定義一個空列表用來存儲數(shù)據(jù) 
  12.  
  13.     # 寫循環(huán)爬取每一頁 
  14.     for page in range(start_page, end_page + 1): 
  15.  
  16.     # ***層網(wǎng)頁的爬取流程 
  17.         print('第{}頁開始爬取'.format(page)) 
  18.  
  19.         # 1、拼接url——可定義一個分函數(shù)1:joint 
  20.         url_new = joint(url_1 ,size=size ,page=page ,type=type) 
  21.  
  22.         # 2、發(fā)起請求,獲取響應——可定義一個分函數(shù)2:que_res 
  23.         response = que_res(url_new) 
  24.  
  25.         # 3、解析內(nèi)容,獲取所需數(shù)據(jù)——可定義一個分函數(shù)3:parse_content_1 
  26.         contents = parse_content_1(response) 
  27.  
  28.         # 4、休眠2秒 
  29.         time.sleep(2) 
  30.  
  31.     # 第二層網(wǎng)頁的爬取流程 
  32.  
  33.         for content in contents: 
  34.             print('    第{}頁{}開始下載'.format(page ,content[0])) 
  35.  
  36.             # 1、拼接url 
  37.             id = content[0] 
  38.             url_2_new = joint(url_2 ,id=id)      # joint為前面定義的第1個函數(shù) 
  39.  
  40.             # 2、發(fā)起請求,獲取響應 
  41.             response_2 = que_res(url_2_new)     # que_res為前面定義的第2個函數(shù) 
  42.  
  43.             # 3、解析內(nèi)容,獲取所需數(shù)據(jù)——可定義一個分函數(shù)4:parse_content_2,直接返回字典格式的數(shù)據(jù) 
  44.             item = parse_content_2(response_2 ,content) 
  45.  
  46.             # 存儲數(shù)據(jù) 
  47.             items.append(item) 
  48.             print('    第{}頁{}結(jié)束下載'.format(page ,content[0])) 
  49.  
  50.             # 休眠5秒 
  51.             time.sleep(5) 
  52.  
  53.         print('第{}頁結(jié)束爬取'.format(page)) 
  54.  
  55.     # 保存數(shù)據(jù)為dataframe格式CSV文件 
  56.     df = pd.DataFrame(items) 
  57.     df.to_csv('data.csv' ,index=False ,sep=',' ,encoding='utf-8-sig'
  58.  
  59.    print('*'*30) 
  60.    print('全部爬取結(jié)束'
  61.  
  62. if __name__ == '__main__'
  63.     main() 

② 獲取url —— ***層和第二層通用

由于我們需要訪問兩層的數(shù)據(jù),所以希望定義一個函數(shù),能對兩層的URL都可以進行拼接。

如下圖為***層頁面的內(nèi)容和源碼,由第二個紅框中的內(nèi)容(X-Requested-With:XMLHttpRequest),可知這是一個AJAX get請求,且攜帶者第三個紅框中的數(shù)據(jù),而第三個紅框中的數(shù)據(jù),又恰好是***個紅框中的url的一部分,即為:

http://www.某信托網(wǎng).com/Action/ProductAJAX.ashx?加上第三個紅框中的數(shù)據(jù)。

第三個框框中包括幾個可變的數(shù)據(jù):pageSize(表示一頁顯示多少產(chǎn)品);pageIndex(表示第幾頁);conditionStr(定義產(chǎn)品類型,1表示信托,2表示資管),其余的數(shù)據(jù)都是固定的(這其中有個_:1544925791285這種下劃線帶一串數(shù)字的東西,像是個隨機數(shù),去掉也沒影響,我就給去掉了)。

用Python爬取金融市場數(shù)據(jù)

下圖為第二層頁面的內(nèi)容和源碼,可見只是一個簡單的get請求,且網(wǎng)址很簡單,就是一個http://www.某信托網(wǎng).com/Product/Detail.aspx?加上一個id,而這個id又來自哪里呢,答案就在***層網(wǎng)頁的響應數(shù)據(jù)中(見再下面一幅圖的紅色框)。

用Python爬取金融市場數(shù)據(jù)

用Python爬取金融市場數(shù)據(jù)

通過上面的分析,***層網(wǎng)頁的請求url由一個固定的部分加上一些數(shù)據(jù),第二層網(wǎng)頁的url依賴于***層的數(shù)據(jù),我們先在主函數(shù)中將url_1、url_2和一些可變的數(shù)據(jù)寫入(見上面的主函數(shù)),然后定義一個函數(shù)用來拼接兩層的url即可,因為***層網(wǎng)頁url的固定部分長度為47,第二層的為43,這里使用一個長度條件來判斷是拼接***層還是拼接第二層。

  1. # 定義第1個分函數(shù)joint,用來拼接url 
  2. def joint(url,size=None,page=None,type=None,id=None): 
  3.     if len(url) > 45: 
  4.         condition = 'producttype:' + type + '|status:在售' 
  5.         data = { 
  6.         'mode''statistics'
  7.         'pageSize'size
  8.         'pageIndex': str(page), 
  9.         'conditionStr': condition, 
  10.         'start_released'''
  11.         'end_released'''
  12.         'orderStr''1'
  13.         'ascStr''ulup' 
  14.         } 
  15.         joint_str = urllib.parse.urlencode(data) 
  16.         url_new = url + joint_str 
  17.     else
  18.         data = { 
  19.             'id':id 
  20.             } 
  21.         joint_str = urllib.parse.urlencode(data) 
  22.         url_new = url + joint_str 
  23.     return url_new 

③ 構(gòu)建request + 獲取response一條龍 —— ***層和第二層通用

獲取url后,接下來就是構(gòu)建request用來發(fā)送請求獲取響應了,此處定義一個函數(shù)實現(xiàn)一條龍服務。

這里為了提防反爬,user_agent在多個里隨機選,并使用了代理池(雖然不多),并且我電腦端也進行了局域網(wǎng)ip代理。

  1. # 定義第2個函數(shù)que_res,用來構(gòu)建request發(fā)送請求,并返回響應response 
  2. def que_res(url): 
  3.  
  4.     # 構(gòu)建request的***步——構(gòu)建頭部:headers 
  5.     USER_AGENTS = [  
  6.         "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"
  7.         "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)"
  8.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"
  9.         "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
  10.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0)"
  11.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"
  12.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"
  13.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)"
  14.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser)"
  15.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"
  16.         ] 
  17.     user_agent = random.choice(USER_AGENTS) 
  18.     headers = { 
  19.         'Accept-Language''zh-CN,zh;q=0.8'
  20.         'Connection''keep-alive',  
  21.         'Host''www.某信托網(wǎng).com'
  22.         'Referer''http://www.某信托網(wǎng).com/Product/Index.aspx'
  23.         'User-Agent': user_agent, 
  24.         'X-Requested-With''XMLHttpRequest' 
  25.         } 
  26.  
  27.     # 構(gòu)建request的第二步——構(gòu)建request 
  28.     request = urllib.request.Request(url=url, headers=headers) 
  29.  
  30.  
  31.     # 發(fā)起請求的***步——構(gòu)建代理池 
  32.     proxy_list = [       
  33.         {'http':'125.40.29.100:8118'}, 
  34.         {'http':'14.118.135.10:808'
  35.         ] 
  36.     proxy = random.choice(proxy_list) 
  37.  
  38.     # 發(fā)起請求的第二步——創(chuàng)建handler和opener 
  39.     handler = urllib.request.ProxyHandler(proxy) 
  40.     opener = urllib.request.build_opener(handler) 
  41.  
  42.     # 發(fā)起請求的第三步——發(fā)起請求,獲取響應內(nèi)容并解碼 
  43.     response = opener.open(request).read().decode() 
  44.  
  45.     # 返回值 
  46.     return response 

④ 解析***層網(wǎng)頁的內(nèi)容

獲取響應之后就是解析并提取數(shù)據(jù)了,***層使用正則表達式的方法來進行。

獲取的response如下如:

用Python爬取金融市場數(shù)據(jù)

因此可寫出如下正則,從左到右分配匹配出ID、產(chǎn)品名稱、發(fā)行機構(gòu)、發(fā)行時間、產(chǎn)品期限、投資行業(yè)、首頁收益。

  1. # 定義第3個函數(shù)parse_content_1,用來解析并匹配***層網(wǎng)頁內(nèi)容,此處使用正則表達式方法 
  2. def parse_content_1(response): 
  3.  
  4.     # 寫正則進行所需數(shù)據(jù)的匹配 
  5.     re_1 = re.compile( 
  6.     r'{"ROWID".*?"ID":"(.*?)","Title":"(.*?)","producttype".*?"issuers":"(.*?)","released":"(.*?) 0:00:00","PeriodTo":(.*?),"StartPrice".*?"moneyinto":"(.*?)","EstimatedRatio1":(.*?),"status":.*?"}'
  7.     contents = re_1.findall(response) 
  8.     return contents 

⑤ 解析第二層網(wǎng)頁的內(nèi)容并輸出數(shù)據(jù)

第二層使用bs4中的select+選擇器的方法來進行。除了***層所提取的數(shù)據(jù)外,還需要發(fā)行地、收益分配方式、發(fā)行規(guī)模、***收益、***收益和利率等級分布情況。

網(wǎng)頁如下,可見,我們所需要的信息隱藏在一個又一個tr標簽里,而這個tr標簽處于id=“procon1”下的一個table標簽里(此處有個坑,就是從網(wǎng)頁來看,table下還有個tbody標簽,而實際得到的響應里并沒有)。

用Python爬取金融市場數(shù)據(jù)

由于我們不是所有的信息都要,所以我們可以一個一個的提取,最終輸出個數(shù)據(jù)。代碼如下(這中間用到了前面提到的選擇器知識和一些字符串處理方法):

  1. # 定義第4個函數(shù)parse_content_2,用來解析并匹配第二層網(wǎng)頁內(nèi)容,并輸出數(shù)據(jù),此處使用BeautifulSoup方法 
  2. def parse_content_2(response,content): 
  3.  
  4.     # 使用bs4進行爬取第二層信息 
  5.     soup = BeautifulSoup(response) 
  6.  
  7.     # 爬取發(fā)行地和收益分配方式,該信息位于id為procon1下的table下的第4個tr里 
  8.     tr_3 = soup.select('#procon1 > table > tr')[3] 
  9. address = tr_3.select('.pro-textcolor')[0].text 
  10. r_style = tr_3.select('.pro-textcolor')[1].text  
  11.  
  12.     # 爬取發(fā)行規(guī)模,該信息位于id為procon1下的table下的第5個tr里 
  13.     tr_4 = soup.select('#procon1 > table > tr')[4] 
  14. guimo = tr_4.select('.pro-textcolor')[1].text 
  15. re_2 = re.compile(r'.*?(\d+).*?', re.S)  
  16.     scale = re_2.findall(guimo)[0] 
  17.    # 爬取收益率,該信息位于id為procon1下的table下的第8個tr里 
  18.     tr_7 = soup.select('#procon1 > table > tr')[7] 
  19. rate = tr_7.select('.pro-textcolor')[0].text[:(-1)] 
  20. r = rate.split('至'
  21.   r_min = r[0] 
  22.     r_max = r[1] 
  23.  
  24.     # 提取利率等級 
  25.     tr_11 = soup.select('#procon1 > table > tr')[11] 
  26. r_grade = tr_11.select('p')[0].text 
  27.  
  28.     # 保存數(shù)據(jù)到一個字典中 
  29.     item = { 
  30.     '產(chǎn)品名稱':content[1], 
  31.     '發(fā)行機構(gòu)':content[2], 
  32.     '發(fā)行時間':content[3], 
  33.     '產(chǎn)品期限':content[4], 
  34.     '投資行業(yè)':content[5], 
  35.     '首頁收益':content[6], 
  36.     '發(fā)行地': address, 
  37.     '收益分配方式': r_style, 
  38.     '發(fā)行規(guī)模': scale, 
  39.     '***收益': r_min, 
  40.     '***收益': r_max, 
  41.     '利率等級': r_grade 
  42.     } 
  43.  
  44.     # 返回數(shù)據(jù) 
  45.     return item 

⑥ 保存數(shù)據(jù)到本地(以dataframe格式保存到本地CSV格式)

  1. # 保存數(shù)據(jù)為dataframe格式CSV文件 
  2.     df = pd.DataFrame(items) 
  3.     df.to_csv('data.csv',index=False,sep=',',encoding='utf-8-sig'
  4.  
  5. 好了,現(xiàn)在就大功告成了,***不要只讓自己爽,也要讓對方的服務器別太難過,在一些地方休眠幾秒,完整代碼如下。 
  6.  
  7. import urllib.request 
  8. import urllib.parse 
  9. import re 
  10. import random 
  11. from bs4 import BeautifulSoup 
  12. import pandas as pd 
  13. import time 
  14.  
  15. # 定義第1個分函數(shù)joint,用來拼接url 
  16. def joint(url,size=None,page=None,type=None,id=None): 
  17.     if len(url) > 45: 
  18.         condition = 'producttype:' + type + '|status:在售' 
  19.         data = { 
  20.         'mode''statistics'
  21.         'pageSize'size
  22.         'pageIndex': str(page), 
  23.         'conditionStr': condition, 
  24.         'start_released'''
  25.         'end_released'''
  26.         'orderStr''1'
  27.         'ascStr''ulup' 
  28.         } 
  29.         joint_str = urllib.parse.urlencode(data) 
  30.         url_new = url + joint_str 
  31.     else
  32.         data = { 
  33.             'id':id 
  34.             } 
  35.         joint_str = urllib.parse.urlencode(data) 
  36.         url_new = url + joint_str 
  37.     return url_new 
  38.  
  39. # 定義第2個函數(shù)que_res,用來構(gòu)建request發(fā)送請求,并返回響應response 
  40. def que_res(url): 
  41.  
  42.     # 構(gòu)建request的***步——構(gòu)建頭部:headers 
  43.     USER_AGENTS = [  
  44.         "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"
  45.         "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)"
  46.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"
  47.         "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
  48.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0)"
  49.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"
  50.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"
  51.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)"
  52.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser)"
  53.         "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"
  54.         ] 
  55.     user_agent = random.choice(USER_AGENTS) 
  56.     headers = { 
  57.         'Accept-Language''zh-CN,zh;q=0.8'
  58.         'Connection''keep-alive',  
  59.         'Host''www.某信托網(wǎng).com'
  60.         'Referer''http://www.某信托網(wǎng).com/Product/Index.aspx'
  61.         'User-Agent': user_agent, 
  62.         'X-Requested-With''XMLHttpRequest' 
  63.         } 
  64.  
  65.     # 構(gòu)建request的第二步——構(gòu)建request 
  66.     request = urllib.request.Request(url=url, headers=headers) 
  67.  
  68.  
  69.     # 發(fā)起請求的***步——構(gòu)建代理池 
  70.     proxy_list = [       
  71.         {'http':'125.40.29.100:8118'}, 
  72.         {'http':'14.118.135.10:808'
  73.         ] 
  74.     proxy = random.choice(proxy_list) 
  75.  
  76.     # 發(fā)起請求的第二步——創(chuàng)建handler和opener 
  77.     handler = urllib.request.ProxyHandler(proxy) 
  78.     opener = urllib.request.build_opener(handler) 
  79.  
  80.     # 發(fā)起請求的第三步——發(fā)起請求,獲取響應內(nèi)容并解碼 
  81.     response = opener.open(request).read().decode() 
  82.  
  83.     # 返回值 
  84.     return response 
  85.  
  86. # 定義第3個函數(shù)parse_content_1,用來解析并匹配***層網(wǎng)頁內(nèi)容,此處使用正則表達式方法 
  87. def parse_content_1(response): 
  88.  
  89.     # 寫正則進行所需數(shù)據(jù)的匹配 
  90.     re_1 = re.compile( 
  91.     r'{"ROWID".*?"ID":"(.*?)","Title":"(.*?)","producttype".*?"issuers":"(.*?)","released":"(.*?) 0:00:00","PeriodTo":(.*?),"StartPrice".*?"moneyinto":"(.*?)","EstimatedRatio1":(.*?),"status":.*?"}'
  92.     contents = re_1.findall(response) 
  93.     return contents 
  94.  
  95. # 定義第4個函數(shù)parse_content_2,用來解析并匹配第二層網(wǎng)頁內(nèi)容,并輸出數(shù)據(jù),此處使用BeautifulSoup方法 
  96. def parse_content_2(response,content): 
  97.  
  98.     # 使用bs4進行爬取第二層信息 
  99.     soup = BeautifulSoup(response) 
  100.  
  101.     # 爬取發(fā)行地和收益分配方式,該信息位于id為procon1下的table下的第4個tr里 
  102.     tr_3 = soup.select('#procon1 > table > tr')[3]         #select到第四個目標tr 
  103.     address = tr_3.select('.pro-textcolor')[0].text        #select到該tr下的class為pro-textcolor的***個內(nèi)容(發(fā)行地) 
  104.     r_style = tr_3.select('.pro-textcolor')[1].text        #select到該tr下的class為pro-textcolor的第二個內(nèi)容(收益分配方式) 
  105.  
  106.     # 爬取發(fā)行規(guī)模,該信息位于id為procon1下的table下的第5個tr里 
  107.     tr_4 = soup.select('#procon1 > table > tr')[4]         #select到第五個目標tr     
  108.     guimo = tr_4.select('.pro-textcolor')[1].text          #select到該tr下的class為pro-textcolor的第二個內(nèi)容(發(fā)行規(guī)模:至***萬) 
  109.     re_2 = re.compile(r'.*?(\d+).*?', re.S)                #設立一個正則表達式,將純數(shù)字提取出來 
  110.     scale = re_2.findall(guimo)[0]                         #提取出純數(shù)字的發(fā)行規(guī)模 
  111.  
  112.     # 爬取收益率,該信息位于id為procon1下的table下的第8個tr里 
  113.     tr_7 = soup.select('#procon1 > table > tr')[7]         #select到第八個目標tr 
  114.     rate = tr_7.select('.pro-textcolor')[0].text[:(-1)]    #select到該tr下的class為pro-textcolor的***個內(nèi)容(且通過下標[-1]將末尾的 % 去除) 
  115.     r = rate.split('至')                                   #此處用來提取***收益和***收益 
  116.     r_min = r[0] 
  117.     r_max = r[1] 
  118.  
  119.     # 提取利率等級 
  120.     tr_11 = soup.select('#procon1 > table > tr')[11]       #select到第十二個目標tr 
  121.     r_grade = tr_11.select('p')[0].text                    #select到該tr下的p下的***個內(nèi)容(即利率等級) 
  122.  
  123.     # 保存數(shù)據(jù)到一個字典中 
  124.     item = { 
  125.     '產(chǎn)品名稱':content[1], 
  126.     '發(fā)行機構(gòu)':content[2], 
  127.     '發(fā)行時間':content[3], 
  128.     '產(chǎn)品期限':content[4], 
  129.     '投資行業(yè)':content[5], 
  130.     '首頁收益':content[6], 
  131.     '發(fā)行地': address, 
  132.     '收益分配方式': r_style, 
  133.     '發(fā)行規(guī)模': scale, 
  134.     '***收益': r_min, 
  135.     '***收益': r_max, 
  136.     '利率等級': r_grade 
  137.     } 
  138.  
  139.     # 返回數(shù)據(jù) 
  140.     return item 
  141.  
  142. # 定義一個主函數(shù) 
  143. def main(): 
  144.  
  145.     # 寫入相關數(shù)據(jù) 
  146.     url_1 = 'http://www.某信托網(wǎng).com/Action/ProductAJAX.ashx?' 
  147.     url_2 = 'http://www.某信托網(wǎng).com/Product/Detail.aspx?' 
  148.     size = input('請輸入每頁顯示數(shù)量:'
  149.     start_page = int(input('請輸入起始頁碼:')) 
  150.     end_page = int(input('請輸入結(jié)束頁碼')) 
  151.     type = input('請輸入產(chǎn)品類型(1代表信托,2代表資管):')  
  152.     items = []                       # 定義一個空列表用來存儲數(shù)據(jù) 
  153.  
  154.     # 寫循環(huán)爬取每一頁 
  155.     for page in range(start_page, end_page + 1): 
  156.  
  157.         # ***層網(wǎng)頁的爬取流程 
  158.         print('第{}頁開始爬取'.format(page)) 
  159.         # 1、拼接url——可定義一個分函數(shù)1:joint 
  160.         url_new = joint(url_1,size=size,page=page,type=type) 
  161.  
  162.         # 2、發(fā)起請求,獲取響應——可定義一個分函數(shù)2:que_res 
  163.         response = que_res(url_new) 
  164.  
  165.         # 3、解析內(nèi)容,獲取所需數(shù)據(jù)——可定義一個分函數(shù)3:parse_content_1 
  166.         contents = parse_content_1(response) 
  167.  
  168.         # 4、休眠2秒 
  169.         time.sleep(2) 
  170.  
  171.         # 第二層網(wǎng)頁的爬取流程 
  172.  
  173.         for content in contents: 
  174.             print('    第{}頁{}開始下載'.format(page,content[0])) 
  175.             # 1、拼接url 
  176.             id = content[0] 
  177.             url_2_new = joint(url_2,id=id)      # joint為前面定義的第1個函數(shù) 
  178.  
  179.             # 2、發(fā)起請求,獲取響應 
  180.             response_2 = que_res(url_2_new)     # que_res為前面定義的第2個函數(shù) 
  181.  
  182.             # 3、解析內(nèi)容,獲取所需數(shù)據(jù)——可定義一個分函數(shù)4:parse_content_2,直接返回字典格式的數(shù)據(jù) 
  183.             item = parse_content_2(response_2,content) 
  184.  
  185.             # 存儲數(shù)據(jù) 
  186.             items.append(item) 
  187.             print('    第{}頁{}結(jié)束下載'.format(page,content[0])) 
  188.             # 休眠5秒 
  189.             time.sleep(5) 
  190.  
  191.         print('第{}頁結(jié)束爬取'.format(page)) 
  192.  
  193.  
  194.     # 保存數(shù)據(jù)為dataframe格式CSV文件 
  195.     df = pd.DataFrame(items) 
  196.     df.to_csv('data.csv',index=False,sep=',',encoding='utf-8-sig'
  197.  
  198.     print('*'*30) 
  199.     print('全部爬取結(jié)束'
  200.  
  201. if __name__ == '__main__'
  202.     main() 

3、爬取結(jié)果

運行代碼,這里以每頁顯示4個產(chǎn)品,爬取前3頁的信托在售為例,運行結(jié)果如下:

用Python爬取金融市場數(shù)據(jù)

然后打開存到本地的CSV文件如下:結(jié)果是美好的。

 

用Python爬取金融市場數(shù)據(jù)

這種兩層網(wǎng)頁的數(shù)據(jù)抓取,可以用在非常非常非常多的地方呦。

責任編輯:未麗燕 來源: 鼻歌三丁燕尾斬
相關推薦

2023-07-10 16:01:56

2022-05-19 14:27:44

人工智能金融市場基金

2018-03-07 17:00:51

2020-06-23 16:49:57

云計算金融市場云端

2018-07-30 17:34:15

華為

2012-04-19 14:44:45

梭子魚備份服務系統(tǒng)

2011-12-29 14:30:09

云計算

2020-11-03 14:10:45

Python爬取天氣爬蟲

2021-08-20 15:54:11

數(shù)字人民幣支付寶微信

2017-07-05 11:53:45

民生銀行互聯(lián)網(wǎng)消費金融

2022-01-07 16:40:07

區(qū)塊鏈證券數(shù)據(jù)

2018-01-09 14:19:14

PythonAndroid爬蟲

2021-04-30 10:24:49

量子計算芯片超算

2022-07-12 09:55:34

Selenium爬取數(shù)據(jù)

2015-05-11 17:13:26

2019-01-11 10:22:31

Python數(shù)據(jù)爬取

2022-01-20 16:42:10

加密貨幣比特幣數(shù)字資產(chǎn)

2012-02-27 17:37:34

投資

2016-12-07 11:18:58

Python爬蟲網(wǎng)站

2017-05-24 15:07:19

Python爬蟲爬取
點贊
收藏

51CTO技術棧公眾號