Python爬取链家网成交数据

Python爬取链家网成交数据

最近要买房

  • 上海房价涨的太凶了,有木有?
  • 爬爬链家网的数据来看看上海房价高的有多离谱?
  • 上海辣么大,买哪里好呢?

环境准备

  • 环境工具准备好,就可以开工了
  • 这里用到python、mysql、tableau几个工具
  • 主要思路就是链家网上的成交记录数据通过python程序爬下来,存储到mysql数据库中,然后通过tableau数据可视化工具进行简单的分析和展示

爬取核心函数

  • 根据上海各区县获取数据,读取链家页面信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def getPage(self,region,pageIndex):
        try:
            url = 'http://sh.lianjia.com/chengjiao/'+ region + '/d'+ str(pageIndex)
            cj = CookieJar()
            opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
            request = urllib2.Request(url,headers = self.headers)
            
            respone = opener.open(request)
            content  = respone.read()
            infoencode = chardet.detect(content).get('encoding','utf-8')
            typeEncode = sys.getfilesystemencoding()
            
            pageCode = content.decode(infoencode,'ignore')#.encode(typeEncode)
            print("page:"+str(pageIndex)+"_connect success..")
            print(url)
           
            return pageCode
        except urllib2.HTTPError,e:
            if hasattr(e,"reason"):
                print url
                print u'连接数据出错,错误原因:',e.reason
                f_error = open('/opt/lianjia/house_trade_error.csv','ab')
                w_error = csv.writer(f_error)
                w_error.writerow([pageIndex,time.strftime('%Y-%m-%d',time.localtime(time.time()))])
                return  None
  • 从页面中提取所需的字段信息,如成交单号、成交价格、房屋名称、所在区域等等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def getPageItems(self,region,pageIndex):
        pageCode = self.getPage(region,pageIndex)
        
        if not pageCode:
            print (u"页面加载失败....")
            return None
        sign ="链家网签约"
        sign = sign.decode('utf8')
        total = "签约总价"
        total =total.decode('utf8')
        pattern = re.compile('<div class="info-panel">.*?name="selectDetail.*?key="(.*?)" href="/chengjiao.*?target="_blank">(.*?)</a>.*?'+
                             '<div class="con">.*?<a href="/chengjiao.*?>(.*?)</a>.*?'+
                             '<a href="/chengjiao.*?>(.*?)</a>.*?'+
                             '<div class="introduce">(.*?)</div>.*?'+
                             '<div class="dealType">.*?<div class="div-cun">(.*?)</div>.*?<p>'+sign+'</p>.*?'+
                             '<div class="div-cun">(.*?)<span>.*?'+
                             '<div class="div-cun">(.*?)<span>.*?<p>'+total+'</p>',re.S)
        items = re.findall(pattern,pageCode)
        #用来存储每页的信息
        pageInfor = []
        #遍历正则表达式匹配的信息''.join(x)
        for item in items:
            pageInfor.append([self.rdate,item[0].strip(),item[1].strip(),item[2].strip(),item[3].strip(),item[4].strip(),item[5].strip()\
                             ,item[6].strip(),item[7].strip() ])
        return pageInfor
  • 获取最大页数
1
2
3
4
5
6
7
8
9
10
11
12
13
def getMaxPage(self,region):
        pageCode = self.getPage(region,1)

        if not pageCode:
            print (u"页面加载失败....")
            return None
        pattern = re.compile('house-lst-page-box">.*?class="on">.*?<a href="/chengjiao/'+region+'/d7" >7</a>.*?<a href="/chengjiao.*?>(.*?)</a>',re.S)
        total_page = re.findall(pattern,pageCode)
        try:
            return total_page[0]
        except Exception,e:
            print(e)
            return 1
  • 写数据到mysql数据库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def writeDataTotmpTable(self,region,pageIndex):
        conn = MySQLdb.connect(self.host,self.user,self.passwd,self.db,charset="utf8")
        pageInfor = self.getPageItems(region,pageIndex)
        if conn:
            if pageInfor:
                try:
                    cursor = conn.cursor()
                    insert_sql = "insert into tmp_t_house_trade_infor(rdate,house_key,house_name,region_name,\
                             district_name,house_introduce,trade_date,price,total_amount)\
                             values(%s,%s,%s,%s,%s,%s,%s,%s,%s)"
                    for i in range(0,len(pageInfor)):
                        #print(pageInfor[i])
                        cursor.execute(insert_sql,pageInfor[i])
                except Exception,e:
                    print e
                conn.commit()
                cursor.close()
                conn.close()
            else:
                print(pageIndex+ ":no data return....")
        else:
            print("connect database failed....")
  • 调度执行
