Python爬取图片

参考了别人的代码。给代码添加了多线程和Queue的结合应用。

[python] view plain copy
  1. #!/usr/bin/env python  
  2. # -*- coding:utf-8 -*-  
  3.   
  4. ''''' 
  5. Created on 2013-3-21 
  6.  
  7. @author: naughty 
  8. '''  
  9. # author: wklken  
  10.   
  11. from sgmllib import SGMLParser  
  12. import os  
  13. import urllib  
  14. import urllib2  
  15. import urlparse  
  16. from Queue import Queue  
  17. from threading import Thread  
  18.   
  19. save_path = '/home/zoer'  
  20. passUrls = set()  
  21.   
  22. qimg = Queue()  
  23. class URLLister(SGMLParser):  
  24.     def reset(self):  
  25.         SGMLParser.reset(self)  
  26.         self.urls = []  
  27.         self.imgs = []  
  28.     def start_a(self, attrs):  
  29.         href = [ v for k, v in attrs if k == "href" and v.startswith("http")]  
  30.         if href:  
  31.             self.urls.extend(href)  
  32.     def start_img(self, attrs):  
  33.         src = [ v for k, v in attrs if k == "src" and v.startswith("http") ]  
  34.         if src:  
  35.             self.imgs.extend(src)  
  36.   
  37. def get_url_of_page(url, if_img=False):  
  38.     ''''' 
  39.     获取一个页面上的所有链接。 
  40.     if_img:如果为true,则获取的是页面上的所有图片的链接 
  41.     '''  
  42.     urls = []  
  43.     try:  
  44.         f = urllib2.urlopen(url, timeout=3).read()  
  45.         url_listen = URLLister()  
  46.         url_listen.feed(f)  
  47.         if if_img:  
  48.             urls.extend(url_listen.imgs)  
  49.         else:  
  50.             urls.extend(url_listen.urls)  
  51.     except urllib2.URLError, e:  
  52.         print e  
  53.     return urls  
  54.   
  55. def get_page_html(begin_url, depth, main_site_domain):  
  56.     ''''' 
  57.     递归处理页面 
  58.     '''  
  59.     if depth <= 0:  
  60.         return  
  61.     print 'handle ' + begin_url  
  62.     passUrls.add(begin_url)  
  63.     #===========================================================================  
  64.     # 读取本页面上的图片  
  65.     #===========================================================================  
  66.     urls = get_url_of_page(begin_url, True)  
  67.     #===========================================================================  
  68.     # 添加图片到queue  
  69.     #===========================================================================  
  70.     for murl in urls:  
  71.         firstindex = murl.find('?')  
  72.         if firstindex != -1:  
  73.             print firstindex  
  74.             murl = murl[:firstindex]  
  75.         print 'add img url:' + murl  
  76.         qimg.put(murl)  
  77.     #===============================================================================  
  78.     # 读取本页面上的链接  
  79.     #===============================================================================  
  80.     urls = get_url_of_page(begin_url)  
  81.     if urls:  
  82.         for murl in urls:  
  83.             if not murl in passUrls:  
  84.                 get_page_html(murl, depth - 1, main_site_domain)  
  85.   
  86. class DPThread(Thread):  
  87.     ''''' 
  88.     下载线程 
  89.     '''  
  90.     def run3(self):  
  91.         while True:  
  92.             filename = qimg.get()  
  93.             filename = filename.split("/")[-1]  
  94.             #dist = os.path.join(save_path, filename)  
  95.             dist = save_path + '/' + filename  
  96.             print dist  
  97.             print 'try connecting ' + filename  
  98.             if filename.endswith('jpg'or filename.endswith('png'or filename.endswith('gif'or filename.endswith('bmp'or filename.endswith('jpeg'):  
  99.                 print 'downloading ' + filename  
  100.                 dist = dist.replace('\\', '/')  
  101.                 urllib.urlretrieve(filename, dist, None)  
  102.                 print "Done: ", filename  
  103.             qimg.task_done()  
  104.       
  105.     def run(self):  
  106.         while True:  
  107.             murl = qimg.get()  
  108.             print 'one '+murl  
  109.             filename = murl.split("/")[-1]  
  110.             urlopen = urllib.URLopener()  
  111.             try:  
  112.                 fp = urlopen.open(murl)  
  113.                 data = fp.read()  
  114.                 fp.close()  
  115.                 f = open(save_path + "/" + filename, 'w+b')  
  116.                 f.write(data)  
  117.                 f.close()  
  118.             except IOError:  
  119.                 print "download error!" + url  
  120.             qimg.task_done()  
  121.   
  122. if __name__ == "__main__":  
  123.     #===========================================================================  
  124.     # 抓取图片首个页面  
  125.     #===========================================================================  
  126.     url = "http://image.baidu.com"  
  127.     #url='http://bringgooglereaderback.com/'  
  128.     #===========================================================================  
  129.     # 图片保存路径  
  130.     #===========================================================================  
  131.       
  132.     if not os.path.exists(save_path):  
  133.         os.mkdir(save_path)  
  134.     #===========================================================================  
  135.     # 遍历深度  
  136.     #===========================================================================  
  137.     max_depth = 1  
  138.     main_site_domain = urlparse.urlsplit(url).netloc  
  139.     get_page_html(url, max_depth, main_site_domain)  
  140.       
  141.     for i in range(1):  
  142.         t = DPThread()  
  143.         t.setDaemon(True)  
  144.         t.start()  
  145.     qimg.join()  
  146.     print 'end'  

上面代码中有一个run方法和一个run3方法。

run3方法中使用urllib的urlretrieve来读取图片。发现这样速度很慢。所以直接在run方法中用了urllib的URLopener来打开图片地址并读取数据直接写到本地磁盘的文件中。

----------------------------------------------------------------------

遇到严重的问题:

由于一开始线程没有设置成Daemon的,所以即使Queue中没有内容了,脚本还是不会退出。设置成Daemon之后,在Queue中每有内容之后,脚本就会退出了。

---------------------------------------------------------

原因解释如下:

python中得thread的一些机制和C/C++不同:在C/C++中,主线程结束后,其子线程会默认被主线程kill掉。而在python中,主线程结束后,会默认等待子线程结束后,主线程才退出。

python对于thread的管理中有两个函数:join和setDaemon

  • join:如在一个线程B中调用threada.join(),则threada结束后,线程B才会接着threada.join()往后运行。
  • setDaemon:主线程A启动了子线程B,调用b.setDaemaon(True),则主线程结束时,会把子线程B也杀死,与C/C++中得默认效果是一样的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值