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连接mysql数据库的正确姿势
Feb 03 Python
浅谈机器学习需要的了解的十大算法
Dec 15 Python
Python+matplotlib实现填充螺旋实例
Jan 15 Python
django 通过ajax完成邮箱用户注册、激活账号的方法
Apr 17 Python
pytorch训练imagenet分类的方法
Jul 27 Python
Python中创建二维数组
Oct 17 Python
Python获取一个用户名的组ID过程解析
Sep 03 Python
解决pyqt5异常退出无提示信息的问题
Apr 08 Python
Python如何读写字节数据
Aug 05 Python
matplotlib对象拾取事件处理的实现
Jan 14 Python
python爬取豆瓣电影TOP250数据
May 23 Python
Python if else条件语句形式详解
Mar 24 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 ucwords() 函数将字符串中每个单词的首字符转换为大写(实现代码)
2016/05/12 PHP
PHP preg_match实现正则表达式匹配功能【输出是否匹配及匹配值】
2017/07/19 PHP
php使用event扩展的io复用测试的示例
2020/10/20 PHP
Asp.net下使用Jquery Ajax传送和接收DataTable的代码
2010/09/12 Javascript
js验证是否为数字的总结
2013/04/14 Javascript
在Ubuntu上安装最新版本的Node.js
2014/07/14 Javascript
由浅入深讲解Javascript继承机制与simple-inheritance源码分析
2015/12/13 Javascript
Node.js Addons翻译(C/C++扩展)
2016/06/12 Javascript
js实现精确到毫秒的倒计时效果
2016/08/05 Javascript
Javascript中浏览器窗口的基本操作总结
2016/08/18 Javascript
jQuery异步提交表单的两种方式
2016/09/13 Javascript
js获取指定字符前/后的字符串简单实例
2016/10/27 Javascript
Vue2实现组件props双向绑定
2016/12/02 Javascript
jquery 实现复选框的全选操作实例代码
2017/01/24 Javascript
快速实现jQuery多级菜单效果
2017/02/01 Javascript
JS实现按钮控制计时开始和停止功能
2017/07/27 Javascript
react native 获取地理位置的方法示例
2018/08/28 Javascript
使用webpack搭建vue项目实现脚手架功能
2019/03/15 Javascript
javascript实现前端成语点击验证优化
2020/06/24 Javascript
[01:25]DOTA2超级联赛专访iG 将调整状态找回自己
2013/06/05 DOTA
[47:45]Liquid vs OG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
[05:59]2018DOTA2国际邀请赛寻真——只为胜利的Secret
2018/08/13 DOTA
pandas or sql计算前后两行数据间的增值方法
2018/04/20 Python
Python OpenCV中的resize()函数的使用
2019/06/20 Python
django的csrf实现过程详解
2019/07/26 Python
Python 用matplotlib画以时间日期为x轴的图像
2019/08/06 Python
给大家整理了19个pythonic的编程习惯(小结)
2019/09/25 Python
通过python连接Linux命令行代码实例
2020/02/18 Python
python爬虫中url管理器去重操作实例
2020/11/30 Python
100%法国制造的游戏和玩具:Les Jouets Français
2021/03/02 全球购物
临床医学专业学生的自我评价分享
2013/11/21 职场文书
汉语言文学职业规划
2014/02/14 职场文书
办公设备采购方案
2014/03/16 职场文书
小时代观后感
2015/06/10 职场文书
总经理年会致辞
2015/07/29 职场文书
2016大学生社会实践单位评语
2015/12/01 职场文书