1
2
3
4
5
6
7
8
9
10
11
def start(self):

        self.deleteTmpTable()
        region_code_list = self.getRegionCode()
        for i in range(0,len(region_code_list)):
            max_page = self.getMaxPage(region_code_list[i][0])
            for j in range(1,int(max_page)+1):
                self.writeDataTotmpTable(region_code_list[i][0],j)

        time.sleep(5)
        self.cal_mysql_produce()

爬取的链家网成交数据及房源数据

  • 链家成交中只有最近一年的成交数据
  • 只爬取了上海的数据

链家上海近一年的成交记录 链家上海新房源数据 链家上海房价周成交走势分析 链家上海房价日成交走势分析 链家上海房屋明细

自己动手搭建企业网盘服务

自己动手搭建企业网盘服务

国内免费网盘

  • 国产网盘纷纷关闭,最早用的快盘、酷盘纷纷停止服务,估计百度云也难逃厄运
  • 国外DropBox又遭屏蔽,使用不方便

自己动手吧

我选择了seafile这一开源网盘软件,详细请看seafile官方网站

准备起来

  • 首先要有一台linux的虚拟机
  • 还要有一块不小的存储空间
  • 然后DIY一下就好啦

安装配置过程

必备的rpm包

1
yum install gcc python-setuptools python-imaging python-ldap MySQL-python python-memcached python-simplejson mysql-server openssl-devel libjpeg libjpeg-level zlib zlib-devel freetype freetype-devel python-devel mysql-devel libjpeg-turbo-devel -y

python2.7的环境

1
2
3
4
5
6
wget https://www.python.org/ftp/python/2.7.11/Python-2.7.11.tgz
tar -zxvf Python-2.7.11.tgz
cd Python-2.7.11
./configure
make
make install
1
2
wget https://bootstrap.pypa.io/ez_setup.py
python2.7 ez_setup.py install
1
2
3
easy_install-2.7 pip
pip2.7 install Pillow
pip2.7 install MySQL-python

mysql数据库

1
2
service mysqld start
mysqladmin -uroot password 'deadeye'

seafile服务器端配置

1
2
3
4
cd /data/xxb/seafile-server-5.0.5/
./setup-seafile-mysql.sh
./seafile.sh start
./seahub.sh start

PC端访问

http访问的默认端口是8000,通过浏览器访问 pc端

同样支持移动端

IOS、Android、MAC ios端

小结

优势

  • 类DropBox的服务,可以实现文件同步、共享、跨平台访问、团队协作等功能
  • 客户端除了网页版之外,还支持 Mac、Linux、Windows 三个桌面平台以及 Android 和 iOS 两个移动平台
  • 可以用办公服务器来同步工作文件,用个人服务器与朋友共享私人文件,两者互不干扰,私密性也可保证
  • 云端数据文件完全切碎并加密,管理员看不到你的文件哦(不像共有云盘,后端文件不切的,copy下来直接访问的,安全性,私密性无法保证)
  • txt 纯文本、Markdown、源代码等文本格式可以直接在线编辑
  • office文件社区版不支持,不过专业版可以哦
公有云和私有云的对比

公有云和私有云的对比

IT as a service

几个概念

  • 公有云
  • 私有云
  • 混合云

  • 计算
  • 存储
  • 网络

  • IaaS云
  • PaaS云
  • SaaS云
  • 容器云

