2019独角兽企业重金招聘Python工程师标准>>>

在 《函数计算本地运行与调试 - Fun Local 基本用法》 中,我们介绍了利用 Fun Local 本地运行、调试函数的方法。但如果仅仅这样简单的介绍,并不能展现 Fun Local 对函数计算开发的巨大效率的提升。

这一次,我们拿一个简单的场景来举例子——开发一个简单的爬虫函数(代码参考函数计算控制台模板),介绍如何以正确姿势,从零开始,开发一个自动伸缩、按调用次数收费的 serverless 爬虫应用。

开发步骤

我们将这个完整的应用拆分成多步,并且在每一步完成后,我们都会进行相应的运行验证。

1. 创建 Fun 项目

首先,我们创建一个名为 image-crawler 的目录作为项目的根。然后在该目录下创建一个名为 template.yml 的文件,内容为:

ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:localdemo:Type: 'Aliyun::Serverless::Service'Properties:Description: 'local invoke demo'image-crawler:Type: 'Aliyun::Serverless::Function'Properties:Handler: index.handlerCodeUri: code/Description: 'Hello world with python2.7!'Runtime: python2.7

如果不了解 Fun 定义的 Serverless Application Model,可以参考 这里。

操作完成后,我们的项目目录结构如下:

.
└── template.yml

2. 编写 helloworld 函数代码

在根目录下创建一个名为 code 的目录,并在该目录下创建一个名为 index.py 的文件,内容为一个简单的 helloworld 函数:

def handler(event, context):return 'hello world!'

在项目根目录下执行:

fun local invoke image-crawler

函数运行成功:

操作完成后,我们的项目目录结构如下:

.
├── code
│   └── index.py
└── template.yml

3. 事件触发函数运行

我们简单修改第 2 步的代码,将 event 打印到 log 中。

import logginglogger = logging.getLogger()def handler(event, context):logger.info("event: " + event)return 'hello world!'

通过触发事件的方式运行函数,得到如下结果:

可以看到,我们的函数已经能正确接收到触发事件了。

Fun Local 更多帮助信息,参考。

4. 获取网页源码内容

接下来,我们添加获取网页内容的代码。

import logging
import json
import urlliblogger = logging.getLogger()def handler(event, context):logger.info("event: " + event)evt = json.loads(event)url = evt['url']html = get_html(url)logger.info("html content length: " + str(len(html)))return 'Done!'def get_html(url):page = urllib.urlopen(url)html = page.read()return html

代码逻辑比较简单,我们这里直接使用了 urllib 库,读取网页内容。

运行函数,得到以下输出:

5. 解析网页中的图片

我们打算通过正则解析网页中包含的 jpg 图片,因此这一步会比较繁琐,因为涉及到正则表达式的微调。为了能快速的解决问题,我们决定利用 fun local 提供的 local debugging 解决问题。local debugging 方法参考: 《函数计算本地运行与调试 - Fun Local 基本用法》。

首先,我们在下面这一行下个断点:

logger.info("html content length: " + str(len(html)))

然后以 debug 的方式启动,vscode 调试器连接后,函数会继续运行到我们断点的这一行:

我们可以直接在 Locals 一栏看到本地变量,其中包含了 html 这个变量,也就是我们获取到的 html 源码。我们可以将它的值复制出来,分析下,然后设计正则表达式。

