python使用tornado实现简单爬虫
本文实例为大家分享了python使用tornado实现简单爬虫的具体代码,供大家参考,具体内容如下
代码在官方文档的示例代码中有,但是作为一个tornado新手来说阅读起来还是有点困难的,于是我在代码中添加了注释,方便理解,代码如下:
#coding=utf-8
#!/usr/bin/envpython
importtime
fromdatetimeimporttimedelta
try:
fromHTMLParserimportHTMLParser
fromurlparseimporturljoin,urldefrag
exceptImportError:
fromhtml.parserimportHTMLParser
fromurllib.parseimporturljoin,urldefrag
fromtornadoimporthttpclient,gen,ioloop,queues
#设置要爬取的网址
base_url='http://www.baidu.com'
#设置worker数量
concurrency=10
#此代码会获取base_url下的所有其他url
@gen.coroutine
defget_links_from_url(url):
try:
#通过异步向url发起请求
response=yieldhttpclient.AsyncHTTPClient().fetch(url)
print('fetched%s'%url)
#响应如果是字节类型进行解码
html=response.bodyifisinstance(response.body,str)\
elseresponse.body.decode(errors='ignore')
#构建url列表
urls=[urljoin(url,remove_fragment(new_url))
fornew_urlinget_links(html)]
exceptExceptionase:
print('Exception:%s%s'%(e,url))
#报错返回空列表
raisegen.Return([])
#返回url列表
raisegen.Return(urls)
defremove_fragment(url):
#去除锚点
pure_url,frag=urldefrag(url)
returnpure_url
defget_links(html):
#从html页面里提取url
classURLSeeker(HTMLParser):
def__init__(self):
HTMLParser.__init__(self)
self.urls=[]
defhandle_starttag(self,tag,attrs):
href=dict(attrs).get('href')
ifhrefandtag=='a':
self.urls.append(href)
url_seeker=URLSeeker()
url_seeker.feed(html)
returnurl_seeker.urls
@gen.coroutine
defmain():
#创建队列
q=queues.Queue()
#记录开始时间戳
start=time.time()
#构建两个集合
fetching,fetched=set(),set()
@gen.coroutine
deffetch_url():
#从队列中取出数据
current_url=yieldq.get()
try:
#如果取出的数据在队列中已经存在返回
ifcurrent_urlinfetching:
return
print('fetching%s'%current_url)
#如果不存在添加到集合当中
fetching.add(current_url)
#从新放入的链接中继续获取链接
urls=yieldget_links_from_url(current_url)
#将已经请求玩的url放入第二个集合
fetched.add(current_url)
fornew_urlinurls:
#OnlyfollowlinksbeneaththebaseURL
#如果链接是以传入的url开始则放入队列
ifnew_url.startswith(base_url):
yieldq.put(new_url)
finally:
#队列内数据减一
q.task_done()
@gen.coroutine
defworker():
whileTrue:
#保证程序持续运行
yieldfetch_url()
#将第一个url放入队列
q.put(base_url)
#Startworkers,thenwaitfortheworkqueuetobeempty.
for_inrange(concurrency):
#启动对应数量的worker
worker()
#等待队列数据处理完成
yieldq.join(timeout=timedelta(seconds=300))
#如果两个集合不相等抛出异常
assertfetching==fetched
#打印执行时间
print('Donein%dseconds,fetched%sURLs.'%(
time.time()-start,len(fetched)))
if__name__=='__main__':
io_loop=ioloop.IOLoop.current()
io_loop.run_sync(main)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。