|
|
51CTO旗下网站
|
|
移动端

用Python爬取金融市场数据

本文结合正则表达式和比较流行的beautifulsoup(bs4),对网页进行解析并提取数据,因此在正式进行之前,有必要简单介绍下正则表达式和bs4.

作者:隠塵退士来源:鼻歌三丁燕尾斩|2019-01-02 12:23

【大咖·来了 第7期】10月24日晚8点观看《智能导购对话机器人实践》

一、写在前面

由于在平时的工作中,需要对某信托网的信托在售和资管在售数据进行统计分析,但是一条一条的输入,显然太过耗时耗力,于是萌生了写个爬虫的想法。

一门计算机语言,可以当做是在模仿人的目的或意图来进行一系列行为或动作,所以在写代码之前,首先要弄清楚你要干什么,如果是你,你每一步的动作是什么,然后将这一步步的动作通过代码传递给计算机,让计算机高效的帮你完成即可。

本文结合正则表达式和比较流行的beautifulsoup(bs4),对网页进行解析并提取数据,因此在正式进行之前,有必要简单介绍下正则表达式和bs4.

二、基础知识

1、正则表达式

具体的详细介绍可自行去网上补知识,这里只介绍一些规则和常用的用法。

  1. # 正则表达式 
  2. 规则: 
  3.     单字符: 
  4.             .  : 除换行以外所有字符 
  5.             [] : 匹配集合中任意一个字符 
  6.             \d : 数字 
  7.             \D : 非数字 
  8.             \w : 数字、字母、下划线、中文 
  9.             \W : 非数字、字母、下划线、中文 
  10.             \s : 空格 
  11.             \S : 非空格 
  12.     数量修饰: 
  13.              * : 任意多次 
  14.              + : 至少1次 
  15.              ?: 非贪婪方式,可有可无 
  16.            {m} : 固定m次 
  17.           {m+} : 至少m次 
  18.          {m,n} : m到n次 
  19.     起始: 
  20.              ^ : 以啥啥开头 
  21.              $ : 以啥啥结尾 
  22.     常用组合和函数: 
  23.             .* : 贪婪方式任意字符任意次数 
  24.            .*? : 非贪婪方式任意字符任意次数 
  25.            r = re.compile(r'正则表达式',re.S) :  
  26.                               最常用:将规则传递给某个参数以便反复使用 
  27.            re.match\re.search\(字符串) 
  28.            re.findall(字符串) 
  29.            re.sub(正则表达式,替换内容,字符串) 

2、bs4

