原作:PAWEŁ FERTYK  翻译:大江狗

原文链接:https://pfertyk.me/2017/06/getting-mars-photos-from-nasa-using-aiohttp/

小编注:aiohttp是基于asyncio实现的异步http框架。本文案例也可以使用异步django实现。

我是Andy Weir写的《火星人》一书的忠实粉丝。阅读时,我想知道马克·沃特尼(Mark Watney)绕着红色星球走的感觉如何。最近,多亏了 Twilio的这篇博文, 我发现NASA提供了一个公共API,可以提供火星漫游者拍摄的照片。但是,由于不是MMS的忠实拥护者,我决定编写自己的应用程序,以将具有启发性的图像直接传递到我的浏览器中。

创建aiohttp应用程序

让我们从一个简单的应用程序开始,只是为了启动和运行aiohttp。首先,创建一个新的virtualenv。建议使用Python 3.5以后版本,因为我们将使用asyncio提供的async defawait语法。如果您想进一步开发该项目并利用异步理解的优势,则可以使用Python 3.6(本例使用python版本)。接下来,安装aiohttp:

pip install aiohttp

现在创建一个python文件(称为nasa.py),并将一些代码放入其中:

from aiohttp import webasync def get_mars_photo(request):return web.Response(text='A photo of Mars')app = web.Application()
app.router.add_get('/', get_mars_photo, name='mars_photo')

如果您不熟悉aiohttp,则可能需要说明以下几点:

  • get_mars_photo协程是一个请求处理程序;它以HTTP请求作为唯一参数,并负责返回HTTP响应(或引发异常)

  • app是高级服务器;它支持路由器,中间件和信号(对于该程序,我们将仅使用路由器)

  • app.router.add_get 在HTTP GET方法和'/'路径上注册请求处理程序

注意:请求处理程序不必一定是协程,它们可以是常规函数。但是我们将使用asyncio的功能,因此程序中的大多数函数都将使用进行定义async def

运行应用程序

要运行您的应用程序,您可以在文件末尾添加以下行:

web.run_app(app, host='127.0.0.1', port=8080)

然后像运行其他任何Python脚本一样运行它:

python nasa.py

但是有更好的方法。在许多第三方库中,您可以找到aiohttp-devtools。它提供了一个很好的runserver命令,可以自动检测您的应用并支持实时重载:

pip install aiohttp-devtools
adev runserver -p 8080 nasa.py

现在如果您访问localhost:8080,则应该在浏览器中看到"A photo of mars"的字样。

使用NASA API

当然,这还没有结束。如果您是一位敏锐的观察者,您会注意到我们没有得到实际的图像,而是一些文本。现在让我们解决这个问题。

