具有异步协同程序的Web爬虫(一)

A. Jesse Jiryu Davis是纽约MongoDB的工程师。他撰写了Motor,即异步MongoDB Python驱动程序,他是MongoDB C驱动程序的主要开发者,也是PyMongo团队的成员。他贡献于asyncio和龙卷风。他写在http://emptysqua.re
Guido van Rossum是Python的创建者,它是网络和网络上的主要编程语言之一。
Python社区将他称为BDFL(Benevolent Dictator For Life),一个直接来自Monty Python短片的标题。
Guido在网上的家是http://www.python.org/~guido/

介绍

古典计算机科学强调有效的算法,尽可能快地完成计算。但是许多网络程序花费时间不用计算,但是保持开放的许多连接速度很慢,或者是偶然的事件。
这些程序提出了一个非常不同的挑战:有效地等待大量的网络事件。这个问题的现代方法是异步I / O或“异步”。

本章介绍一个简单的网络爬虫。爬虫是一个原型的异步应用程序,因为它等待许多响应,但几乎没有计算。
一次可以获取的页面越多,越快完成。如果它将线程用于每个正在运行的请求,那么随着并发请求数量的增加,它将在内存不足或其他与线程相关的资源耗尽内存之前耗尽。它通过使用异步I / O避免了线程的需要。

我们将这个例子分为三个阶段。首先,我们显示一个异步事件循环,并绘制一个使用事件循环与回调的爬网程序:它是非常有效的,但将其扩展到更复杂的问题将导致无法管理的意大利面条代码。第二,因此,我们展示了Python协同程序是高效和可扩展的。我们使用生成器函数在Python中实现简单的协同程序。
在第三阶段,我们使用Python标准“asyncio”库(http://aosabook.org/en/500L/a-web-crawler-with-asyncio-coroutines.html#fn1)的全功能协同程序,并使用异步队列进行协调。

任务

网页抓取工具查找并下载网站上的所有页面,也许可以归档或索引。从根URL开始,它会获取每个页面,解析它以查看页面的链接,并将其添加到队列中。它在获取没有未看到的链接的页面并且队列为空时停止。

我们可以通过同时下载多个页面来加速这个过程。当抓取工具找到新的链接时,它会在单独的插槽上启动对新页面的同时提取操作。它在到达时解析响应,向队列添加新链接。可能会出现一些递减的回报,其中太多的并发降低性能,因此我们将并发请求的数量上限,并将其余链接留在队列中,直到某些正在运行的请求完成。

传统方法

我们如何使爬虫并发?传统上我们将创建一个线程池。每个线程将通过套接字一次下载一页。例如,要下载一个页面xkcd.com

def fetch(url):
    sock = socket.socket()
    sock.connect(('xkcd.com', 80))
    request = 'GET {} HTTP/1.0\r\nHost: xkcd.com\r\n\r\n'.format(url)
    sock.send(request.encode('ascii'))
    response = b''
    chunk = sock.recv(4096)
    while chunk:
        response += chunk
        chunk = sock.recv(4096)

    # Page is now downloaded.
    links = parse_links(response)
    q.add(links)

默认情况下,插座操作阻塞:当线程调用等的方法connect或者recv,它会暂停,直到操作完成。2因此,一次下载多个页面,我们需要许多线程。复杂的应用程序通过在线程池中保留空闲线程来摊销线程创建的成本,然后检查它们以便重新使用以用于后续任务; 它与连接池中的套接字相同。

然而,线程是昂贵的,并且操作系统对进程,用户或机器可能具有的线程数量强制执行各种硬上限。
在Jesse的系统上,Python线程花费大约50k的内存,并启动数以万计的线程会导致失败。
如果我们在并发套接字上同时执行数万个并发操作,那么在我们用完了套接字之前,我们用完了线程。
线程上的线程开销或系统限制是瓶颈。在他有影响力的文章“C10K问题” 3中,Dan Kegel概述了I / O并发多线程的局限性。他开始,现在是网络服务器同时处理万个客户的时候了,你不觉得吗?毕竟网络是一个很大的地方。
凯格尔在1999年创造了“C10K”一词。现在有一万个连接听起来很精致,但问题只有在尺寸上才有变化,而不是实物。那么,当使用C10K的每个连接的线程是不切实际的。现在的帽子数量级更高。事实上,我们的玩具网络抓取工具可以正常工作。然而,对于非常大规模的应用程序,拥有成千上万的连接,仍然保留上限:有一个限制,大多数系统仍然可以创建套接字,但已经用完了线程。我们如何克服这个?

异步

异步I / O框架使用非阻塞套接字在单个线程上执行并发操作。在我们的异步抓取工具中,我们设置套接字非阻塞,然后我们开始连接到服务器:

sock = socket.socket()
sock.setblocking(False)
try:
    sock.connect(('xkcd.com', 80))
except BlockingIOError:
    pass

刺激性地,非阻塞套接字connect即使正常工作也会引起异常。此异常复制下面的C函数,它设置的刺激性行为errno来EINPROGRESS告诉你它已经开始。现在,我们的抓取工具需要一种方法来知道连接何时建立,因此可以发送HTTP请求。我们可以简单地继续努力:

request = 'GET {} HTTP/1.0\r\nHost: xkcd.com\r\n\r\n'.format(url)
encoded = request.encode('ascii')
while True:
    try:
        sock.send(encoded)
        break  # Done.
    except OSError as e:
        pass
print('sent')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容

  • title标题: A Web Crawler With asyncio Coroutinesauthor作者: A...
    彰乐乐乐乐阅读 2,029评论 0 8
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 明媚的笑容、清澈的眼神,源于家乡的水土。 爱你.请记得这个宝贝的温暖和美好,撒欢于家乡的广袤无垠。 麻麻和她的闺蜜...
    简_雅阁阅读 169评论 0 0
  • 他总会觉得自己似乎并不适合于周围的环境。 为什么这么讲呢? 他来自于一个贫困的家庭,全班四十七个人,一共有四十六部...
    我我不是我阅读 254评论 0 0
  • 為什么有那麼多新東西?
    史祖德阅读 182评论 0 1