Python tornado队列示例-一个并发web爬虫代码分享


Posted in Python onJanuary 09, 2018

Queue

Tornado的tornado.queue模块为基于协程的应用程序实现了一个异步生产者/消费者模式的队列。这与python标准库为多线程环境实现的queue模块类似。

一个协程执行到yieldqueue.get会暂停,直到队列中有条目。如果queue有上限,一个协程执行yieldqueue.put将会暂停,直到队列中有空闲的位置。

在一个queue内部维护了一个未完成任务的引用计数,每调用一次put操作便会增加引用计数,而调用task_done操作将会减少引用计数。

下面是一个简单的web爬虫的例子:

最开始,queue只包含一个基准url。当一个worker从中取出一个url后,它会从对应的页面中解析中所包含的url并将其放入队列,然后调用task_done减少引用计数一次。

最后,worker会取出一个url,而这个url页面中的所有url都已经被处理过了,这时队列中也没有url了。这时调用task_done会将引用计数减少至0.

这样,在main协程里,join操作将会解除挂起并结束主协程。

这个爬虫使用了HTMLParse来解析html页面。

import time
from datetime import timedelta

try:
 from HTMLParser import HTMLParser
 from urlparse import urljoin, urldefrag
except ImportError:
 from html.parser import HTMLParser
 from urllib.parse import urljoin, urldefrag

from tornado import httpclient, gen, ioloop, queues

base_url = 'http://www.tornadoweb.org/en/stable/'
concurrency = 10


@gen.coroutine
def get_links_from_url(url):
 """Download the page at `url` and parse it for links.

 Returned links have had the fragment after `#` removed, and have been made
 absolute so, e.g. the URL 'gen.html#tornado.gen.coroutine' becomes
 'http://www.tornadoweb.org/en/stable/gen.html'.
 """
 try:
  response = yield httpclient.AsyncHTTPClient().fetch(url)
  print('fetched %s' % url)

  html = response.body if isinstance(response.body, str) \
   else response.body.decode()
  urls = [urljoin(url, remove_fragment(new_url))
    for new_url in get_links(html)]
 except Exception as e:
  print('Exception: %s %s' % (e, url))
  raise gen.Return([])

 raise gen.Return(urls)

#用于从一个包含片段的url中提取中真正的url.
def remove_fragment(url):  
 pure_url, frag = urldefrag(url)
 return pure_url


def get_links(html):
 class URLSeeker(HTMLParser):
  def __init__(self):
   HTMLParser.__init__(self)
   self.urls = []

	#从所有a标签中提取中href属性。
  def handle_starttag(self, tag, attrs):
   href = dict(attrs).get('href')
   if href and tag == 'a':
    self.urls.append(href)

 url_seeker = URLSeeker()
 url_seeker.feed(html)
 return url_seeker.urls


@gen.coroutine
def main():
 q = queues.Queue()
 start = time.time()
 fetching, fetched = set(), set()

 @gen.coroutine
 def fetch_url():
  current_url = yield q.get()
  try:
   if current_url in fetching:
    return

   print('fetching %s' % current_url)
   fetching.add(current_url)
   urls = yield get_links_from_url(current_url)
   fetched.add(current_url)

   for new_url in urls:
    # Only follow links beneath the base URL
    if new_url.startswith(base_url):
     yield q.put(new_url)

  finally:
   q.task_done()

 @gen.coroutine
 def worker():
  while True:
   yield fetch_url()

 q.put(base_url)

 # Start workers, then wait for the work queue to be empty.
 for _ in range(concurrency):
  worker()
 yield q.join(timeout=timedelta(seconds=300))
 assert fetching == fetched
 print('Done in %d seconds, fetched %s URLs.' % (
  time.time() - start, len(fetched)))


if __name__ == '__main__':
 import logging
 logging.basicConfig()
 io_loop = ioloop.IOLoop.current()
 io_loop.run_sync(main)

总结

以上所述,来自Tornado官方网站用户指南的介绍和实例,这位同学进行了简单的翻译,然后把代码拿过来了。时间有些仓促,小编并未进行tornado的安装和对本段代码进行测试,故无结果演示,大家请见谅。

