Crossin的编程教室

标题: 抓取美女图片的爬虫小程序 [打印本页]

作者: creek    时间: 2014-6-27 18:51
标题: 抓取美女图片的爬虫小程序
一个python爬虫小程序,爬的是www.22mm.cc里面的美女图片,该如何把它改成多线程呢??
  1. #!/usr/bin/env python
  2. #coding:UTF-8
  3. import urllib
  4. import re
  5. import os
  6. import os.path

  7. index=0
  8. #抓取页面的函数
  9. def getPage(url):
  10.         page=urllib.urlopen(url).read()
  11.         return page

  12. #抓取首页美女分类的链接信息
  13. def getSortLinkInfo(html):
  14.         patt='<a href="/[^\s]+?\.html" title="[^\s]+?"'
  15.         regex=re.compile(patt)
  16.         linkInfo=re.findall(regex,html)
  17.         links={}
  18.         for i in linkInfo:
  19.                 #links.append('http://www.22mm.cc'+i.split('"')[1])
  20.                 links['http://www.22mm.cc'+i.split('"')[1]]=i.split('"')[3]
  21.         return links        #links是有效链接的列表

  22. #获取特定美女页面中的链接信息
  23. def getBeautyLinkInfo(link):
  24.         page=getPage(link)
  25.         patt='<a href=\'[^\s]+?-\d+?\.html\'>\d+?</a>'
  26.         regex=re.compile(patt)
  27.         lastLink=re.findall(regex,page)
  28.         if len(lastLink)>0:
  29.                 lastLink=lastLink[-1].split("'")[1]
  30.         return lastLink                #lastLink是最后一个美女页面的相对路径

  31. #提取最终美女图片的链接
  32. def getImgLinks(lastLink):
  33.         page=getPage(lastLink)
  34.         patt='arrayImg\[0\]="(http://[^\s]+?\.jpg)"'
  35.         regex=re.compile(patt)
  36.         imgLinks=re.findall(regex,page)
  37.         return imgLinks     #imgLinks是有效的图片链接的列表

  38. #下载并且保存图片
  39. def saveImg(imgLinks,dirname):
  40.         global index
  41.         path=unicode('D:\\pics\\'+dirname,'utf8')
  42.         os.mkdir('%s' %(path))
  43.         dirname=dirname.decode('utf8')
  44.         for i in imgLinks:
  45.                 urllib.urlretrieve(i,'D:\\pics\%s\%d.jpg' % (dirname,index))
  46.                 print '%s has been downloaded and saved successfully.'%(i)
  47.                 index+=1

  48. indexURL='http://www.22mm.cc'

  49. def start():
  50.         homePage=getPage(indexURL)
  51.         links=getSortLinkInfo(homePage)
  52.         for i in links:
  53.                 #dirname=unicode('D:\\pics\\'+links[i],'utf8')
  54.                 #os.mkdir('%s' %(dirname))
  55.                 dirname=links[i]
  56.                 relPath=getBeautyLinkInfo(i)       
  57.                 if len(relPath)>0:
  58.                         lastLink='http://www.22mm.cc/mm/'+i.split("/")[4]+'/'+relPath
  59.                         tempLinks=getImgLinks(lastLink)
  60.                         imgLinks=[]
  61.                         for j in tempLinks:
  62.                                 imgLinks.append(re.sub('big','pic',j))
  63.                         saveImg(imgLinks,dirname)
  64.                     
  65.                         
  66. start()
复制代码

