《实用的人工智能》一书 机器学习和云技术

图片 嗨,habrozhiteli! 这本Noah礼品书适用于对AI,机器学习,云计算以及数据主题的任何组合感兴趣的任何人。 程序员和仅仅是关心技术的人都可以在这里找到有用的信息。 用Python给出了代码示例。 它涵盖了许多高级主题,例如云平台的使用(例如AWS,GCP和Azure)以及机器学习技术和AI的实现。 精通Python,云计算和ML的Jedi也将为自己找到许多有用的想法,这些想法可以立即应用于当前的工作中。

我们邀请您阅读“在AWS中创建智能Slack机器人”一书的节选

人们一直梦想着创造一种“人造生活”。 通常,尽管这可以通过创建机器人来实现。 机器人已成为我们日常生活中越来越不可或缺的一部分,尤其是自苹果公司的Siri和亚马逊公司的Alexa问世以来。 在本章中,我们将揭示创建机器人的所有秘密。

机器人创造


为了创建机器人,我们将使用Python语言的Slack库(https://github.com/slackapi/python-slackclient)。 要开始使用Slack,您需要生成一个标识令牌。 通常,使用此类标记导出环境变量是有意义的。 我经常在virtualenv中执行此操作,因此在当前环境中执行时会自动获得对其的访问。 为此,您需要通过编辑激活脚本来“破解” virtualenv实用程序。

在〜/ .env / bin / activate脚本中导出Slack变量时,它将类似于以下内容。

仅作为参考,如果您想跟上最新的创新,建议使用新的官方Python实用程序来管理环境-pipenv(https://github.com/pypa/pipenv):

_OLD_VIRTUAL_PATH="$PATH" PATH="$VIRTUAL_ENV/bin:$PATH" export PATH SLACK_API_TOKEN=<Your Token Here> export SLACK_API_TOKEN 

使用OS X和Linux操作系统的printenv命令来检查是否设置了环境变量是很方便的。 之后,您可以使用以下简短脚本来验证消息的发送:

 import os from slackclient import SlackClient slack_token = os.environ["SLACK_API_TOKEN"] sc = SlackClient(slack_token) sc.api_call( "chat.postMessage", channel="#general", text="Hello from my bot! :tada:" ) 

还应注意,pipenv实用程序是推荐的解决方案,将pip和virtualenv实用程序的功能组合在一个组件中。 它已经成为一个新标准,因此从软件包管理的角度来看它是有意义的。

将库转换为命令行实用程序


与本书中的其他示例一样,将我们的代码转换为命令行实用程序是一个好主意,以使测试新主意更加容易。 值得注意的是,许多新手开发人员通常不喜欢命令行工具,而是使用其他解决方案,例如,它们只能在Jupiter笔记本电脑上工作。 我将短暂扮演恶魔律师的角色,并向读者提出一个问题:“为什么在基于Jupiter笔记本的项目中我们需要命令行实用程序? Jupiter记事本是否不需要不必要的命令外壳和命令行?” 将命令行实用程序添加到项目中是很好的,因为它使您可以快速尝试不同的输入选项。 Jupiter笔记本代码块不接受输入;从某种意义上讲,这些是带有硬连线数据的脚本。

GCP和AWS平台上的许多命令行实用程序都不是偶然存在的:它们提供了图形界面上没有的灵活性和功能。 科幻小说家尼尔·史蒂文森(Neal Stephenson)撰写的一本关于该主题的精彩论文集被称为“从头开始……那里是一条命令行”。 史蒂文森在其中说:“对于每一个甚至完全改变编程环境的软件组件,即使是最小的GUI,GUI也会带来相当大的额外开销。” 他用以下词语结束了收藏:“……生活是一件非常艰辛的事情; 没有接口会改变这一点; 还有其他认为是简单的人……“足够坚强,但我的经验表明这是真的。 命令行的生活越来越好。 尝试一下,您将不想回到GUI。

为此,我们将使用click程序包,如下所示。 使用新界面发送消息非常简单。

 ./clibot.py send --message "from cli" sending message from cli to #general 

图7.1显示了默认值以及来自cli实用程序的自定义消息。

 #!/usr/bin/env python import os import click from slackclient import SlackClient SLACK_TOKEN = os.environ["SLACK_API_TOKEN"] def send_message(channel="#general", message="Hello from my bot!"): """   """ slack_client = SlackClient(SLACK_TOKEN) res = slack_client.api_call( "chat.postMessage", channel=channel, text=message ) return res @click.group() @click.version_option("0.1") def cli(): """      """ @cli.command("send") @click.option("--message", default="Hello from my bot!", help="text of message") @click.option("--channel", default="#general", help="general channel") def send(channel, message): click.echo(f"sending message {message} to {channel}") send_message(channel, message=message) if __name__ == '__main__': cli() 

图片

我们使用AWS Step Functions服务将机器人提升到一个新的高度


在创建用于向Slack发送消息的通信渠道之后,您可以改进我们的代码,即:按计划运行它,并将其用于任何有用的操作。 AWS Step Functions服务非常适合此用途。 在下一部分中,我们的Slack机器人将学习如何抓取Yahoo!的体育页面。 NBA球员,获取他们的出生地,然后将数据发送到Slack。

图7.2显示了现成的逐步操作功能。 第一步是提取NBA球员个人资料URL,第二步是使用Beautiful Soup库查找每个球员的出生地。 完成分步功能后,结果将发送回Slack。

图片

AWS Lambda和Chalice可用于在step函数中协调工作的各个部分。 Lambda(https://aws.amazon.com/lambda/)允许用户在AWS中执行功能,而Chalice框架(http://chalice.readthedocs.io/en/latest/)允许您在Py​​thon中创建无服务器应用程序。 这是一些先决条件:

  • 用户必须具有一个AWS账户。
  • 用户需要凭据才能使用API​​;
  • Lambda角色(由Chalice创建)必须具有一个策略,该策略具有调用相应的AWS服务(例如S3)所需的特权。

配置IAM凭据


可以在boto3.readthedocs.io/en/latest/guide/configuration.html上找到设置AWS凭证的详细说明。 可在此处找到有关在Windows和Linux操作系统上导出AWS变量的信息。 有多种配置凭证的方法,但是virtualenv用户可以在/ bin / activate脚本中将AWS凭证放入本地虚拟环境中:

 #  AWS AWS_DEFAULT_REGION=us-east-1 AWS_ACCESS_KEY_ID=xxxxxxxx AWS_SESSION_TOKEN=xxxxxxxx 


 #  export AWS_DEFAULT_REGION export AWS_ACCESS_KEY_ID export AWS_DEFAULT_REGION 

与圣杯一起工作。 Chalice有一个命令行实用程序,其中包含许多可用命令:

 Usage: chalice [OPTIONS] COMMAND [ARGS]... Options: --version Show the version and exit. --project-dir TEXT The project directory. Defaults to CWD --debug / --no-debug Print debug logs to stderr. --help Show this message and exit. Commands: delete deploy gen-policy generate-pipeline Generate a cloudformation template for a... generate-sdk local logs new-project package url 

app.py模板中的代码可以替换为Lambda服务函数。 AWS Chalice的方便之处在于,除了Web服务之外,它还可以创建“独立” Lambda函数。 借助此功能,您可以创建多个Lambda函数,将它们与逐步函数相关联,并将它们像Lego多维数据集一样组合在一起。

例如,您可以轻松创建将执行任何操作的预定Lambda函数:

 @app.schedule(Rate(1, unit=Rate.MINUTES)) def every_minute(event): """,    """ #   Slack 

要与用于网络抓取的机器人建立交互,您需要创建多个功能。 在文件的开头,有导入,并声明了许多变量:

 import logging import csv from io import StringIO import boto3 from bs4 import BeautifulSoup import requests from chalice import (Chalice, Rate) APP_NAME = 'scrape-yahoo' app = Chalice(app_name=APP_NAME) app.log.setLevel(logging.DEBUG) 

机器人可能需要在S3中存储一些数据。 以下功能使用Boto将结果保存到CSV文件中:

 def create_s3_file(data, name="birthplaces.csv"): csv_buffer = StringIO() app.log.info(f"Creating file with {data} for name") writer = csv.writer(csv_buffer) for key, value in data.items(): writer.writerow([key,value]) s3 = boto3.resource('s3') res = s3.Bucket('aiwebscraping').\ put_object(Key=name, Body=csv_buffer.getvalue()) return res 

fetch_page函数使用Beautiful Soup库来解析根据NBA统计信息URL定位的HTML页面,并返回汤对象:

 def fetch_page(url="https://sports.yahoo.com/nba/stats/"): """ URL Yahoo""" #       #  Beautiful Soup app.log.info(f"Fetching urls from {url}") res = requests.get(url) soup = BeautifulSoup(res.content, 'html.parser') return soup 

get_player_links和fetch_player_urls函数获取指向玩家资料URL的链接:

 def get_player_links(soup): """   URL    URL     'a'       'nba/players' """ nba_player_urls = [] for link in soup.find_all('a'): link_url = link.get('href') #  if link_url: if "nba/players" in link_url: print(link_url) nba_player_urls.append(link_url) return nba_player_urls def fetch_player_urls(): """ URL """ soup = fetch_page() urls = get_player_links(soup) return urls 

接下来,在find_birthplaces函数中,我们从这些页面上的URL中提取玩家的出生地:

 def find_birthplaces(urls): """       NBA  Yahoo""" birthplaces = {} for url in urls: profile = requests.get(url) profile_url = BeautifulSoup(profile.content, 'html.parser') lines = profile_url.text res2 = lines.split(",") key_line = [] for line in res2: if "Birth" in line: #print(line) key_line.append(line) try: birth_place = key_line[0].split(":")[-1].strip() app.log.info(f"birth_place: {birth_place}") except IndexError: app.log.info(f"skipping {url}") continue birthplaces[url] = birth_place app.log.info(birth_place) return birthplaces 

现在,我们将继续介绍Chalice的功能。 请注意:对于Chalice框架,必须创建默认路径:

 #     HTTP- @app.route('/') def index(): """ URL""" app.log.info(f"/ Route: for {APP_NAME}") return {'app_name': APP_NAME} 

以下Lambda函数是将HTTP URL连接到先前编写的函数的路由:

 @app.route('/player_urls') def player_urls(): """ URL """ app.log.info(f"/player_urls Route: for {APP_NAME}") urls = fetch_player_urls() return {"nba_player_urls": urls} 

以下Lambda函数是独立的,可以在分步函数中调用它们:

 #   Lambda @app.lambda_function() def return_player_urls(event, context): """  Lambda,  URL """ app.log.info(f"standalone lambda 'return_players_urls'\ {APP_NAME} with {event} and {context}") urls = fetch_player_urls() return {"urls": urls} #   Lambda @app.lambda_function() def birthplace_from_urls(event, context): """   """ app.log.info(f"standalone lambda 'birthplace_from_urls'\ {APP_NAME} with {event} and {context}") payload = event["urls"] birthplaces = find_birthplaces(payload) return birthplaces #   Lambda @app.lambda_function() def create_s3_file_from_json(event, context): """  S3      JSON""" app.log.info(f"Creating s3 file with event data {event}\ and context {context}") print(type(event)) res = create_s3_file(data=event) app.log.info(f"response of putting file: {res}") return True 

如果您在本地运行生成的Chalice应用程序,将显示以下结果:

 → scrape-yahoo git:(master)  chalice local Serving on 127.0.0.1:8000 scrape-yahoo - INFO - / Route: for scrape-yahoo 127.0.0.1 - - [12/Dec/2017 03:25:42] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [12/Dec/2017 03:25:42] "GET /favicon.ico" scrape-yahoo - INFO - / Route: for scrape-yahoo 127.0.0.1 - - [12/Dec/2017 03:25:45] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [12/Dec/2017 03:25:45] "GET /favicon.ico" scrape-yahoo - INFO - /player_urls Route: for scrape-yahoo scrape-yahoo - INFO - https://sports.yahoo.com/nba/stats/ https://sports.yahoo.com/nba/players/4563/ https://sports.yahoo.com/nba/players/5185/ https://sports.yahoo.com/nba/players/3704/ https://sports.yahoo.com/nba/players/5012/ https://sports.yahoo.com/nba/players/4612/ https://sports.yahoo.com/nba/players/5015/ https://sports.yahoo.com/nba/players/4497/ https://sports.yahoo.com/nba/players/4720/ https://sports.yahoo.com/nba/players/3818/ https://sports.yahoo.com/nba/players/5432/ https://sports.yahoo.com/nba/players/5471/ https://sports.yahoo.com/nba/players/4244/ https://sports.yahoo.com/nba/players/5464/ https://sports.yahoo.com/nba/players/5294/ https://sports.yahoo.com/nba/players/5336/ https://sports.yahoo.com/nba/players/4390/ https://sports.yahoo.com/nba/players/4563/ https://sports.yahoo.com/nba/players/3704/ https://sports.yahoo.com/nba/players/5600/ https://sports.yahoo.com/nba/players/4624/ 127.0.0.1 - - [12/Dec/2017 03:25:53] "GET /player_urls" 127.0.0.1 - - [12/Dec/2017 03:25:53] "GET /favicon.ico" 

要部署该应用程序,请运行chalice deploy命令:

 → scrape-yahoo git:(master)  chalice deploy Creating role: scrape-yahoo-dev Creating deployment package. Creating lambda function: scrape-yahoo-dev Initiating first time deployment. Deploying to API Gateway stage: api https://bt98uzs1cc.execute-api.us-east-1.amazonaws.com/api/ 

感谢HTTP的命令行界面(https://github.com/jakubroztocil/httpie),我们从AWS调用了HTTP路由,并提取了/ api / player_urls中可用的链接:

 → scrape-yahoo git:(master)  http \ https://<a lambda route>.amazonaws.com/api/player_urls HTTP/1.1 200 OK Connection: keep-alive Content-Length: 941 Content-Type: application/json Date: Tue, 12 Dec 2017 11:48:41 GMT Via: 1.1 ba90f9bd20de9ac04075a8309c165ab1.cloudfront.net (CloudFront) X-Amz-Cf-Id: ViZswjo4UeHYwrc9e-5vMVTDhV_Ic0dhVIG0BrDdtYqd5KWcAuZKKQ== X-Amzn-Trace-Id: sampled=0;root=1-5a2fc217-07cc12d50a4d38a59a688f5c X-Cache: Miss from cloudfront x-amzn-RequestId: 64f24fcd-df32-11e7-a81a-2b511652b4f6 { "nba_player_urls": [ "https://sports.yahoo.com/nba/players/4563/", "https://sports.yahoo.com/nba/players/5185/", "https://sports.yahoo.com/nba/players/3704/", "https://sports.yahoo.com/nba/players/5012/", "https://sports.yahoo.com/nba/players/4612/", "https://sports.yahoo.com/nba/players/5015/", "https://sports.yahoo.com/nba/players/4497/", "https://sports.yahoo.com/nba/players/4720/", "https://sports.yahoo.com/nba/players/3818/", "https://sports.yahoo.com/nba/players/5432/", "https://sports.yahoo.com/nba/players/5471/", "https://sports.yahoo.com/nba/players/4244/", "https://sports.yahoo.com/nba/players/5464/", "https://sports.yahoo.com/nba/players/5294/", "https://sports.yahoo.com/nba/players/5336/", "https://sports.yahoo.com/nba/players/4390/", "https://sports.yahoo.com/nba/players/4563/", "https://sports.yahoo.com/nba/players/3704/", "https://sports.yahoo.com/nba/players/5600/", "https://sports.yahoo.com/nba/players/4624/" ] } 

使用Lambda函数的另一种便捷方法是使用click包和Python Boto库直接调用它们。

我们可以创建一个名为wscli.py的新命令行实用程序(Web抓取命令行界面的缩写-“ Web抓取的命令行界面”)。 在代码的第一部分中,我们配置日志记录并导入库:

 #!/usr/bin/env python import logging import json import boto3 import click from pythonjsonlogger import jsonlogger #  log = logging.getLogger(__name__) log.setLevel(logging.INFO) LOGHANDLER = logging.StreamHandler() FORMMATTER = jsonlogger.JsonFormatter() LOGHANDLER.setFormatter(FORMMATTER) log.addHandler(LOGHANDLER) 

以下三个函数旨在通过invoke_lambda连接到Lambda函数:

 ### API Boto Lambda def lambda_connection(region_name="us-east-1"): """   Lambda""" lambda_conn = boto3.client("lambda", region_name=region_name) extra_msg = {"region_name": region_name, "aws_service": "lambda"} log.info("instantiate lambda client", extra=extra_msg) return lambda_conn def parse_lambda_result(response): """     Boto   JSON""" body = response['Payload'] json_result = body.read() lambda_return_value = json.loads(json_result) return lambda_return_value def invoke_lambda(func_name, lambda_conn, payload=None, invocation_type="RequestResponse"): """  Lambda""" extra_msg = {"function_name": func_name, "aws_service": "lambda", "payload":payload} log.info("Calling lambda function", extra=extra_msg) if not payload: payload = json.dumps({"payload":"None"}) response = lambda_conn.invoke(FunctionName=func_name, InvocationType=invocation_type, Payload=payload ) log.info(response, extra=extra_msg) lambda_return_value = parse_lambda_result(response) return lambda_return_value 

我们用Python包包装invoke_lambda函数,以创建Click命令行实用程序。 请注意,我们为--func选项设置了默认值,该选项使用我们先前部署的Lambda函数:

 @click.group() @click.version_option("1.0") def cli(): """     -""" @cli.command("lambda") @click.option("--func", default="scrape-yahoo-dev-return_player_urls", help="name of execution") @click.option("--payload", default='{"cli":"invoke"}', help="name of payload") def call_lambda(func, payload): """  Lambda ./wscli.py lambda """ click.echo(click.style("Lambda Function invoked from cli:", bg='blue', fg='white')) conn = lambda_connection() lambda_return_value = invoke_lambda(func_name=func, lambda_conn=conn, payload=payload) formatted_json = json.dumps(lambda_return_value, sort_keys=True, indent=4) click.echo(click.style( "Lambda Return Value Below:", bg='blue', fg='white')) click.echo(click.style(formatted_json,fg="red")) if __name__ == "__main__": cli() 

该实用程序显示的结果类似于调用HTTP接口:

 → X ./wscli.py lambda \ --func=scrape-yahoo-dev-birthplace_from_urls\ --payload '{"url":["https://sports.yahoo.com/nba/players/4624/",\ "https://sports.yahoo.com/nba/players/5185/"]}' Lambda Function invoked from cli: {"message": "instantiate lambda client", "region_name": "us-east-1", "aws_service": "lambda"} {"message": "Calling lambda function", "function_name": "scrape-yahoo-dev-birthplace_from_urls", "aws_service": "lambda", "payload": "{\"url\":[\"https://sports.yahoo.com/nba/players/4624/\", \"https://sports.yahoo.com/nba/players/5185/\"]}"} {"message": null, "ResponseMetadata": {"RequestId": "a6049115-df59-11e7-935d-bb1de9c0649d", "HTTPStatusCode": 200, "HTTPHeaders": {"date": "Tue, 12 Dec 2017 16:29:43 GMT", "content-type": "application/json", "content-length": "118", "connection": "keep-alive", "x-amzn-requestid": "a6049115-df59-11e7-935d-bb1de9c0649d", "x-amzn-remapped-content-length": "0", "x-amz-executed-version": "$LATEST", "x-amzn-trace-id": "root=1-5a3003f2-2583679b2456022568ed0682;sampled=0"}, "RetryAttempts": 0}, "StatusCode": 200, "ExecutedVersion": "$LATEST", "Payload": "<botocore.response.StreamingBody object at 0x10ee37dd8>", "function_name": "scrape-yahoo-dev-birthplace_from_urls", "aws_service": "lambda", "payload": "{\"url\":[\"https://sports.yahoo.com/nba/players/4624/\", \"https://sports.yahoo.com/nba/players/5185/\"]}"} Lambda Return Value Below: { "https://sports.yahoo.com/nba/players/4624/": "Indianapolis", "https://sports.yahoo.com/nba/players/5185/": "Athens" } 

完成分步功能的创建


如AWS文档(https://docs.aws.amazon.com/step-functions/latest/dg/tutorial-creating-activity-state-machine.html)所述,创建分步功能的最后一步是使用状态机结构的Web界面,采用JavaScript对象符号(JSON)格式。 以下代码演示了该管道,从原始的Lambda函数开始,这些函数用于抓取Yahoo !,将数据存储在S3文件中,最后将内容发送到Slack:

 { "Comment": "Fetch Player Urls", "StartAt": "FetchUrls", "States": { "FetchUrls": { "Type": "Task", "Resource": \ "arn:aws:lambda:us-east-1:561744971673:\ function:scrape-yahoo-dev-return_player_urls", "Next": "FetchBirthplaces" }, "FetchBirthplaces": { "Type": "Task", "Resource": \ "arn:aws:lambda:us-east-1:561744971673:\ function:scrape-yahoo-dev-birthplace_from_urls", "Next": "WriteToS3" }, "WriteToS3": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:\ 561744971673:function:scrape-yahoo-dev-create_s3_file_from_json", "Next": "SendToSlack" }, "SendToSlack": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:561744971673:\ function:send_message", "Next": "Finish" }, "Finish": { "Type": "Pass", "Result": "Finished", "End": true } } } 

在图。 7.2显示了该管道的第一部分的执行。 查看状态机的中间结果非常有用。 此外,实时监视状态机各部分的功能非常便于调试。

图7.3显示了一个完整的管道,其中增加了写入S3文件并将内容发送到Slack的步骤。 剩下的只是决定如何在特定时间间隔或响应事件运行此抓取实用程序。

图片

总结


在本章中,向您介绍了许多构建AI应用程序的惊人概念。 它创建了Slack机器人和Web抓取实用程序,然后使用来自AWS的无服务器服务进行了连接。 您可以在这种初始框架中添加更多的内容-例如,用于处理以自然语言编写的文本以阅读网页并获取其简要内容的Lambda函数,或者在没有老师的情况下进行聚类算法,这将通过任意属性将新的NBA球员聚类。

»这本书的更多信息可以在出版商的网站上找到
» 目录
» 摘录

快递公司优惠券20%的折扣- 礼物

PS:这本书的成本的7%将用于新计算机书籍的翻译,移交给印刷厂的书籍清单在此处

Source: https://habr.com/ru/post/zh-CN439990/


All Articles