有关Python tornado队列示例-一个并发web爬虫代码分享的介绍就到这里了,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
python连接字符串的方法小结
Jul 13 Python
sublime text 3配置使用python操作方法
Jun 11 Python
Python多线程爬虫实战_爬取糗事百科段子的实例
Dec 15 Python
利用Python如何生成hash值示例详解
Dec 20 Python
python实现批量视频分帧、保存视频帧
May 31 Python
python安装scipy的步骤解析
Sep 28 Python
原来我一直安装 Python 库的姿势都不对呀
Nov 11 Python
Django更新models数据库结构步骤
Apr 01 Python
详解使用scrapy进行模拟登陆三种方式
Feb 21 Python
Python文件的操作示例的详细讲解
Apr 08 Python
Python制作一个随机抽奖小工具的实现
Jul 07 Python
Python如何快速找到多个字典中的公共键(key)
Apr 29 Python
Python中join函数简单代码示例
Jan 09 #Python
Python中顺序表的实现简单代码分享
Jan 09 #Python
python中set()函数简介及实例解析
Jan 09 #Python
Python中摘要算法MD5,SHA1简介及应用实例代码
Jan 09 #Python
深入了解Python中pop和remove的使用方法
Jan 09 #Python
Python使用smtp和pop简单收发邮件完整实例
Jan 09 #Python
Numpy中stack(),hstack(),vstack()函数用法介绍及实例
Jan 09 #Python
You might like
PHP 增加了对 .ZIP 文件的读取功能
2006/10/09 PHP
PHP 在5.1.* 和5.2.*之间 PDO数据库操作中的不同之处小结
2012/03/07 PHP
一个PHP针对数字的加密解密类
2014/03/20 PHP
php中spl_autoload详解
2014/10/17 PHP
PHP正则表达式 /i, /is, /s, /isU等介绍
2014/10/23 PHP
Discuz不使用插件实现简单的打赏功能
2019/03/21 PHP
Jquery在IE7下无法使用 $.ajax解决方法
2009/11/11 Javascript
用客户端js实现带省略号的分页
2013/04/27 Javascript
JavaScript:Div层拖动效果实例代码
2013/08/06 Javascript
Jquery 复选框取值兼容FF和IE8(测试有效)
2013/10/29 Javascript
jQuery实现视频作为全屏幕背景
2014/12/18 Javascript
js常用系统函数用法实例分析
2015/01/12 Javascript
Jquery api 速查表分享
2015/01/12 Javascript
js实现跟随鼠标移动且带关闭功能的图片广告实例
2015/02/26 Javascript
javascript实现百度地图鼠标滑动事件显示、隐藏
2015/04/02 Javascript
JQuery中DOM事件合成用法实例分析
2015/06/13 Javascript
JavaScript中两个字符串的匹配
2016/06/08 Javascript
ES6记录异步函数的执行时间详解
2016/08/31 Javascript
js前端实现多图图片上传预览的两个方法(推荐)
2016/11/18 Javascript
js中数组插入、删除元素操作的方法
2017/02/15 Javascript
JavaScript中使用Async实现异步控制
2017/08/15 Javascript
element-ui中dialog弹窗关闭按钮失效的解决
2020/09/22 Javascript
[02:57]2014DOTA2国际邀请赛-观众采访
2014/07/19 DOTA
[01:23:45]DOTA2-DPC中国联赛 正赛 CDEC vs Dragon BO3 第一场 1月22日
2021/03/11 DOTA
Pyramid将models.py文件的内容分布到多个文件的方法
2013/11/27 Python
python2与python3共存问题的解决方法
2018/09/18 Python
详解python做UI界面的方法
2019/02/27 Python
python保留小数位的三种实现方法
2020/01/07 Python
如何利用Python 进行边缘检测
2020/10/14 Python
html5唤起app的方法
2017/11/30 HTML / CSS
端午节寄语2015
2015/03/23 职场文书
总经理助理岗位职责范本
2015/03/31 职场文书
电台广播稿范文
2015/08/19 职场文书
什么是执行力?9个故事告诉您:成功绝非偶然!
2019/07/05 职场文书
mysql查询的控制语句图文详解
2021/04/11 MySQL
德生TECSUN S-2000使用手册文字版
2022/05/10 无线电