要从火星获取照片,我们将使用NASA API。每个火星探路者(rover)都有自己的URL(对于好奇号,它url是https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos)。我们必须为每个请求至少提供2个参数:

  • sol:火星轮转或拍摄照片的日期,从探路者的着陆日期开始算起(最大值可以rover/max_sol在响应的一部分中找到 )

  • API_KEY:由美国航天局提供的API密钥(你可以使用默认的:DEMO_KEY

响应数据里我们将获得一张照片列表,每张照片均带有URL,相机信息和探路者信息。

修改nasa.py文件,如下所示:

import randomfrom aiohttp import web, ClientSession
from aiohttp.web import HTTPFoundNASA_API_KEY = 'DEMO_KEY'
ROVER_URL = 'https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos'async def get_mars_image_url_from_nasa():while True:sol = random.randint(0, 1722)params = {'sol': sol, 'api_key': NASA_API_KEY}async with ClientSession() as session:async with session.get(ROVER_URL, params=params) as resp:resp_dict = await resp.json()if 'photos' not in resp_dict:raise Exceptionphotos = resp_dict['photos']if not photos:continuereturn random.choice(photos)['img_src']async def get_mars_photo(request):url = await get_mars_image_url_from_nasa()return HTTPFound(url)

到底发生了什么事?

  • 我们选择一个随机拍摄日期(对于“好奇心” max_sol,在撰写本文时,其值为1722)

  • ClientSession 创建一个会话,我们可以使用该会话从NASA API获取响应

  • 我们使用获取JSON响应 resp.json()

  • 我们检查响应中是否存在“照片”键;如果没有,我们已经达到了每小时请求数量的上限,我们需要稍等片刻

  • 如果当天没有照片,我们会再次检查是否有其他拍摄时间

  • 然后,我们使用HTTPFound响应重定向到找到的照片

获取NASA API密钥

DEMO_KEYNASA提供的默认设置可以正常工作,但是您很快就会达到每小时API调用的限制。我建议您获取自己的API密钥。您可以在此处进行操作 (注册过程非常简单快捷)。

现在,当您运行该应用程序时,您将直接从火星重定向到一个漂亮的图像:

好吧,这不完全是我的意思...

验证图像

您刚刚看到的图像并不让人受到启发。事实证明,漫游者拍摄了很多非常无聊的照片。我想看看马克·沃特尼(Mark Watney)在他不可思议的旅程中所看到的,但这还不够好。让我们找到一种解决方法。

我们将需要对图像进行某种形式的验证。在指定筛选条件前,我们可以修改代码:

async def get_mars_photo_bytes():while True:image_url = await get_mars_image_url_from_nasa()async with ClientSession() as session:async with session.get(image_url) as resp:image_bytes = await resp.read()if await validate_image(image_bytes):breakreturn image_bytesasync def get_mars_photo(request):image = await get_mars_photo_bytes()return web.Response(body=image, content_type='image/jpeg')

这里发生了一些新的事情:

  • 我们使用先前定义的函数获取URL,然后使用读取图像中的原始字节 resp.read()

  • 我们检查我们的图片是否足够好;如果没有,我们一直在寻找

  • 一旦有了令人满意的照片,我们会将其放入响应中(注意,我们仍然使用与web.Response以前相同的照片,但是这次我们指定body 而不是text,同时了定义content_type

注意:在此代码中,我们删除了重定向(HTTPFound),因此现在我们可以轻松地刷新页面以获取另一个图像。

现在我们需要弄清楚如何验证照片。我们可以很容易做到的一件事就是检查图像尺寸否足够大。这不是一个完美的验证,但现在应该这样做。要处理图像,我们将需要python的图片库Pillow。

pip install pillow

我们的验证函数可能如下所示:

import io
from PIL import Imageasync def validate_image(image_bytes):image = Image.open(io.BytesIO(image_bytes))return image.width >= 1024 and image.height >= 1024

现在刷新浏览器,应该可以看到火星大图了。

现在我们可以更进一步,拒绝灰度图像:

async def validate_image(image_bytes):image = Image.open(io.BytesIO(image_bytes))return image.width >= 1024 and image.height >= 1024 and image.mode != 'L'

现在我们的程序开始返回更多鼓舞人心的照片:

偶尔还能看到机器人自拍:

总结

我们整个程序如下所示:

import random
import iofrom aiohttp import web, ClientSessionfrom PIL import ImageNASA_API_KEY = 'DEMO_KEY'
ROVER_URL = 'https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos'async def validate_image(image_bytes):image = Image.open(io.BytesIO(image_bytes))return image.width >= 1024 and image.height >= 1024 and image.mode != 'L'async def get_mars_image_url_from_nasa():while True:sol = random.randint(0, 1722)params = {'sol': sol, 'api_key': NASA_API_KEY}async with ClientSession() as session:async with session.get(ROVER_URL, params=params) as resp:resp_dict = await resp.json()if 'photos' not in resp_dict:raise Exceptionphotos = resp_dict['photos']if not photos:continuereturn random.choice(photos)['img_src']async def get_mars_photo_bytes():while True:image_url = await get_mars_image_url_from_nasa()async with ClientSession() as session:async with session.get(image_url) as resp:image_bytes = await resp.read()if await validate_image(image_bytes):breakreturn image_bytesasync def get_mars_photo(request):image = await get_mars_photo_bytes()return web.Response(body=image, content_type='image/jpeg')app = web.Application()
app.router.add_get('/', get_mars_photo, name='mars_photo')

我们还可以改善很多事情(例如max_sol从API中获取价值,传递流动站的名称,缓存URL),但是现在它已经完成了工作:我们可以得到一张随机的,鼓舞人心的火星照片,并觉得我们确实在那里。

我希望您喜欢这个简短的教程。如果您发现错误或有任何疑问,请告诉我。

大江狗点评

本例使用aiohttp异步抓取了火星的图片,也可以通过Django异步, requests或httpx库实现。Python web开发异步编程越来越重要,建议大家重视关注。

推荐阅读

非常适合小白的 Asyncio 教程

支持异步的新一代Python网络请求库Httpx介绍

Python协程与异步编程(asyncio库)总结

是时候试试Django 3.1新的异步视图功能了

使用python异步框架aiohttp从NASA抓取火星图片相关推荐

  1. Python异步爬虫之协程抓取妹子图片(aiohttp、aiofiles)

    目录 前言 一.什么是协程? 二.协程的优势 三.代码分析 1.引入库 2.获取所有时间线的链接 3.获取一个时间线中所有相册的链接 4.获取一个相册中所有的图片链接以及相册的名字 5.下载并保存图片 ...

  2. python的前端框架_web前端三大主流框架之Python异步框架如何工作?

    这篇文章我们从 socket 编程的例子来看看 Python 异步框架是如何工作的,需要了解下简单的 socket 编程以及 Linux 提供的 I/O 复用机制. Python 异步框架也是基于操作 ...

  3. python scrapy框架 抓取的图片路径打不开图片_Python使用Scrapy爬虫框架全站爬取图片并保存本地的实现代码...

    大家可以在Github上clone全部源码. 基本上按照文档的流程走一遍就基本会用了. Step1: 在开始爬取之前,必须创建一个新的Scrapy项目. 进入打算存储代码的目录中,运行下列命令: sc ...

  4. python中国大学排名爬虫写明详细步骤-Python爬虫--2019大学排名数据抓取

    Python爬虫--2019大学排名数据抓取 准备工作 输入:大学排名URL连接 输出:大学排名信息屏幕输出 所需要用到的库:requests,bs4 思路 获取网页信息 提取网页中的内容并放到数据结 ...

  5. python爬虫资源大全_Python爬虫抓取纯静态网站及其资源(基础篇)

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 以下文章来源于腾讯云 作者:程序员宝库 **( 想要学习Python?Python ...

  6. Python进阶之Scrapy利用ImagesPipeline抓取汽车之家宝马5系缩略图

    Python进阶之Scrapy利用ImagesPipeline抓取汽车之家宝马5系缩略图 1. 创建项目 2. 使用ImagesPipeline爬取数据 items.py setings.py aut ...

  7. Python3网络爬虫之Scrapy框架实现招聘数据抓取

    项目需求: 某招聘网上面有公司发布的的各种工作岗位,进入首页 https://careers.tencent.com/ 后可见 到一个搜索框,如下图所示: 在搜索框输入岗位名称,跳转到如下图所示页面, ...

  8. Python语言程序设计之urllib.request抓取页面,网易公开课之《麻省理工学院公开课:算法导论》

    Python语言用urllib.request模块抓取页面非常简单,再将抓取的页面内容用re模块解析,找出自己想要的东西.下面就就此方法来抓取网易公开课之<麻省理工学院公开课:算法导论>, ...

  9. python抓取网站图片_利用python抓取网站图片

    看了网上关于python抓取网站图片的例子,所以自己也尝试着写一个,但是发现这个网站的src不是标准的路径,需要自己添加前面的目录地址,尝试了几次也不成功,所以希望有经验的朋友指导下. 本人是初学者, ...

最新文章

  1. muduo之ThreadPool
  2. c语言代码大全500行,C语言职工档案管理系统 500多行代码1
  3. html 树状折叠,折叠树状页.html
  4. 解决deepin微信无法登录
  5. 【MyBatis框架】高级映射-延迟加载
  6. spring mvc对异步请求的处理
  7. 【英语学习】【WOTD】purview 释义/词源/示例
  8. layui动态渲染生成select的option值
  9. Quartus II 13.1的安装及使用
  10. 高等数学和计算机相结合的论文,高等数学教学与专业结合模式的初步探索论文...
  11. 华为路由器配置OSPF实现不同网段通信
  12. 多线程的实现和使用场景
  13. 【PyTorch深度学习项目实战100例】—— 基于ResNet50实现多目标美味蛋糕图像分类 | 第51例
  14. 利用百度进行人脸搜索
  15. flyingsaucer转换多个html,java - 使用FlyingSaucer将包含阿拉伯字符的HTML页面转换为PDF - 堆栈内存溢出...
  16. DbVisualizer 10破解之后,在输入框使用光标无法准确定位字符
  17. 仿xp画板、画图重绘、五子棋总结
  18. 计算机管理服务哪个是打印机的,开启打印机服务,教您win7开启打印机服务
  19. 51Nod 2069 牛奶 c/c++题解
  20. 多表(三个表)插入与删除操作

热门文章

  1. 被“现实”打败的3D打印
  2. 动物识别系统-tensorflow项目
  3. BLE蓝牙芯片KT1025A程序代码和调试总结
  4. 高博十四讲中第六章非线性优化 由于g2o更新出现的问题解决
  5. 【解决方案】摄像机户外直播能在哪些地方运用?团建/项目启动会/户外婚礼等户外直播方案介绍
  6. 如何做电视节目的视频直播(电视台节目直播)
  7. 瑞萨RA MCU立创EDA训练营——自制瑞萨开发板
  8. 【成员故事】CSDN杨东杰:生态运营需要一个自己的圈子
  9. 搜索中常见数据结构与算法探究(二)
  10. java面条对折问题