我们可以先写一个简单的,比如可以是 http:\/\/[^\s,"]*\.jpg

怎么快速校验这段代码的正确性呢?我们可以利用调试器提供的 Watch(监视) 功能。

创建一个 Watch 变量,将下面的值输入进去:

re.findall(re.compile(r'http:\/\/[^\s,"]*\.jpg'), html)

回车后,即可看到代码的执行效果:

这里一般不太容易一次写对,可以反复修改正则测试,直到正确为止。

我们得到的正确的图片解析的逻辑添加到代码中:

reg = r'http:\/\/[^\s,"]*\.jpg'
imgre = re.compile(reg)def get_img(html):return re.findall(imgre, html)

然后在 handler 方法中调用即可:

def handler(event, context):logger.info("event: " + event)evt = json.loads(event)url = evt['url']html = get_html(url)img_list = get_img(html)logger.info(img_list)return 'Done!'

编写完成后,可以继续本地执行,验证下结果:

echo '{"url": "https://image.baidu.com/search/index?tn=baiduimage&word=%E5%A3%81%E7%BA%B8"}' \| fun local invoke image-crawler

可以看到,img_list 已经输出到控制台了:

6. 将图片上传到 oss

解析到的图片,我们选择使用 oss 存储。

首先,我们需要通过环境变量配置 OSS Endpoint 以及 OSS Bucket。

在 template 中配置环境变量(需提前创建好 oss bucket):

EnvironmentVariables:OSSEndpoint: oss-cn-hangzhou.aliyuncs.comBucketName: fun-local-test

然后就可以直接在函数中获取到这两个环境变量了:

endpoint = os.environ['OSSEndpoint']
bucket_name = os.environ['BucketName']

另外,fun local 运行函数时,还会提供一个额外的变量用来标识这是一个本地运行的函数。通过这个标识,我们可以用来做一些本地化的操作,比如我们可以在线上运行时连接 RDS,在本地运行时连接 Mysql。

这里,我们用该标识以不同的的方式创建 oss client,原因是线上运行时,通过 credentials 获取到的是扮演角色的临时 ak,有有效期限制,而本地运行时,没有该限制。oss 提供了这两种方式的构造方法,我们直接使用即可:

creds = context.credentialsif (local):auth = oss2.Auth(creds.access_key_id,creds.access_key_secret)
else:auth = oss2.StsAuth(creds.access_key_id,creds.access_key_secret,creds.security_token)bucket = oss2.Bucket(auth, endpoint, bucket_name)

接着我们遍历所有图片,将所有的图片上传到 oss:

count = 0
for item in img_list:count += 1logging.info(item)# Get each picturepic = urllib.urlopen(item)# Store all the pictures in oss bucket, keyed by timestamp in microsecond unitbucket.put_object(str(datetime.datetime.now().microsecond) + '.png', pic)  

再在本地运行一下函数:

echo '{"url": "https://image.baidu.com/search/index?tn=baiduimage&word=%E5%A3%81%E7%BA%B8"}' \| fun local invoke image-crawler

可以从日志看到,图片被一张一张的解析出来,并被上传到 oss 上了。

登陆 oss 控制台,可以看到这些图片。

部署

本地开发完成后,我们还需要将其发布到线上,让其成为一个可被调用的服务。以往,你可能觉得比较麻烦,比如要登陆控制台,创建服务、创建函数、配置环境变量,创建角色等,现在有了 fun 后,这一切都不需要了。

不过,本地与线上还是有些区别的,那就是要授权函数计算能够访问 OSS,怎么做呢?很简单,在我们的 template 中加入一行配置即可(Polices 文档,可以参考):

Policies: AliyunOSSFullAccess

添加后的 template.yml 内容如下:

ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:localdemo:Type: 'Aliyun::Serverless::Service'Properties:Description: 'local invoke demo'Policies: AliyunOSSFullAccessimage-crawler:Type: 'Aliyun::Serverless::Function'Properties:Handler: index.handlerCodeUri: code/Description: 'Hello world with python2.7!'Runtime: python2.7EnvironmentVariables:OSSEndpoint: oss-cn-hangzhou.aliyuncs.comBucketName: fun-local-test

然后,使用 fun deploy 后,可以看到部署成功的日志。

验证

通过控制台验证

登陆控制台,可以看到,我们的服务、函数、代码、环境变量等都已经就绪了。

在触发事件中,写入我们用来测试的 json,然后执行:

可以发现,会获得与本地一致的效果:

通过 fcli 验证

fcli 帮助文档 参考。

在终端执行以下命令,可以获取函数列表:

fcli function list --service-name localdemo

可以看到我们的 image-crawler 已经创建成功了。

{"Functions": ["image-crawler","java8","nodejs6","nodejs8","php72","python27","python3"],"NextToken": null
}

使用以下命令则可以调用函数运行:

fcli function invoke --service-name localdemo \--function-name image-crawler \--event-str '{"url": "https://image.baidu.com/search/index?tn=baiduimage&word=%E5%A3%81%E7%BA%B8"}'

运行成功后,会得到与控制台与 fun local 一致的结果。

小结

至此,我们的开发就算告一段落。

本文利用 fun local 提供的本地运行、调试的能力,做到了在本地开发函数,并且通过反复的执行函数得到反馈以便于快速迭代代码。

在本地开发完成后,不需要对代码进行任何修改,通过 fun deploy 命令,一键部署到云端,达到预期的效果。

本文介绍的方法,并不是开发函数计算的唯一方式。本文的目的,是能够向开发者传达一种信号——开发函数计算时,只要身姿正确,就会非常享受,开发流程也会十分顺畅。祝您使用愉快。

原文链接

转载于:https://my.oschina.net/u/1464083/blog/2987880

开发函数计算的正确姿势 —— 爬虫相关推荐

  1. 开发函数计算的正确姿势——支持 ES6 语法和 webpack 压缩

    为什么80%的码农都做不了架构师?>>>    首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算 ...

  2. 开发函数计算的正确姿势 —— 使用 Fun Local 本地运行与调试

    前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算 ...

  3. 开发函数计算的正确姿势——轻松解决大依赖部署

    前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算 ...

  4. 开发函数计算的正确姿势 —— 移植 next.js 服务端渲染框架

    为什么80%的码农都做不了架构师?>>>    首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算 ...

  5. aptitude安装出现依赖_开发函数计算的正确姿势——依赖安装方法一览

    1. 前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函 ...

  6. 开发函数计算的正确姿势———为 PHP 运行时添加自定义扩展

    PHP 语言提供了一种扩展机制(Extension),通过 PHP 扩展可以增强语法.调用 C/C++ 实现的库函数以及优化执行性能.PHP 扩展是与平台相关的动态链接库,在 Linux 和 Mac ...

  7. 开发函数计算的正确姿势——运行 Selenium Java

    前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算 ...

  8. 开发函数计算的正确姿势——使用交互模式安装依赖

    前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算 ...

  9. 开发函数计算的正确姿势——借助 Ghostscript 将 PDF 转换成 JPG

    前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute):函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算准 ...

