开发函数计算的正确姿势 —— 爬虫

在 《函数计算本地运行与调试 - 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 命令,一键部署到云端,达到预期的效果。

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

 

原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/520282.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SonarQube 规则的挂起与激活

文章目录规则添加规则挂起规则添加 规则挂起

内存性能的正确解读

一台服务器,不管是物理机还是虚拟机,必不可少的就是内存,内存的性能又是如何来衡量呢。 1. 内存与缓存 现在比较新的CPU一般都有三级缓存,L1 Cache(32KB-256KB),L2 Cache(128KB-2M…

2019年技术盘点云数据库篇(一):UCloud专家谈云数据库:千锤百炼 云之重器

作者 | 刘丹 出品 | CSDN云计算(ID:CSDNcloud) 公有云逐渐成为企业运行 IT 设施的新趋势,那么作为企业最核心的系统—数据库,数据上云也成为大数据时代的必然选择。对企业来说,数据可视为其命脉&#xff0…

专访阿里云专有云马劲,一个理性的理想主义者

“我的故事都是和团队技术相关的,自己还真没有什么引人入胜的故事。”当马劲被问到能不能多分享些个人经历故事时他笑着说,我们就干脆怀着好奇聊了聊他和阿里云专有云一路走来的故事。 马劲,花名隆猫,阿里云专有云事业部兼企业应用…

80后阿里P10,“关老板”如何带着MaxCompute一路升级?

我是个幸运的人。虽然幸运不能被复制,但是眼光和努力可以。 关涛/关老板,80后的阿里P10,阿里巴巴通用计算平台负责人,阿里巴巴计算平台研究员。12年职场人生,微软和阿里的选择。 关涛的花名取自谐音:观涛。…

【重磅快讯】T11 2019数据智能技术峰会举办,AI将成为行业颠覆者

当前数据的价值日益凸显,已成为重要的生产要素和社会财富。云计算、人工智能、5G等技术的蓬勃发展,带来了智能化时代算力的提升。以数据为“能源”、以技术为“引擎”,才能将数据转化为智能,产生突破局限、跨越发展的力量。11月25…

如何创建一个数据科学项目?

假如你想要开始一个新的数据科学项目,比如对数据集进行简单的分析,或者是一个复杂的项目。你应该如何组织你的项目流程?数据和代码要放在那里?应该使用什么工具?在对数据处理之前,需要考虑哪些方面&#xf…

i 智慧 | IBM存储:全面贯彻新存储的“智慧之道”

戳蓝字“CSDN云计算”关注我们哦!作者 | 刘丹责编 | 阿秃出品 | CSDN云计算(ID:CSDNcloud)随着移动互联网、信息技术等创新发展,数据量呈指数级爆发式增长并表现在多个方面,即规模扩张、结构多元化的数据新…

二十分钟教你如何将区块链应用与函数计算相结合

前言 本篇文章适合对区块链应用感兴趣或是想要通过函数计算服务进一步开发区块链应用的新人。本文将结合阿里云区块链服务、阿里云函数计算服务、阿里云日志服务 以及社区应用 Marbles,手把手教大家如何将阿里云区块链服务与阿里云函数计算服务相结合,并…

Spring项目启动加载xml配置文件替换数据库提高响应速度

文章目录1. pom依赖2. xml配置文件3. 获取参数工具类4. 根据beanId从SpringBootIOC获取类实例工具类5. 测试类6. 浏览器控制台验证1. pom依赖 <properties><!--全局版本控制--><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><…

目标检测算法图解:一文看懂RCNN系列算法

在生活中&#xff0c;经常会遇到这样的一种情况&#xff0c;上班要出门的时候&#xff0c;突然找不到一件东西了&#xff0c;比如钥匙、手机或者手表等。这个时候一般在房间翻一遍各个角落来寻找不见的物品&#xff0c;最后突然一拍大脑&#xff0c;想到在某一个地方&#xff0…

不懂数据库的码农不是好程序员!

毋庸置疑&#xff0c;现在是“一切皆数”的时代&#xff0c;放眼目前炙手可热的大数据、人工智能等创新技术&#xff0c;如果没有数据加以支撑&#xff0c;一切的一切将毫无用武之地&#xff0c;更不必谈信息化、智能化and so on&#xff0c;而数据库作为存储和承载数据的重要场…

基于深度学习模型WideDeep的推荐

本实验选用数据为UCI开源数据集&#xff0c;仅用于学习&#xff0c;请勿商用&#xff09; Wide&Deep推荐算法出自一篇论文《Wide&Deep Learning for RecommenderSystems》&#xff0c;Wide&Deep由两部分组成&#xff0c;分别是Wide和Deep。先来说wide&#xff0c;…

RabbitMQ非root用户安装(Linux环境)

文章目录一、用户操作1. 创建fismq用户并设置密码2. 给fismq用户设置目录权限二、Erlang 操作2.1. Erlang下载2.2. Erlang 上传并解压2.3. 验证rabbitmq依赖是否安装2.4. 安装rabbitmq依赖2.5. Erlang 编译、安装2.6. Erlang 配置环境变量2.7. Erlang 验证三、RabbitMQ3.1. Rab…

深度学习目标检测系列:faster RCNN实现|附python源码

目标检测一直是计算机视觉中比较热门的研究领域&#xff0c;有一些常用且成熟的算法得到业内公认水平&#xff0c;比如RCNN系列算法、SSD以及YOLO等。如果你是从事这一行业的话&#xff0c;你会使用哪种算法进行目标检测任务呢&#xff1f;在我寻求在最短的时间内构建最精确的模…

mysql冷热数据LRU_浅析MySQL的lru链表

一、简述传统的lru链表lru&#xff1a;least recently used相信大家对lru链表是不陌生的&#xff0c;它算是一种基础的数据结构吧&#xff0c;而且想必面试时也被问到过什么是lru链表&#xff0c;甚至是让你手写一个lru链表。想必你已经知道了mysql的buffer pool机制以及mysql组…

报应!GitHub上线围剿Python计划,已有4万人跟进,你呢?

人红是非多&#xff0c;最近Python就遇到了这样的问题。与国际技术社区上一片「形势大好」对比鲜明的是&#xff0c;国内技术圈却一直存在对Python&#xff0c;「力挺」和「吃瓜」两派阵营&#xff0c;针锋相对&#xff0c;最近就悄然上线一个争议性疑问&#xff1a;围剿Python…

生物智能与AI——关乎创造、关乎理解(上)

几百万年前&#xff0c;第一次人类智能的星火出现在非洲大陆&#xff0c;并且持续发展&#xff0c;最终在大约10万年前在智人的大脑中达到顶峰。作为现代人类&#xff0c;我们只能想象我们的古代祖先在窥视夜空时所经历的事情&#xff0c;以思考物理现实的本质&#xff0c;以及…

Spring Cloud Config 规范

Spring Cloud Config 规范 首先Spring Cloud 是基于 Spring 来扩展的&#xff0c;Spring 本身就提供当创建一个Bean时可从Environment 中将一些属性值通过Value的形式注入到业务代码中的能力。那Spring Cloud Config 要解决的问题就是&#xff1a; 如何将配置加载到 Environm…

RabbitMQ开机启动 Centos7环境

文章目录8.1. 创建启动脚本8.2. 赋予启动脚本可执行权限8.3. 加入开机启动并指定用户8.4. 赋予可执行权限8.5. 重启MQ服务器测试8.6. 查看MQ服务运行状态8.7. 浏览器验证MQ管控台8.1. 创建启动脚本 操作说明&#xff1a;使用fismq用户操作&#xff0c;使用root用户权限的地方我…