关闭

python爬图片

256人阅读 评论(0) 收藏 举报
分类:

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

[python] view plaincopy
  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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:72749次
    • 积分:1424
    • 等级:
    • 排名:千里之外
    • 原创:71篇
    • 转载:44篇
    • 译文:0篇
    • 评论:14条
    文章分类
    最新评论