公有云和私有云的区别

  • IT设施的位置 当自己构建一个私有云平台的时候,IT基础设施是自己的,一般位于企业内部。而采用公有云平台的时候,IT基础设施是位于一个第三方的数据中心。这里有一个例外,那就是现在有一些服务提供商提出的虚拟私有云(VPC, Virtual Private Cloud)的概念,它指的是在第三方数据中心内部通过技术手段隔离出来的一个专用计算环境,并通过安全通道与企业相连接。

  • 基础设施差异性 对于许多大型企业,由于经过了多年的IT建设和技术演变,他们的IT基础设施往往采用了不同的技术和平台,也就是说,这些企业采用的是异构平台环境。但是,对于目前大部分公有云服务提供商来说,他们的平台往往是通过廉价和标准的硬件平台来构建的。这些标准化方式构建的平台能够以比较好的性价比满足大部分用户的需求。另外,在服务的提供方面,公有云服务提供商往往提供最为大众化的、需求量最为广泛和集中的服务。因此,对于公有云服务来说,其服务和环境往往是同构的,这与企业自建的IT环境不一样。

  • 商务模式 企业如果选择自己构建IT系统,那么显然需要进行一次性的大量投资来采购软、硬件设备,甚至包括数据中心的基础建设等。在企业的财务报表中,这体现为一个比较大的固定成本。但是,如果企业采用第三方提供的公有云服务,那么根据目前云计算服务的收费方式,企业可以选择按月服务费的方式或者按IT资源使用量的方式来进行付费。这样,对于企业来说不需要一个大量的前期投入就可以使用IT服务,其体现为一个持续的运营成本。

  • 控制程度的不同 企业自己构建的IT系统是作为企业资产完全由企业自己拥有,并由企业自己来运维。虽然企业需要自己的IT运维团队,但好处是企业可以独立控制IT系统,并根据实际需要来进行改造和客户化。而对于公有云服务,企业实际上是采用租用服务的方式,好处是不需要自己来管理基础平台服务,但是对于企业来说这同时也降低了其定制化的能力,因为所有的基础设施,包括服务器、网络和存储等,以及上面的软件平台都是由服务提供商来进行维护和管理。

学校需要哪些云服务

应用类型

  • 管理信息系统
  • 网站
  • 移动APP及微信
  • Oracle数据库
  • 财务ERP套件
  • 虚拟桌面

服务类型

  • 存储(FC和NAS)
  • 计算
  • 网络
  • 安全
  • 大数据分析
  • 数据库及缓存
  • 自动化运维及部署管理
  • 监控平台
  • 备份与恢复
  • 开放API

  • 负载均衡
  • 域名解析
  • Oracle数据库
  • NoSQL数据库
  • 缓存
  • 消息队列
  • Java中间件
  • PHP环境、.Net环境
  • Web服务器
  • 数据分析及大数据分析
  • 报表分析应用
  • 入侵防御及防病毒
  • web应用防火墙
  • 网络防火墙
  • 服务器安全
  • 运维审计
  • 数据库审计
  • 网络安全域隔离
  • 数据及文件备份及恢复
  • 虚机备份及恢复
  • 数据库备份及恢复

如何选择

主流的公有云服务商

  • 阿里云
  • 腾讯云
  • UCloud
  • 青云

公有云的价格

公有云服务的价格也不便宜 拿阿里云举例 一个标准的2cpu 8G内存,40G硬盘云主机,一年的基本费用是3300元左右; 目前信息办一共有虚机555个,大约一年的费用165万元; 如果需要负载均衡、安全服务、自动化运维等等其他必须的选型,初步估算费用要翻一倍以上;

私有云有哪些问题

  • 一次性投入资金大,还需要自己准备机房,采购机器等流程
  • 底层基础设施(包括服务器、交换机、防火墙、负载均衡器等设备)全部自己管理维护,工作量较大

公有云有哪些问题

  • 安全性存质疑
  • 上云后应用有些需要改造
  • 统一管理比较难
  • 在面对不同类型的资源时,统一管理以及运维的难度越来越大

混合云是当下最适合的选择

  • 现在的数据中心还可以继续使用
  • 拥抱互联网+战略
  • 两条腿走路

总结

  • 创业型、初创型、互联网公司最适合使用公有云服务
  • 大型国企、传统公司可以选择私有云模式
  • 公益行事业单位如高校等可以选择混合云模式
Web应用的负载均衡、集群、高可用

Web应用的负载均衡、集群、高可用


