分享

Python网络爬虫小试刀

 zhou网摘 2018-02-21

前篇回顾:下载一个类型集合的全部图片
本篇目标:获得一个集合页面中所有集合中所有的图片

使用urllib2获取已知集合网页页面的HTML代码,首先使用正则表达式获取本页图片集合的url,根据上篇所写戏在图片集合的函数 def getImgAssemble(url, fileName, filePath): 将集合中所有图片下载到指定文件夹,并将文件夹命名为图片集合标题名,然后判断是否还有下一页。如果有的话则进入下一页进行同样的动作,直到最后一页则集合页面所有图片下载完毕。
本篇将使用threading多线程和线程锁使下载并发执行,以增加效率和运行速度。

有关python多线程:

请自行AOL或百度去。。。。

集合页面url = 'http://desk.zol.com.cn/meinv/'
首先建个函数def getImgCatalog(url, filePath):,然后往里面塞我们需要的东西就好咯。先写好基础到,获取已知url的HTML。
代码如下:
  1. 73 def getImgCatalog(url, filePath):  
  2. 74     if not os.path.exists(filePath):  
  3. 75         os.makedirs(filePath)  
  4. 76     if not filePath.endswith('/'):  
  5. 77         filePath += '/'  
  6. 78  
  7. 79     user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  
  8. 80     headers = {'User-Agent' : user_agent}  
  9. 81  
  10. 82     request = urllib2.Request(url, headers=headers)  
  11. 83     content = urllib2.urlopen(request).read().decode('GBK')  
  12. 84  
  13. 85     f = open('url.txt', 'w')  
  14. 86     f.write(content.encode('utf-8'))  
  15. 87     f.close()  
  16. 88  
  17. 89     print content  
  18. 90  
部分结果如下:


接下来我们可以使用正则表达式从HTML中提取我们需要的信息啦。
根据上篇我们所写下载集合图集的函数def getImgAssemble(url, fileName, filePath):和我们的需求,我们需要获取这些信息:
图片集合的url:使用来作为函数getImgAssemble的url
图片集合title:作为函数getImgAssemble的fileName。

OK,爬出本页全部图片暂时需要这些信息。
获取图片集合的url,HTML代码如下:

获取其中url和title的正则表达式为:
'<li\s+class="photo-list-padding"><a\s+class="pic"\s+href="(.+?)"\s+target=".+?"\s+hidefocus=".+?"><img\s*width=".+?"\s+height=".+?"\s+alt="(.+?)".+?/>'

增加了正则表达式的代码如下:
  1. 73 def getImgCatalog(url, filePath):  
  2. 74     if not os.path.exists(filePath):  
  3. 75         os.makedirs(filePath)  
  4. 76     if not filePath.endswith('/'):  
  5. 77         filePath += '/'  
  6. 78  
  7. 79     user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  
  8. 80     headers = {'User-Agent' : user_agent}  
  9. 81  
  10. 82     request = urllib2.Request(url, headers=headers)  
  11. 83     content = urllib2.urlopen(request).read().decode('GBK')  
  12. 84  
  13. 85     pattern = re.compile('<li\s+class="photo-list-padding"><a\s+class="pic"\s+href="(.+?)"\s+target=".+?"\s+hid    efocus=".+?"><img\s*width=".+?"\s+height=".+?"\s+alt="(.+?)".+?/>', \  
  14. 86             re.S)  
  15. 87     imgInfoList = re.findall(pattern, content)  
  16. 88  
  17. 89     for item in imgInfoList:  
  18. 90         sUrl = mUrl + item[0]  
  19. 91  
  20. 92         print sUrl  
  21. 93         print item[1]  
  22. 94  
结果如下图:

我们已经得到了我们想要的结果。
然后再将函数getImgAssemble加进去。
我们再加一个显示运行时间的函数在main()里面以计算程序运行上时间:
import datetime
startTime = datetime.datetime.now()
endTime = datetime.datetime.now()
print (endTime-startTime).seconds
print "count : %d" %count

增加代码如下:
  1. 74 def getImgCatalog(url, filePath):  
  2. 75     if not os.path.exists(filePath):  
  3. 76         os.makedirs(filePath)  
  4. 77     if not filePath.endswith('/'):  
  5. 78         filePath += '/'  
  6. 79  
  7. 80     user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  
  8. 81     headers = {'User-Agent' : user_agent}  
  9. 82  
  10. 83     request = urllib2.Request(url, headers=headers)  
  11. 84     content = urllib2.urlopen(request).read().decode('GBK')  
  12. 85  
  13. 86     pattern = re.compile('<li\s+class="photo-list-padding"><a\s+class="pic"\s+href="(.+?)"\s+target=".+?"\s+hid    efocus=".+?"><img\s*width=".+?"\s+height=".+?"\s+alt="(.+?)".+?/>', \  
  14. 87             re.S)  
  15. 88     imgInfoList = re.findall(pattern, content)  
  16. 89  
  17. 90     for item in imgInfoList:  
  18. 91         sUrl = mUrl + item[0]  
  19. 92         getImgAssemble(sUrl, item[1], filePath)  
  20. 93  