最新文章

  1. WebShell代码分析溯源(第1题)
  2. 约束rmq_差分约束
  3. python-mysql 基础知识记录
  4. thinkphp mysql 中文 问号_thinkphp分页中文参数乱码解决
  5. hdoj 1257(暴力)
  6. 从「猜画小歌」,谈企业的「数据困惑」该何去何从?
  7. [python] 字典:按key排序或按value排序
  8. 视图状态机制下的IStateManager接口
  9. MD5加盐的一个简单算法
  10. Rainmeter新手教程
  11. 实践三 网络嗅探与协议分析
  12. php 公众号 群发,php实现微信公众号无限群发
  13. 南卡和声阔蓝牙耳机哪个比较好用?降噪效果好的蓝牙耳机推荐
  14. 万网域名查询API接口
  15. Attention Mechanisms in Computer Vision: A Survey(四)
  16. 月夜无声,谁与我醉今宵
  17. 微信私房菜走红 外卖、用户、监管三方皆受伤
  18. 苹果7 无线流量连接不上网络连接服务器,iPhone7连不上wifi无线网的四种解决方法...
  19. GPU Skinning介绍
  20. Making FIFA Coins with FUT 14 Winter Upgrades

热门文章

  1. 五个超酷Linux命令
  2. 为什么要继承Serializable类?
  3. Magento 2中文手册之常见概念解析
  4. 正则表达式获取TABLE里的内容
  5. js不停地触发按钮的事件
  6. 如何破解root以及grub密码
  7. 刀片服务器与机架服务器对比
  8. React+TypeScript练手小项目
  9. 7:MD5、圆形图片、动态换肤
  10. EOS之记事本智能合约