作者: crossin先生    时间: 2014-6-28 16:57
这个程序有意思
去看一下 thread 模块相关的用法
作者: creek    时间: 2014-6-30 23:19
修改了一下,之前的只能抓取首页的图片,下面这个应该能爬取全站的
  1. #!usr/bin/env python
  2. #coding:UTF-8
  3. import urllib2
  4. import urllib
  5. import re
  6. import os

  7. # 获取页面的html
  8. def get_page(url):
  9.         req=urllib2.Request(url)
  10.         try:
  11.                 html=urllib2.urlopen(req).read()
  12.                 return html
  13.         except urllib2.URLError,e:
  14.                 if e.code==404:
  15.                         return False

  16. #获取美女图片的四个分类链接
  17. def get_fen_lei_link(html):
  18.         patt='<a href="/mm/[^\s]+?/" >'
  19.         regex=re.compile(patt)
  20.         fen_lei_link=[]
  21.         temp_link=re.findall(regex,html)[0:4]
  22.         for link in temp_link:
  23.                 fen_lei_link.append('http://www.22mm.cc'+link.split('"')[1])
  24.         return fen_lei_link

  25. #获取套图的链接
  26. def get_taotu_link(specific_page):
  27.         global taotu_links
  28.         taotu_links={}
  29.         patt='<a href="/[^\s]+?\.html" title=".+?"'
  30.         regex=re.compile(patt)
  31.         link_info=re.findall(regex,specific_page)
  32.         for i in link_info:
  33.                 taotu_links['http://www.22mm.cc'+i.split('"')[1]]=i.split('"')[3]

  34. #获取套图页面中指向最后一个图片的链接
  35. def get_taotu_last_link(taotu_link):
  36.         taotu_page=get_page(taotu_link)
  37.         patt='<a href=\'[^\s]+?-\d+?\.html\'>\d+?</a>'
  38.         regex=re.compile(patt)
  39.         taotu_last_link=re.findall(regex,taotu_page)[-1].split("'")[1]
  40.         return taotu_last_link

  41. #获取暂时的图片链接
  42. def get_temp_image_link(taotu_last_link):
  43.         taotu_last_page=get_page(taotu_last_link)
  44.         patt=patt='arrayImg\[\d\]="(http://[^\s]+?\.jpg)"'
  45.         regex=re.compile(patt)
  46.         temp_image_link=re.findall(regex,taotu_last_page)
  47.         return temp_image_link

  48. #将图片下载并且保存到D盘的pic文件夹中
  49. def save_image(image_links,dirname):
  50.         global index
  51.         path=unicode('D:\\pic\\'+dirname,'utf8')
  52.         os.mkdir('%s' %(path))
  53.         dirname=dirname.decode('utf8')
  54.         for img_link in image_links:
  55.                 urllib.urlretrieve(img_link,'D:\\pic\%s\%d.jpg' % (dirname,index))
  56.                 print '%s has been downloaded and saved successfully.'%(img_link)
  57.                 index+=1

  58. def start():
  59.         print 'Waiting............'
  60.         url='http://www.22mm.cc'
  61.         html=get_page(url)
  62.         fen_lei_link=get_fen_lei_link(html)
  63.         for link in fen_lei_link:
  64.                 temp_link=link
  65.                 page_index=1        #page_index是页面索引
  66.                 specific_page=get_page(link)
  67.                 get_taotu_link(specific_page)
  68.                 while page_index<4:        #套图的数目很多,暂时只抓取每个分类的前三页图片
  69.                         if page_index==1:
  70.                                 specific_page=get_page(link)
  71.                                 get_taotu_link(specific_page)
  72.                         else:
  73.                                 link=temp_link+'index_%d.html' %(page_index)
  74.                                 specific_page=get_page(link)
  75.                                 if not specific_page:
  76.                                         break
  77.                                 else:
  78.                                         get_taotu_link(specific_page)
  79.                         for key in taotu_links:
  80.                                 dirname=taotu_links[key]
  81.                                 temp_taotu_last_link=get_taotu_last_link(key)
  82.                                 taotu_last_link='http://www.22mm.cc/mm/'+key.split("/")[4]+'/'+temp_taotu_last_link
  83.                                 temp_image_link=get_temp_image_link(taotu_last_link)
  84.                                 image_links=[]
  85.                                 for each in temp_image_link:
  86.                                         image_links.append(re.sub('big','pic',each))
  87.                                 save_image(image_links,dirname)
  88.                         page_index+=1

  89. #links是存储套图链接信息的字典
  90. taotu_links={}
  91. #index是图片名称的索引
  92. index=0
  93. start()
复制代码
对于Python的多线程,我有好些疑问,搜索了也没得到满意的答案
1.一个进程里面同一时刻只能运行一个线程么?
2.倘若1成立,那么sleep()在实际的应用程序中不是反而拉低了效率?
提了两个很菜的问题,希望crossin先生看到了能顺手解答一下,多谢
作者: crossin先生    时间: 2014-7-1 11:50
creek 发表于 2014-6-30 23:19
修改了一下,之前的只能抓取首页的图片,下面这个应该能爬取全站的对于Python的多线程,我有好些疑问,搜索 ...