同样,详细知识自行补,这里只介绍常用的用法:select结合选择器的用法。

  1. # bs4用法 
  2. 首先加载里面的BeautifulSoup: 
  3. from bs4 import BeautifulSoup 
  4. soup = BeautifulSoup('网页响应回来的东西'

主要有以下几种提取规则:

  1. 1、获取标签 
  2.     soup.a   获取a标签(***个) 
  3. 2、获取属性 
  4.     soup.a.attrs   获取a标签下所有的属性和值,返回的是字典 
  5.     soup.a['name'] 获取a标签下的name属性 
  6. 3、获取内容 
  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.     结合选择器使用,常用的选择器如下: 
  18.     标签选择器:如div表示为div 
  19.     类选择器:.表示,如class = 'you'表示为.you 
  20.     id选择器:#表示,如id = 'me'表示为#me  
  21.    组合选择器:如div,.you,#me    
  22.    层级选择器:如div .you #me表示选取div标签下的you类下的id为me的内容 
  23.               再如div > .you > #me,> 则表示只能是下面一级 

三、开始实战——爬取某信托网的信托在售数据

1、爬取前的准备工作——梳理好代码的逻辑

正如前面所说,写代码之前,首先要清楚你想要干什么,如果是你,你是什么样的动作来达到你的这个目的或意图。

***,你的目的或意图是什么,对于本例而言,我需要获取任意某页至某页信托在售产品的下面数据:产品名称、发行机构、发行时间、***收益、产品期限、投资行业、发行地、收益分配方式、发行规模、***收益、***收益和利率等级划分情况这12个数据。

第二,如果是人,需要哪些动作来达到这个目的。我们来看下网页。动作就清晰了:

输入网址/搜索关键字 > 进入网站 > 点击红色框框里的信托产品和在售 > 录入下面绿色框框里的相关信息 > 发现信息不全,再点击这个产品,在详情页(再下一张图)继续录入。

用Python爬取金融市场数据

用Python爬取金融市场数据

2、开始爬取

既然动作清晰了,那就可以让计算机来模拟人的这个动作进行爬取了。

然后就是写代码的逻辑了。我们用做数学题常用的倒推法来梳理这个过程。

要想获取数据 < 你得解析网页给你的响应 < 你得有个响应 < 你得发送请求 < 你得有个请求request < 你得有个url。

然后我们再正过来解题:获取url > 构建request > 发送请求 > 获取响应 > 解析响应 > 获取所需数据 > 保存数据。

所以按照这个步骤,我们可以先做出一个大框架,然后在框架的基础上补充血肉。大框架,就是定义个主函数。

值得注意的是,本例中,每个产品的信息获取,我们都有二次点击的动作,即***页数据不全,我们再点击进入详情页进行剩余数据的获取,因此,本例是有两层的数据获取过程的。***层使用正则表达式,第二层使用bs4。

① 定义主函数

如下是这个主函数,前面的写入相关数据你可以先不管,这都是在***步的获取url时,后补过来的。

回到前面的目的:提取任意某页至任意某页的数据,所以写个循环是必须的,然后在循环下方,两层网页的数据获取框架就出来了。(由于第二层网页的url是根据***层网页的某个数据拼接出来的,而***层网页是一下子提取整个页面所有产品的信息,所以第二层网页的提取也设置了个循环,对***层网页的所有产品,一个一个点进去进行提取)

  1. # 定义一个主函数 
  2. def main(): 
  3.  
  4.     # 写入相关数据 
  5.     url_1 = 'http://www.某信托网.com/Action/ProductAJAX.ashx?' 
  6.     url_2 = 'http://www.某信托网/Product/Detail.aspx?' 
  7.     size = input('请输入每页显示数量:'
  8.     start_page = int(input('请输入起始页码:')) 
  9.     end_page = int(input('请输入结束页码')) 
  10.     type = input('请输入产品类型(1代表信托,2代表资管):')   
  11.     items = []                # 定义一个空列表用来存储数据 
  12.  
  13.     # 写循环爬取每一页 
  14.     for page in range(start_page, end_page + 1): 
  15.  
  16.     # ***层网页的爬取流程 
  17.         print('第{}页开始爬取'.format(page)) 
  18.  
  19.         # 1、拼接url——可定义一个分函数1:joint 
  20.         url_new = joint(url_1 ,size=size ,page=page ,type=type) 
  21.  
  22.         # 2、发起请求,获取响应——可定义一个分函数2:que_res 
  23.         response = que_res(url_new) 
  24.  
  25.         # 3、解析内容,获取所需数据——可定义一个分函数3:parse_content_1 
  26.         contents = parse_content_1(response) 
  27.  
  28.         # 4、休眠2秒 
  29.         time.sleep(2) 
  30.  
  31.     # 第二层网页的爬取流程 
  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个函数 
  39.  
  40.             # 2、发起请求,获取响应 
  41.             response_2 = que_res(url_2_new)     # que_res为前面定义的第2个函数 
  42.  
  43.             # 3、解析内容,获取所需数据——可定义一个分函数4:parse_content_2,直接返回字典格式的数据 
  44.             item = parse_content_2(response_2 ,content) 
  45.  
  46.             # 存储数据 
  47.             items.append(item) 
  48.             print('    第{}页{}结束下载'.format(page ,content[0])) 
  49.  
  50.             # 休眠5秒 
  51.             time.sleep(5) 
  52.  
  53.         print('第{}页结束爬取'.format(page)) 
  54.  
  55.     # 保存数据为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('全部爬取结束'
  61.  
  62. if __name__ == '__main__'
  63.     main() 

② 获取url —— ***层和第二层通用

由于我们需要访问两层的数据,所以希望定义一个函数,能对两层的URL都可以进行拼接。

如下图为***层页面的内容和源码,由第二个红框中的内容(X-Requested-With:XMLHttpRequest),可知这是一个AJAX get请求,且携带者第三个红框中的数据,而第三个红框中的数据,又恰好是***个红框中的url的一部分,即为:

http://www.某信托网.com/Action/ProductAJAX.ashx?加上第三个红框中的数据。

第三个框框中包括几个可变的数据:pageSize(表示一页显示多少产品);pageIndex(表示第几页);conditionStr(定义产品类型,1表示信托,2表示资管),其余的数据都是固定的(这其中有个_:1544925791285这种下划线带一串数字的东西,像是个随机数,去掉也没影响,我就给去掉了)。

用Python爬取金融市场数据

下图为第二层页面的内容和源码,可见只是一个简单的get请求,且网址很简单,就是一个http://www.某信托网.com/Product/Detail.aspx?加上一个id,而这个id又来自哪里呢,答案就在***层网页的响应数据中(见再下面一幅图的红色框)。

用Python爬取金融市场数据

用Python爬取金融市场数据

通过上面的分析,***层网页的请求url由一个固定的部分加上一些数据,第二层网页的url依赖于***层的数据,我们先在主函数中将url_1、url_2和一些可变的数据写入(见上面的主函数),然后定义一个函数用来拼接两层的url即可,因为***层网页url的固定部分长度为47,第二层的为43,这里使用一个长度条件来判断是拼接***层还是拼接第二层。

  1. # 定义第1个分函数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 

③ 构建request + 获取response一条龙 —— ***层和第二层通用

获取url后,接下来就是构建request用来发送请求获取响应了,此处定义一个函数实现一条龙服务。

这里为了提防反爬,user_agent在多个里随机选,并使用了代理池(虽然不多),并且我电脑端也进行了局域网ip代理。

  1. # 定义第2个函数que_res,用来构建request发送请求,并返回响应response 
  2. def que_res(url): 
  3.  
  4.     # 构建request的***步——构建头部: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.某信托网.com'
  22.         'Referer''http://www.某信托网.com/Product/Index.aspx'
  23.         'User-Agent': user_agent, 
  24.         'X-Requested-With''XMLHttpRequest' 
  25.         } 
  26.  
  27.     # 构建request的第二步——构建request 
  28.     request = urllib.request.Request(url=url, headers=headers) 
  29.  
  30.  
  31.     # 发起请求的***步——构建代理池 
  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.     # 发起请求的第二步——创建handler和opener 
  39.     handler = urllib.request.ProxyHandler(proxy) 
  40.     opener = urllib.request.build_opener(handler) 
  41.  
  42.     # 发起请求的第三步——发起请求,获取响应内容并解码 
  43.     response = opener.open(request).read().decode() 
  44.  
  45.     # 返回值 
  46.     return response 

④ 解析***层网页的内容

获取响应之后就是解析并提取数据了,***层使用正则表达式的方法来进行。

获取的response如下如:

用Python爬取金融市场数据

因此可写出如下正则,从左到右分配匹配出ID、产品名称、发行机构、发行时间、产品期限、投资行业、首页收益。

  1. # 定义第3个函数parse_content_1,用来解析并匹配***层网页内容,此处使用正则表达式方法 
  2. def parse_content_1(response): 
  3.  
  4.     # 写正则进行所需数据的匹配 
  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 

⑤ 解析第二层网页的内容并输出数据

第二层使用bs4中的select+选择器的方法来进行。除了***层所提取的数据外,还需要发行地、收益分配方式、发行规模、***收益、***收益和利率等级分布情况。

网页如下,可见,我们所需要的信息隐藏在一个又一个tr标签里,而这个tr标签处于id=“procon1”下的一个table标签里(此处有个坑,就是从网页来看,table下还有个tbody标签,而实际得到的响应里并没有)。

用Python爬取金融市场数据

由于我们不是所有的信息都要,所以我们可以一个一个的提取,最终输出个数据。代码如下(这中间用到了前面提到的选择器知识和一些字符串处理方法):

  1. # 定义第4个函数parse_content_2,用来解析并匹配第二层网页内容,并输出数据,此处使用BeautifulSoup方法 
  2. def parse_content_2(response,content): 
  3.  
  4.     # 使用bs4进行爬取第二层信息 
  5.     soup = BeautifulSoup(response) 
  6.  
  7.     # 爬取发行地和收益分配方式,该信息位于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.     # 爬取发行规模,该信息位于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.     # 保存数据到一个字典中 
  29.     item = { 
  30.     '产品名称':content[1], 
  31.     '发行机构':content[2], 
  32.     '发行时间':content[3], 
  33.     '产品期限':content[4], 
  34.     '投资行业':content[5], 
  35.     '首页收益':content[6], 
  36.     '发行地': address, 
  37.     '收益分配方式': r_style, 
  38.     '发行规模': scale, 
  39.     '***收益': r_min, 
  40.     '***收益': r_max, 
  41.     '利率等级': r_grade 
  42.     } 
  43.  
  44.     # 返回数据 
  45.     return item 

⑥ 保存数据到本地(以dataframe格式保存到本地CSV格式)

  1. # 保存数据为dataframe格式CSV文件 
  2.     df = pd.DataFrame(items) 
  3.     df.to_csv('data.csv',index=False,sep=',',encoding='utf-8-sig'
  4.  
  5. 好了,现在就大功告成了,***不要只让自己爽,也要让对方的服务器别太难过,在一些地方休眠几秒,完整代码如下。 
  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个分函数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个函数que_res,用来构建request发送请求,并返回响应response 
  40. def que_res(url): 
  41.  
  42.     # 构建request的***步——构建头部: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.某信托网.com'
  60.         'Referer''http://www.某信托网.com/Product/Index.aspx'
  61.         'User-Agent': user_agent, 
  62.         'X-Requested-With''XMLHttpRequest' 
  63.         } 
  64.  
  65.     # 构建request的第二步——构建request 
  66.     request = urllib.request.Request(url=url, headers=headers) 
  67.  
  68.  
  69.     # 发起请求的***步——构建代理池 
  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.     # 发起请求的第二步——创建handler和opener 
  77.     handler = urllib.request.ProxyHandler(proxy) 
  78.     opener = urllib.request.build_opener(handler) 
  79.  
  80.     # 发起请求的第三步——发起请求,获取响应内容并解码 
  81.     response = opener.open(request).read().decode() 
  82.  
  83.     # 返回值 
  84.     return response 
  85.  
  86. # 定义第3个函数parse_content_1,用来解析并匹配***层网页内容,此处使用正则表达式方法 
  87. def parse_content_1(response): 
  88.  
  89.     # 写正则进行所需数据的匹配 
  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个函数parse_content_2,用来解析并匹配第二层网页内容,并输出数据,此处使用BeautifulSoup方法 
  96. def parse_content_2(response,content): 
  97.  
  98.     # 使用bs4进行爬取第二层信息 
  99.     soup = BeautifulSoup(response) 
  100.  
  101.     # 爬取发行地和收益分配方式,该信息位于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的***个内容(发行地) 
  104.     r_style = tr_3.select('.pro-textcolor')[1].text        #select到该tr下的class为pro-textcolor的第二个内容(收益分配方式) 
  105.  
  106.     # 爬取发行规模,该信息位于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的第二个内容(发行规模:至***万) 
  109.     re_2 = re.compile(r'.*?(\d+).*?', re.S)                #设立一个正则表达式,将纯数字提取出来 
  110.     scale = re_2.findall(guimo)[0]                         #提取出纯数字的发行规模 
  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的***个内容(且通过下标[-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下的***个内容(即利率等级) 
  122.  
  123.     # 保存数据到一个字典中 
  124.     item = { 
  125.     '产品名称':content[1], 
  126.     '发行机构':content[2], 
  127.     '发行时间':content[3], 
  128.     '产品期限':content[4], 
  129.     '投资行业':content[5], 
  130.     '首页收益':content[6], 
  131.     '发行地': address, 
  132.     '收益分配方式': r_style, 
  133.     '发行规模': scale, 
  134.     '***收益': r_min, 
  135.     '***收益': r_max, 
  136.     '利率等级': r_grade 
  137.     } 
  138.  
  139.     # 返回数据 
  140.     return item 
  141.  
  142. # 定义一个主函数 
  143. def main(): 
  144.  
  145.     # 写入相关数据 
  146.     url_1 = 'http://www.某信托网.com/Action/ProductAJAX.ashx?' 
  147.     url_2 = 'http://www.某信托网.com/Product/Detail.aspx?' 
  148.     size = input('请输入每页显示数量:'
  149.     start_page = int(input('请输入起始页码:')) 
  150.     end_page = int(input('请输入结束页码')) 
  151.     type = input('请输入产品类型(1代表信托,2代表资管):')  
  152.     items = []                       # 定义一个空列表用来存储数据 
  153.  
  154.     # 写循环爬取每一页 
  155.     for page in range(start_page, end_page + 1): 
  156.  
  157.         # ***层网页的爬取流程 
  158.         print('第{}页开始爬取'.format(page)) 
  159.         # 1、拼接url——可定义一个分函数1:joint 
  160.         url_new = joint(url_1,size=size,page=page,type=type) 
  161.  
  162.         # 2、发起请求,获取响应——可定义一个分函数2:que_res 
  163.         response = que_res(url_new) 
  164.  
  165.         # 3、解析内容,获取所需数据——可定义一个分函数3:parse_content_1 
  166.         contents = parse_content_1(response) 
  167.  
  168.         # 4、休眠2秒 
  169.         time.sleep(2) 
  170.  
  171.         # 第二层网页的爬取流程 
  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个函数 
  178.  
  179.             # 2、发起请求,获取响应 
  180.             response_2 = que_res(url_2_new)     # que_res为前面定义的第2个函数 
  181.  
  182.             # 3、解析内容,获取所需数据——可定义一个分函数4:parse_content_2,直接返回字典格式的数据 
  183.             item = parse_content_2(response_2,content) 
  184.  
  185.             # 存储数据 
  186.             items.append(item) 
  187.             print('    第{}页{}结束下载'.format(page,content[0])) 
  188.             # 休眠5秒 
  189.             time.sleep(5) 
  190.  
  191.         print('第{}页结束爬取'.format(page)) 
  192.  
  193.  
  194.     # 保存数据为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('全部爬取结束'
  200.  
  201. if __name__ == '__main__'
  202.     main() 

3、爬取结果

运行代码,这里以每页显示4个产品,爬取前3页的信托在售为例,运行结果如下:

用Python爬取金融市场数据

然后打开存到本地的CSV文件如下:结果是美好的。

用Python爬取金融市场数据

这种两层网页的数据抓取,可以用在非常非常非常多的地方呦。

【编辑推荐】

  1. 超有趣!手把手教你用Python实现实时“人脸检测”
  2. 人工智能时代,我用Python写了一个智能机器人来聊天,非常不错!
  3. Python基础知识大全:集合用法、文件操作、字符编码转换、函数
  4. 春运渡劫?Python帮你12306抢回家的火车票
  5. Python数据可视化:25年GDP之变
【责任编辑:未丽燕 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

订阅专栏+更多

16招轻松掌握PPT技巧

16招轻松掌握PPT技巧

GET职场加薪技能
共16章 | 晒书包

289人订阅学习

20个局域网建设改造案例

20个局域网建设改造案例

网络搭建技巧
共20章 | 捷哥CCIE

645人订阅学习

WOT2019全球人工智能技术峰会

WOT2019全球人工智能技术峰会

通用技术、应用领域、企业赋能三大章节,13大技术专场,60+国内外一线人工智能精英大咖站台,分享人工智能的平台工具、算法模型、语音视觉等技术主题,助力人工智能落地。
共50章 | WOT峰会

0人订阅学习

读 书 +更多

超级网管员——网络应用

本书全面、深入地介绍了网络应用技术,主要内容包括:RMS权限管理服务、Exchange邮件服务、LCS即时消息服务、WSUS系统更新服务、Symantec网...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊

51CTO服务号

51CTO播客