问题

  • 什么是无状态应用?
  • 什么是负载均衡?
  • 实现WEB负载均衡的方法有哪些?以及如何实现?
  • 这些方案都有什么缺陷或问题?
  • 会话保持、session复制、session共享

负载均衡

在实际应用中,在Web服务器集群之前总会有一台负载均衡服务器,负载均衡设备的任务就是作为Web服务器流量的入口,挑选最合适的一台Web服务器,将客户端的请求转发给它处理,实现客户端到真实服务端的透明转发。 最近几年很火的云计算以及分布式架构,本质上也是将后端服务器作为计算资源、存储资源,由某台管理服务器封装成一个服务对外提供,客户端不需要关心真正提供服务的是哪台机器,在它看来,就好像它面对的是一台拥有近乎无限能力的服务器,而本质上,真正提供服务的,是后端的集群。      负载均衡架构图

集群

将相同服务部署在多台服务器上构成一个集群整体对外提供服务,这些集群可以是Web应用服务器集群,也可以是数据库服务器集群,还可以是分布式缓存服务器集群等等。

高可用

指以减少服务中断时间为目的的服务器集群技术。它通过保护用户的业务程序对外不间断提供的服务,把因软件/硬件/人为造成的故障对业务的影响降低到最小程度。

session复制/共享

在访问系统的会话过程中,用户登录系统后,不管访问系统的任何资源地址都不需要重复登录,这里面servlet保存了该用户的会话(session)。如果两个tomcat(A、B)提供集群服务时候,用户在A-tomcat上登录,接下来的请求web服务器根据策略分发到B-tomcat,因为B-tomcat没有保存用户的会话(session)信息,不知道其登录,会跳转到登录界面。 这时候我们需要让B-tomcat也保存有A-tomcat的会话,我们可以使用tomcat的session复制实现或者通过其他手段让session共享。

几个组件

  • apache 它是Apache软件基金会的一个开放源代码的跨平台的网页服务器,属于老牌的web服务器了,支持基于Ip或者域名的虚拟主机,支持代理服务器,支持安全Socket层(SSL)等等,目前互联网主要使用它做静态资源服务器,也可以做代理服务器转发请求(如:图片链等),结合tomcat等servlet容器处理jsp。

  • ngnix 俄罗斯人开发的一个高性能的 HTTP和反向代理服务器。由于Nginx 超越 Apache 的高性能和稳定性,使得国内使用 Nginx 作为 Web 服务器的网站也越来越多,其中包括新浪博客、新浪播客、网易新闻、腾讯网、搜狐博客等门户网站频道等,在3w以上的高并发环境下,ngnix处理能力相当于apache的10倍。 参考:apache和tomcat的性能分析和对比

  • lvs Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统。由毕业于国防科技大学的章文嵩博士于1998年5月创立,可以实现LINUX平台下的简单负载均衡。了解更多,访问官网

  • keepalive 这里说的keepalive不是apache或者tomcat等某个组件上的属性字段,它也是一个组件,可以实现web服务器的高可用(HA high availably)。它可以检测web服务器的工作状态,如果该服务器出现故障被检测到,将其剔除服务器群中,直至正常工作后,keepalive会自动检测到并加入到服务器群里面。实现主备服务器发生故障时ip瞬时无缝交接。它是LVS集群节点健康检测的一个用户空间守护进程,也是LVS的引导故障转移模块(director failover)。Keepalived守护进程可以检查LVS池的状态。如果LVS服务器池当中的某一个服务器宕机了。keepalived会通过一 个setsockopt呼叫通知内核将这个节点从LVS拓扑图中移除。

  • memcached 它是一个高性能分布式内存对象缓存系统。当初是Danga Interactive为了LiveJournal快速发展开发的系统,用于对业务查询数据缓存,减轻数据库的负载。其守护进程(daemon)是用C写的,但是客户端支持几乎所有语言,服务端和客户端通过简单的协议通信;在memcached里面缓存的数据必须序列化。

  • terracotta 是一款由美国Terracotta公司开发的著名开源Java集群平台。它在JVM与Java应用之间实现了一个专门处理集群功能的抽象层,允许用户在不改变系统代码的情况下实现java应用的集群。支持数据的持久化、session的复制以及高可用(HA)。详细参考

为什么需要回话保持