是的。如果cpu只能同时执行一个进程,那么多线程的计算没有什么好处,甚至还耽误了线程切换的时间。
但是多线程可以避免一个线程被阻塞住,导致其他任务无法进行的情况,这在有网络请求或者文件读写的时候很有用。相当于把等待对方服务器响应和下载的时间节省了下来。
另外,我不是很确定,多核cpu是否可以并行多个python线程。
作者: liu-pengfei    时间: 2014-9-22 19:07
楼主,我复制了你的改进后的代码,运行的时候只是在命令行输出了wait...其他什么都没有,D盘没有图片。于是我又在D盘下手动新建一个文件夹,名字是pic,再次运行,可以了,但是下载了两组图片后,大概有十多张,就报错停止了,说是下表越界。重新运行,又是只是在命令行输出了wait...其他什么都没有。这是怎么回事啊?
作者: 小燕smile    时间: 2015-9-7 13:13
@crossin先生  我自己也写了一个抓取图片的脚本,但是在下载图片到电脑的时候发生urllib.error.ContentTooShortError: <urlopen error retrieval incomplete: got only 36211 out of 508217 bytes>的错误,再次执行,却没有任何问题,怀疑是不是和网络有关?由于网速较慢,导致下载图片到内存中的部分较少或者内存占用率较高导致?有没有什么办法能够避免这种错误发生?

作者: crossin先生    时间: 2015-9-8 19:16
小燕smile 发表于 2015-9-7 13:13
@crossin先生  我自己也写了一个抓取图片的脚本,但是在下载图片到电脑的时候发生urllib.error.ContentTooS ...

似乎只是网络不好,没能一次下载成功。
避免发生就是做异常处理,错误的情况下自动重新下载
作者: airabout    时间: 2016-3-13 21:45
我是新手 请问这些代码是在哪运行的? 是cmd里的python吗······
作者: crossin先生    时间: 2016-3-14 12:30
airabout 发表于 2016-3-13 21:45
我是新手 请问这些代码是在哪运行的? 是cmd里的python吗······

先保存在文件里,然后在cmd下用 python xxx.py 这样的命令来执行。或者放在开发工具里执行
作者: 小燕smile    时间: 2016-4-13 16:25
不清楚之前该网站的源代码怎么写的,但是目前该网站很多地方貌似做了改版,没有实际测试lz的代码,估计已经不能用了吧!
作者: crossin先生    时间: 2016-4-13 21:13
小燕smile 发表于 2016-4-13 16:25
不清楚之前该网站的源代码怎么写的,但是目前该网站很多地方貌似做了改版,没有实际测试lz的代码,估计已经 ...

爬虫程序都是要经常随源站进行调整的
作者: 小燕smile    时间: 2016-4-13 21:37
既然这样,给大家一个最新该网站爬虫:
  1. from bs4 import BeautifulSoup
  2. import urllib.request
  3. from collections import deque,defaultdict
  4. import re
  5. import os


  6. url='http://www.22mm.cc/'

  7. def get_page(url):
  8.     headers = {
  9.     'Connection': 'Keep-Alive',
  10.     'Accept': "image/png,image/*;q=0.8,*/*;q=0.5",
  11.     'Accept-Language': "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
  12.     'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0",
  13.     'Referer':"http://www.22mm.cc/"
  14.     }
  15.     req = urllib.request.Request(url, headers=headers)
  16.     response = urllib.request.urlopen(req)
  17.     responseutf8 = response.read().decode()
  18.     responsegbk = responseutf8.encode('gbk', 'ignore')
  19.     page = responsegbk.decode('gbk')
  20.     return page

  21. def get_first_link(page):
  22.     queue=deque()
  23.     filename=[]
  24.     baseurl='http://22mm.xiuna.com'
  25.     soup=BeautifulSoup(page)
  26.     pic=soup.find(id = 'recshowBox')
  27.     for child in pic.children:
  28.          queue.append(baseurl+child['href'])
  29.          filename.append(child['title'])
  30.     return filename,queue

  31. def get_all_links(filename, queue):
  32.     d=defaultdict(set)
  33.     n=0
  34.     while queue:
  35.         link2=[]
  36.         linkss=link2[:]
  37.         links=link2[:]
  38.         link1=link2[:]
  39.         baselink=queue.popleft()
  40.         pagecode=get_page(baselink)
  41.         soup=BeautifulSoup(pagecode)
  42.         link=soup.find(class_="pagelist")
  43.         for child in link.children:
  44.             try:
  45.                 linkss.append(child['href'])
  46.             except:
  47.                 continue
  48.         links=linkss[1:-1]
  49.         pattern=re.compile('http.*/')
  50.         addurl=re.findall(pattern,baselink)
  51.         link1=[addurl[0]+link for link in links]
  52.         '''for link in links:
  53.             link1.append(addurl[0]+link)
  54.             link1.append(baselink)'''
  55.         for value in link1:
  56.             d[filename[n]].add(value)
  57.         n+=1
  58.     return d

  59. def download_all_pic(d):
  60.     for key in d:
  61.         print("正在创建{}的目录".format(key))
  62.         path='D:\\pics\\'+key+'\\'
  63.         os.mkdir('%s'%path)
  64.         print(path)
  65.         print("开始下载{}的图集...".format(key))
  66.         index=1
  67.         for i in d[key]:
  68.             global index
  69.             page1=get_page(i)
  70.             pattern1=re.compile(r'arrayImg\[0\]="(http.*?jpg)')
  71.             addurl1=re.findall(pattern1,page1)
  72.             down=addurl1[-1].replace('big','pic')
  73.             print("正在下载%s的第%d张图片" % (key,index))
  74.             urllib.request.urlretrieve(down,'D:\\pics\%s\%d.jpg' % (key,index))
  75.             print("下载完成")
  76.             index+=1

  77. def start(url):
  78.     page=get_page(url)
  79.     filename, queue=get_first_link(page)
  80.     d=get_all_links(filename,queue)
  81.     download_all_pic(d)

  82. start(url)