main:
  1.  95 def main():  
  2.  96     startTime = datetime.datetime.now()  
  3.  97  
  4.  98     #img save path  
  5.  99     savePath = os.getcwd()  
  6. 100  
  7. 101     url = 'http://b./desk/bizhi/image/7/960x600/1450950428732.jpg'  
  8. 102     #img name4  
  9. 103     imgName = 'pic1.jpg'  
  10. 104     #downloadImg(url, imgName, savePath)  
  11. 105  
  12. 106     sUrl = 'http://desk.zol.com.cn/bizhi/6128_75825_2.html'  
  13. 107     fileName = 'meinv'  
  14. 108     #getImgAssemble(sUrl, fileName, savePath)  
  15. 109  
  16. 110     cUrl = 'http://desk.zol.com.cn/meinv/'  
  17. 111     getImgCatalog(cUrl, savePath)  
  18. 112  
  19. 113     endTime = datetime.datetime.now()  
  20. 114     print '\ntotal running time : %d s' %(endTime-startTime).seconds  
  21. 115  
结果截图:


时间用了68s,没有比较就不知道这个时间是长还是短。

下面来加个多线程和线程锁,代码如下:

  1. import threading  
  1.  75 catalogLock = threading.Lock()  
  2.  76 def getImgCatalog(url, filePath):  
  3.  77     if not os.path.exists(filePath):  
  4.  78         os.makedirs(filePath)  
  5.  79     if not filePath.endswith('/'):  
  6.  80         filePath += '/'  
  7.  81  
  8.  82     user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  
  9.  83     headers = {'User-Agent' : user_agent}  
  10.  84  
  11.  85     request = urllib2.Request(url, headers=headers)  
  12.  86     content = urllib2.urlopen(request).read().decode('GBK')  
  13.  87  
  14.  88     pattern = re.compile('<li\s+class="photo-list-padding"><a\s+class="pic"\s+href="(.+?)"\s+target=".+?"\s+hidefocus=    ".+?"><img\s*width=".+?"\s+height=".+?"\s+alt="(.+?)".+?/>', \  
  15.  89             re.S)  
  16.  90     imgInfoList = re.findall(pattern, content)  
  17.  91  
  18.  92     threads = []  
  19.  93     for item in imgInfoList:  
  20.  94         sUrl = mUrl + item[0]  
  21.  95  
  22.  96         #add thread  
  23.  97         if catalogLock.acquire():  
  24.  98             t = threading.Thread(target=getImgAssemble, args=(sUrl, item[1], filePath))  
  25.  99             t.setDaemon(True)  
  26. 100             threads.append(t)  
  27. 101             catalogLock.release()  
  28. 102  
  29. 103     for i in range(len(threads)):  
  30. 104         threads[i].start()  
  31. 105     for i in range(len(threads)):  
  32. 106         threads[i].join(30)  
  33. 107  
结果如下截图:


用时15s。可以看出,时间明显减少。
其实中间出了个问题困扰了很久。
有时候跑到中间会假死,然后ctrl+c并不能关闭线程,后来发现join里面加一个timeout就可以了,数值可以随意,但是要设的大一点,因为线程里面下载图片不是按顺序逐个下载的,一个图片可能挂起很长时间才会被下载,而且设置的大小并不影响结果时间,我们只是想把能下载下来的图片全部下载下来就好。
希望有谁能提供解决办法解决假死问题。


接下来判读是否有下一页,有的话获取下一页的url。
有下一个的HTML如下:


最后一页的HTML如下截图:


其实我们只需要判断是否有’id="pageNext"‘就可以判断是否有下一页了。
如果有’id="pageNext"‘,则利用正则表达式‘<a\s+id="pageNext"\s+href="(.+?)"\s*class="next"\s+target=".+?">’获取到下页的url。