对于需要交互,或者事务型的网站应用,做了web负载均衡的集群后,需要解决session同步的问题。因为经过负载均衡调度器,同一IP的客户端连接可能会被分配到不同的真实服务器上(real server),如果session不同步的话,会影响交互或者事务的连续性。比如,用户登录的状态。 负载均衡的软件一般都提供持久连接的功能,即同一IP客户端的连接在设定的时间段内都分配到同一个real server。比如lvs的persistent,nginx的ip hash 和haproxy的source调度算法。这样处理实现最为简单,但一定程度上会影响调度分配的均衡性。

如何实现会话保持

  • 在集群节点间分发同步session

通过组播的方式在集群间共享session,比如tomcat目前就具备这样的功能。优点是web容器自身支持,配置简单,适合中小型网站。缺点是当一台real server上的session变更后会将变更的数据以组播的形式分发给集群间的所有节点,对网络和所有的web容器都是存在开销。集群越大浪费越严重。不能做到线性的扩展。

  • 将session放置在共享存储上

将所有real server的session的存储路径指向同一台后端的共享存储(比如nfs服务器)。这样所有的web服务器向同一个位置获取session数据,在网络中session只有一份。相比前面组播的方式来说,网络开销较小。缺点是受制于存储设备的依赖,如果存储设备down掉,就无法工作了,要做存储的高可用,避免断点故障。另外,当访问量过大时,磁盘的IO也是一个非常大的问题。

  • 基于数据库的Session共享

把session信息存储在数据库中,通常使用内存表,以提高Session操作的读写效率 这个方案的实用性比较强,应用较为普遍。缺点在于Session的并发读写能力取决于数据库的性能,同时需要我们自己来实现Session淘汰逻辑,以便定时从数据表中更新、删除Session记录,当并发过高时容易出现表锁,对数据库造成较大压力

  • 利用cookie同步session

session是以文件的形式存放在服务器端的,而cookie是以文件的形式存放在客户端的。以cookie作为中转站,将用户的session 数据全部放在cookie中,服务器从cookie中读取session数据,做到同步。这样做的优点是减轻了服务器端的开销,简化了服务器架构,很多大型站点都在这么干。缺点有三:1.用户可能在浏览器中禁用cookie;2.cookie的数据大小有限制;3.cookie是可伪造的。

  • 将session放置在memcache中

这可能也是目前互联网中比较流行的一种用法。所有Web服务器都把Session写入到memcache,也都从memcache来获取。 memcache本身就是一个分布式缓存,便于扩展。网络开销较小,几乎没有IO。性能也更好。缺点,受制于Memcache的容量(除非你有足够内存存储),如果用户量突然增多cache由于容量的限制会将一些数据挤出缓存,另外memcache故障或重启session会完全丢失掉。

RPC服务化框架

RPC服务化框架

什么是RPC

RPC(Remote Procedure Call)是一种远程调用协议,简单地说就是能使应用像调用本地方法一样的调用远程的过程或服务,可以应用在分布式服务、分布式计算、远程服务调用等许多场景。说起 RPC 大家并不陌生,业界有很多开源的优秀 RPC 框架,例如 Dubbo、Thrift、gRPC、Hprose 等等。下面先简单介绍一下 RPC 与常用远程调用方式的特点,以及一些优秀的开源 RPC 框架。

RPC与其它远程调用方式比较

RPC 与 HTTP、RMI、Web Service 都能完成远程调用,但是实现方式和侧重点各有不同。

HTTP

  • HTTP(HyperText Transfer Protocol)是应用层通信协议,使用标准语义访问指定资源(图片、接口等),网络中的中转服务器能识别协议内容。HTTP 协议是一种资源访问协议,通过 HTTP 协议可以完成远程请求并返回请求结果。
  • HTTP 的优点是简单、易用、可理解性强且语言无关,在远程服务调用中包括微博有着广泛应用。HTTP 的缺点是协议头较重,一般请求到具体服务器的链路较长,可能会有 DNS 解析、Nginx 代理等。
  • RPC 是一种协议规范,可以把 HTTP 看作是一种 RPC 的实现,也可以把 HTTP 作为 RPC 的传输协议来应用。RPC 服务的自动化程度比较高,能够实现强大的服务治理功能,和语言结合更友好,性能也十分优秀。与 HTTP 相比,RPC 的缺点就是相对复杂,学习成本稍高。