复制代码
采用了bs4完成
作者: 小燕smile    时间: 2016-4-13 21:46
几点说明:
1.该爬虫只是爬取该网站展示区的几组图片,全站的?自己扩展一下,不想要那么多图片,故一开始就没那些写;
2.D:\\pics,代码没有主动判断D盘是否有pics目录,直接下载的,故需要你提前在D盘创建该目录,否则可能无法运行比较懒……;
3.基于py3.4 win7 pycharm4.5测试可用,其他未测试;
4.不论使用哪种编辑器运行,注意设置好encoding(包括代码本身和对网页内容的解码),否则对这种中文网站encode可能会报错;
5.这种爬虫具有时效性,万一网页改版(例如使用JavaScript)就会失效,需要再次修正方可使用;
最终效果:
代码如果执行无误,会在你的D盘pics下创建几个目录,并在目录内下载相应的图片……
作者: crossin先生    时间: 2016-4-13 22:48
小燕smile 发表于 2016-4-13 21:46
几点说明:
1.该爬虫只是爬取该网站展示区的几组图片,全站的?自己扩展一下,不想要那么多图片,故 ...

非常赞啊
作者: dekun    时间: 2016-6-11 10:26
小燕smile 发表于 2016-4-13 16:25
不清楚之前该网站的源代码怎么写的,但是目前该网站很多地方貌似做了改版,没有实际测试lz的代码,估计已经 ...

实测 还是可以用的现在
作者: pythonnm    时间: 2016-9-8 16:22
看了楼主的帖子,我不禁产生这样的疑问,是程序员都是老司机,还是老司机都是程序员
作者: crossin先生    时间: 2016-9-8 19:10
pythonnm 发表于 2016-9-8 16:22
看了楼主的帖子,我不禁产生这样的疑问,是程序员都是老司机,还是老司机都是程序员 ...

不想做司机的厨师,不是好程序员
作者: 我叫别这样    时间: 2017-7-4 14:23
  1. #获取美女图片的四个分类链接
  2. def get_fen_lei_link(html):
  3.         patt='<a href="/mm/[^\s]+?/" >'
  4.         regex=re.compile(patt)
  5.         fen_lei_link=[]
  6.         temp_link=re.findall(regex,html)[0:4]
  7.         for link in temp_link:
  8.                 fen_lei_link.append('http://www.22mm.cc'+link.split('"')[1])
  9.         return fen_lei_link
复制代码
这里我获得的temp_link这个List长度是0 是怎么回事?

QQ截图20170704142043.jpg (74.25 KB, 下载次数: 687)

QQ截图20170704142043.jpg


作者: crossin先生    时间: 2017-7-4 17:22
我叫别这样 发表于 2017-7-4 14:23
这里我获得的temp_link这个List长度是0 是怎么回事?

那就是findall没拿到结果
通过增加输出调试,确认你的 html内容对不对,regex的规则是不是其效果




欢迎光临 Crossin的编程教室 (https://bbs.crossincode.com/) Powered by Discuz! X2.5