整体代码如下:
  1. #/usr/bin/env python  
  2.   
  3. import os  
  4. import re  
  5. import urllib  
  6. import urllib2  
  7. import datetime  
  8. import threading  
  9.   
  10. mUrl = 'http://desk.zol.com.cn'  
  11.   
  12. def downloadImg(url, imgName, savePath):  
  13.     if savePath == '':  
  14.         return 'image save path is nil.'  
  15.     if imgName == '':  
  16.         return 'image is nil.'  
  17.     if url == '':  
  18.         return 'url is nil.'  
  19.   
  20.     if not os.path.exists(savePath):  
  21.         os.makedirs(savePath)  
  22.     if not savePath.endswith('/'):  
  23.         savePath += '/'  
  24.   
  25.     savePathName = savePath + imgName  
  26.     urllib.urlretrieve(url, savePathName)  
  27.   
  28.     print url  
  29.   
  30. def getImgAssemble(url, fileName, filePath):  
  31.     if not os.path.exists(filePath):  
  32.         os.makedirs(filePath)  
  33.     if not filePath.endswith('/'):  
  34.         filePath += '/'  
  35.     if not fileName in filePath:  
  36.         filePath += fileName  
  37.   
  38.     print '******', url  
  39.     user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  
  40.     headers = {'User-Agent' : user_agent}  
  41.       
  42.     tmpUrl = url  
  43.     while True:  
  44.         try:     
  45.             request = urllib2.Request(tmpUrl, headers=headers)  
  46.             content = urllib2.urlopen(request).read().decode('GBK')  
  47.             imgUrl = re.search('<img\s+id="bigImg"\s+src="(.+?)"\s*srcs=".+?"\s+width="\d+"\s+height="\d+">', \  
  48.                     content).group(1)  
  49.             imgCount = re.search('<h3><a\s+id="titleName"\s+href=".+?">.+?</a><span>.+?(\d+).+?</span></h3>', \  
  50.                     content).group(1)  
  51.   
  52.             imgSuffix = re.search('http://.+?\..+?/.+?\.(.+?)$', \  
  53.                     imgUrl).group(1)  
  54.             imgName = fileName + imgCount + '.' + imgSuffix  
  55.             downloadImg(imgUrl, imgName, filePath)  
  56.   
  57.             nextUrlFlag = re.search('<a\s+id="pageNext"\s+class="next"\s+href="(.+?)"\s+title=".+?">', \  
  58.                     content).group(1)  
  59.   
  60.             if not "javascript:" in nextUrlFlag:  
  61.                 tmpUrl = mUrl + nextUrlFlag  
  62.                 continue  
  63.             else:  
  64.                 print '\n'  
  65.                 break  
  66.   
  67.         except AttributeError:  
  68.             print 'attributeError'  
  69.         except urllib2.URLError, e:  
  70.             if hasattr(e, 'code'):  
  71.                 print e.code  
  72.             if hasattr(e, 'reason'):  
  73.                 print e.reason  
  74.   
  75. catalogLock = threading.Lock()  
  76. def getImgCatalog(url, filePath):  
  77.     if not os.path.exists(filePath):  
  78.         os.makedirs(filePath)  
  79.     if not filePath.endswith('/'):  
  80.         filePath += '/'  
  81.   
  82.     user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'  
  83.     headers = {'User-Agent' : user_agent}  
  84.     tmpUrl = url  
  85.     while True:  
  86.         request = urllib2.Request(tmpUrl, headers=headers)  
  87.         content = urllib2.urlopen(request).read().decode('GBK')  
  88.   
  89.         pattern = re.compile('<li\s+class="photo-list-padding"><a\s+class="pic"\s+href="(.+?)"\s+target=".+?"\s+hidefocus=".+?"><img\s*width=".+?"\s+height=".+?"\s+alt="(.+?)".+?/>', \  
  90.                 re.S)  
  91.         imgInfoList = re.findall(pattern, content)  
  92.       
  93.         threads = []  
  94.         for item in imgInfoList:  
  95.             sUrl = mUrl + item[0]  
  96.   
  97.             #add thread  
  98.             if catalogLock.acquire():  
  99.                 t = threading.Thread(target=getImgAssemble, args=(sUrl, item[1], filePath))  
  100.                 t.setDaemon(True)  
  101.                 threads.append(t)  
  102.                 catalogLock.release()  
  103.   
  104.         for i in range(len(threads)):  
  105.             threads[i].start()  
  106.         for i in range(len(threads)):  
  107.             threads[i].join(30)  
  108.   
  109.         if not 'id="pageNext"' in content:  
  110.             break  
  111.         else:  
  112.             tmpUrl = mUrl + re.search('<a\s+id="pageNext"\s+href="(.+?)"\s*class="next"\s+target=".+?">', \  
  113.                     content).group(1)  
  114.   
  115. def main():  
  116.     startTime = datetime.datetime.now()  
  117.   
  118.     #img save path  
  119.     savePath = os.getcwd()  
  120.       
  121.     url = 'http://b./desk/bizhi/image/7/960x600/1450950428732.jpg'  
  122.     #img name4  
  123.     imgName = 'pic1.jpg'  
  124.     #downloadImg(url, imgName, savePath)  
  125.   
  126.     sUrl = 'http://desk.zol.com.cn/bizhi/6128_75825_2.html'  
  127.     fileName = 'meinv'  
  128.     #getImgAssemble(sUrl, fileName, savePath)  
  129.       
  130.     cUrl = 'http://desk.zol.com.cn/meinv/'  
  131.     cFilePath = savePath+'/meinv'  
  132.     getImgCatalog(cUrl, cFilePath)  
  133.   
  134.     endTime = datetime.datetime.now()  
  135.     print '\ntotal running time : %d s' %(endTime-startTime).seconds  
  136.   
  137.   
  138. if __name__ == '__main__':  
  139.     main()  
运行结果如下




文件总共1.64GB,用时494s,大概3.4Mb/s,网速的话平时迅雷下载会员高速离线下载差不多5Mb/s。
速度来说,还可以吧。

the end
谢谢

下篇预告:获取整个网站所有类型的壁纸

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多