RMI

  • RMI(Remote Method Invocation)是指 Java 语言中的远程方法调用,RMI 中的每个方法都具有方法签名,RMI 客户端和服务器端通过方法签名进行远程方法调用。RMI 只能在 Java 语言中使用,可以把 RMI 看作面向对象的 Java RPC。

Web Service

  • Web Service 是一种基于 Web 进行服务发布、查询、调用的架构方式,重点在于服务的管理与使用。Web Service 一般通过 WSDL 描述服务,使用 SOAP通过 HTTP 调用服务。
  • RPC 是一种远程访问协议,而 Web Service 是一种体系结构,Web Service 也可以通过 RPC 来进行服务调用,因此 Web Service 更适合同一个 RPC 框架进行比较。当 RPC 框架提供了服务的发现与管理,并使用 HTTP 作为传输协议时,其实就是 Web Service。
  • 相对 Web Service,RPC 框架可以对服务进行更细粒度的治理,包括流量控制、SLA 管理等,在微服务化、分布式计算方面有更大的优势。

RPC框架选择

选择基于http协议实现的RPC框架

典型RPC调用框架

RPC的实现和调用框架,五花八门,简单介绍其中几种比较典型的

  • RMI实现,利用java.rmi包实现,基于Java远程方法协议(Java Remote Method Protocol) 和java的原生序列化
  • Hessian,是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。 基于HTTP协议,采用二进制编解码。
  • protobuf-rpc-pro 是一个Java类库,提供了基于 Google 的 Protocol Buffers 协议的远程方法调用的框架。基于 Netty 底层的 NIO 技术。支持 TCP 重用/ keep-alive、SSL加密、RPC 调用取消操作、嵌入式日志等功能。
  • THRIFT是一种可伸缩的跨语言服务的软件框架。它拥有功能强大的代码生成引擎,无缝地支持C + +,C#,Java,Python和PHP和Ruby。thrift允许你定义一个描述文件,描述数据类型和服务接口。依据该文件,编译器方便地生成RPC客户端和服务器通信代码。
    最初由facebook开发用做系统内个语言之间的RPC通信 。 2007年由facebook贡献到apache基金,现在是apache下的opensource之一 。 支持多种语言之间的RPC方式的通信:php语言client可以构造一个对象,调用相应的服务方法来调用java语言的服务,跨越语言的C/S RPC调用,底层通讯基于SOCKET。
  • AVRO,Avro出自Hadoop之父Doug Cutting, 在Thrift已经相当流行的情况下Avro的推出,其目标不仅是提供一套类似Thrift的通讯中间件更是要建立一个新的,标准性的云计算的数据交换和存储的Protocol。支持HTTP,TCP两种协议。

除此之外,业内知名的几个服务框架还包括

  • Finagle — Twitter开发并开源,专为JVM设计的一个可扩展的RPC系统,其核心的组件包括Future、Service以及Filter;
  • Dubbo — 阿里开发贡献的一个开源项目,是一个高性能分布式服务框架,它主要由三个核心部分组成:Remoting:提供远程调用的网络通信框架;集群:抽象出具有负载均衡、故障转移等集群能力;注册中心:一个服务注册框架,提供服务事件的发布订阅
  • Sofa-PBRPC — 是一个轻量级的,基于Protobuf实现的一个RPC框架,由百度开发并开源,仅支持C++
  • Motan — 新浪微博的RPC框架,序列化接口可扩展、具有集群方案,不开源
  • Poppy — 腾讯基于Protocol Buffer的网络通信解决方案,除了RPC方式的编程接口之外,也具有集群方案,支持服务监控、调试、在线profiling等辅助功能,不开源

服务框架特点

  • 丰富的客户端特性支持 – 异步、连接池、多协议支持、规避策略等
  • 完整的集群方案 – 服务发现、负载均衡等
  • 服务注册管理 – 一般均使用Zookeeper作为服务注册管理组件
  • 完善的监控措施 – 宏观上,可以通过统一的监控平台整体运行状况;微观上,可以像本地函数profiling一样,分析一个函数调用的分步耗时