Python爬虫学习(6): 爬取MM图片
为了有趣我们今天就主要去爬取以下MM的图片,并将其按名保存在本地。要爬取的网站为: 大秀台模特网
1. 分析网站
进入官网后我们发现有很多分类:
而我们要爬取的模特中的女模内容,点进入之后其网址为:http://www.daxiutai.com/mote/5.html ,这也将是我们爬取的入口点,为了方便,我们只是爬取其推荐的部分的模特的信息和图片。
当我们点击其中的一个人物的时候就会进入他们的个人主页中,里边包括个人的详细信息以及各种图片。模特的详细都将从这里爬取。
上述的个人主页中的模特图片不全,所以模特的图片将从其照片展示网页中爬取,而其照片的展示网页可以通过点击任意主页上的图片进入,如下图所示:
我们要实现的效果就是每个模特一个文件夹,特定模特文件夹下包括一个模特信息说明的txt文档以及其所有爬取到图片
2. 爬取过程
2.1 爬取各个模特的主页地址
在点击女性模特页面中的模特头像的时候就会进入此模特的主页之中,而各个模特的主页中包含模特的主要信息,所以要先在http://www.daxiutai.com/mote/5.html中获得每个模特的主页地址。
其最里边的<li>标签中就包含模特的主页地址信息,通过蓝色选中部分中地址就可以获取模特主页地址,但却不是图片的地址,应为其是被重定向过。
In [93]: url_femal = "http://www.daxiutai.com/mote/5.html"
In [94]: request = urllib2.Request(url_femal)
In [95]: response = urllib2.urlopen(request)
In [96]: content = response.read()
#绿色部分就是获取到的地址
In [105]: pattern = re.compile(r"(?:<li\s+class=\"li_01\">).*?<a\s+href=\"(.*?)\".*?>",re.S)
In [106]: result = re.findall(pattern,content)
In [107]: result[0]
Out[107]: 'http://www.daxiutai.com/mote_profile/13517.html'
# 总共抓取了60条数据
In [108]: len(result)
Out[108]: 60
艾,写网页的那个家伙太懒了没有把女模特和其它的模特区分开来,所以只能把其他的都抓取下来,而且有重复地址,所以还要去重。
# 去除重复
In [110]: result = list(set(result))
In [111]: len(result)
Out[111]: 57
因为上述这些抓取到的地址在访问的时候会重定向,所以我们需要一一获取其重定后的地址,这一阶段比较费时间,得等一会儿。
#重定位后的地址放在main_url中
In [124]: main_url = []
# 循环获取重定位后的地址
In [125]: for item in result:
...: res = urllib2.urlopen(item)
...: main_url.append(res.geturl())
...: print res.geturl()
http://www.daxiutai.com/mote_profile/13523.html
http://heijin.daxiutai.com/
http://fuxinyu.daxiutai.com/
http://152nicai.daxiutai.com/
http://lfh0706.daxiutai.com/
http://649629484.daxiutai.com/
........................
上述打印的地址中红色类型的地址不是重定位后的地址,且是不可访问的,如果在浏览器中输入此地址会出现如下反应:
所以这样的地址是需要剔除的,剔除时所依据的特性就是//后边是否接着www。
In [135]: main = [] In [136]: for item in main_url:
...: mat = re.match(".*?www.*?",item)
...: if not mat:
...: main.append(item)
# 剔除之后还有55条数据
In [137]: len(main)
Out[137]: 55
2.2 爬取模特的个人信息
模特的个人信息显示如图所示:
HTML源码情况为:
粗略提取一个模特的信息:
In [184]: response = urllib2.urlopen(main[10],timeout=5)
...: content = response.read() In [185]: pattern = re.compile(r"<strong>(.*?)</strong>(.+?)<br\s*/>")
In [186]: result = re.findall(pattern,content)
In [187]: for item in result:
...: print item[0],item[1] 昵称: 我才是宝宝
空间地址: <br /><a href="http://babysix.daxiutai.com/">http://babysix.daxiutai.com/</a>
性别 :女
出生年月 :2016-03
籍贯 :天津市 天津市
身高 :166cm
体重 :45kg
三围 :82 63 88
鞋码 :38
肤色 :黄色
头发颜色 :黑
婚姻状况 :未婚
是否有纹身 :无
纹身何处 :
是否可以拍内衣广告 :不可以
我们发现在匹配过程中中文的:符号也被匹配出来了,而这个在匹配过程中应该去掉。同时空间地址一项的结果明显混乱,但是为了不增加正则表达式的难度,我们在后续处理中直接用我们重定向后的地址取代这个地址即可。
因为包含中文符号的情况可能是这样的:
也会是这样的:
所以明显感觉到了网页的作者的慢慢的恶意。。。。。,所以我们用 (?::)? 来解决这个问题。分组中?:表示匹配但不计入结果,接下来的:是要匹配到的中文冒号,一定要是中文的,分组外边的?表示这个分组可以匹配到也可以匹配不到都行。
In [205]: response = urllib2.urlopen(main[10],timeout=5)
In [206]: content = response.read() In [207]: pattern = re.compile(r"<strong>(.*?)(?::)?</strong>(?::)?(.+?)<br\s*/>") In [208]: result = re.findall(pattern,content) In [209]: for item in result:
...: print item[0],item[1]
...:
昵称 我才是宝宝
空间地址 <br /><a href="http://babysix.daxiutai.com/">http://babysix.daxiutai.com/</a>
性别 女
出生年月 2016-03
籍贯 天津市 天津市
身高 166cm
体重 45kg
三围 82 63 88
鞋码 38
肤色 黄色
头发颜色 黑
婚姻状况 未婚
是否有纹身 无
纹身何处 : # 这里还是有些问题,为了简单我们就不再更改内容了
是否可以拍内衣广告 不可以
上边仅仅是获取一个模特的详细信息,接下来我们将获取所有的模特的信息:
In [90]: result = []
In [90]: for item in main:
response = urllib2.urlopen(item,timeout=8)
content = response.read()
temp = re.findall(pattern,content)
result.append(temp)
上述获取的结果都存储在result中,但是显示效果却很low,为了好看,我们用DataFrame存储。
注意:下边的代码如果直接copy到ipython中执行会有错误,最好是自己按照代码层级自己敲入:
for item in main:
response = urllib2.urlopen(item,timeout=8)
content = response.read()
temp = re.findall(pattern,content)
line_list = []
for x in temp:
line_list.append(list(x))
# 这里
line_list[1][1] = item
line_dict = dict(line_list)
result.append(line_dict)
frame = DataFrame(result)
效果如下图所表示(只是截取了前10个信息):
为了方便,我们将这个过程写为一个python可执行文件,内容如下:
#!/usr/bin/python
#! -*- coding:utf-8 -*- import urllib
import urllib2
import re
import numpy as np
import pandas as pd
from pandas import DataFrame,Series class ScrapModel:
def __init__(self):
self.entry_url = "http://www.daxiutai.com/mote/5.html"
def get_personal_address(self):
try:
print "进入主页中..."
request = urllib2.Request(self.entry_url)
response = urllib2.urlopen(request,timeout=5)
content = response.read()
pattern = re.compile(r"(?:<li\s+class=\"li_01\">).*?<a\s+href=\"(.*?)\".*?>",re.S)
original_add = re.findall(pattern,content)
# 去重复
original_add = list(set(original_add))
redirect_add = []
print "获取重定向地址中..."
for item in original_add:
res = urllib2.urlopen(item,timeout=5)
url = res.geturl()
# 去除不可访问地址
mat = re.match(r".*?www.*?",url)
if not mat:
redirect_add.append(url)
print url
return redirect_add
except Exception,e:
if hasattr(e,"reason"):
print u"连接失败,原因:",e.reason
if hasattr(e,"code"):
print "code:",e.code
return None
def get_personal_info(self,redirect_add):
if (len(redirect_add) == 0):
print "传入参数长度为0"
return None
try:
pattern = re.compile(r"<strong>(.*?)(?::)?</strong>(?::)?(.+?)<br\s*/>")
print "获取模特信息中..."
result = []
for item in redirect_add:
response = urllib2.urlopen(item,timeout=8)
content = response.read()
temp = re.findall(pattern,content)
line_list = []
for x in temp:
# list(x) 是将匹配到的二元组变换为二元的list
line_list.append(list(x))
print "获取到 %s 的信息"%line_list[0][1]
# 这里重新设置模特的空间地址
line_list[1][1] = item
# 这个做法会将二元list的第一个元素变成字典的类型的key,对应的第二个会变成value
line_dict = dict(line_list)
result.append(line_dict)
# 将结果转换为DataFrame类型
frame = DataFrame(result)
print frame
return frame
except Exception,e:
print Exception,e
if hasattr(e,"reason"):
print u"连接失败,原因:",e.reason
if hasattr(e,"code"):
print "code:",e.code
return None spider = ScrapModel()
redirect_add = spider.get_personal_address()
spider.get_personal_info(redirect_add)
2.3 爬取模特的图片
在模特的个人主页中点击相册就会进入相册界面,其地址格式为: 个人主页/album.html
而点击其中的任意一个相册就会进入其图片展示页面,而我们的图片也将从这里抓取
所以接下来我们要获取每一个相册的地址,我们从每个模特的相册集页面中进入,也就是地址格式为: 个人主页地址/album.html 的形式:
In [226]: url = "http://yiyingxing.daxiutai.com/album.html" In [227]: response =urllib2.urlopen(urllib2.Request(url)) In [228]: content = response.read() In [229]: pattern = re.compile(r"<p><a.*?href=\"(.*?)\".*?img.*?/a></p>") In [230]: albums = re.findall(pattern,content) In [231]: albums
Out[231]:
['http://yiyingxing.daxiutai.com/photo/14422.html',
'http://yiyingxing.daxiutai.com/photo/14421.html']
接下来我们获取所有模特的相册地址
# model_info就是前边一节中get_personal_info返回的结果
def get_albums_address(modle_info):
albums_addr = {}
try:
redirect_add = modle_info.index.tolist()
pattern = re.compile(r"<p><a.*?href=\"(.*?)\".*?img.*?/a></p>")
for item in redirect_add:
response = urllib2.urlopen(item + "album.html",timeout=10)
content = response.read()
albums = re.findall(pattern,content)
print "the albums is:",albums
albums_addr[item] = albums
return albums_addr
except Exception,e:
print Exception,e
if hasattr(e,"reason"):
print u"连接失败,原因:",e.reason
if hasattr(e,"code"):
print "code:",e.code
return None
获取到的地址放在字典类型中,其中的每一项的key值是模特的个人主页,value就是相册地址构成的列表。
获取到了相册地址之后就该进入每一个相册中获取其图片,但是有的时候其相册页面中的图片就是原图,像这样的:
但有的时候却又是缩略图,是这样的:
实际上去掉图片名中 _thumb 就会是原图地址,所以这两种都按照一种形式抓取,然后去掉缩略图中的 _thumb:
def get_album_photos(address):
print "获取一个新模特的图片中..."
photos = []
try:
pattern = re.compile(r"<p><a.*?rel=\"(.*?)\".*?/a></p>")
for item in address:
response = urllib2.urlopen(item,timeout=10)
content = response.read()
temp = re.findall(pattern,content)
if temp:
print "获得了MM的%d张照片",len(temp)
photos = photos + temp
if not photos:
print "这家伙太懒了,什么图片都没有留下.."
return None
return photos
except Exception,e:
print Exception,e
if hasattr(e,"reason"):
print u"连接失败,原因:",e.reason
if hasattr(e,"code"):
print "code:",e.code
return None
用获取到的模特相册地址测试调用:
In [35]: get_album_photos(albums_addr["http://timey.daxiutai.com/"])
获取一个新模特的图片中...
获得了MM的%d张照片 8
获得了MM的%d张照片 11
获得了MM的%d张照片 13
Out[35]:
['http://www.daxiutai.com/uploadfiles/user/i191156228/20160513/cf7a25fcbde925cc1aec6654da47ebe4.jpg',
'http://www.daxiutai.com/uploadfiles/user/i191156228/20160513/35bbdb12829a7ca080beb3804e541da7.jpg',
获取所有的图片,并将放入字典类型中
def get_all_photos(albums_addr):
photos = {}
for key in albums_addr:
temp = get_album_photos(albums_addr[key])
if temp:
photos[key] = temp
return photos
2.4 信息保存
模特的图片和个人信息已经有了,接下来我们就将其保存在本地。
def save_one_info(self,info,photos):
dir_name = info[" 昵称"]
exists = os.path.exists(dir_name)
if not exists:
print "创建模特文件夹:"+dir_name
os.makedirs(dir_name)
print "保存模特信息中: "+dir_name
one.to_csv(dir_name+"/"+dir_name+".txt",sep=":")
for photo in photos:
photo = re.sub("_thumb","",photo)
file_name = dir_name+"/"+re.split("/",photo)[-1]
print "正在保存图片: "+file_name
res = urllib.urlopen(photo)
data = res.read()
f = open(file_name,"wb")
f.write(data)
f.close()
测试一个人的保存:
save_one_info(modle_info.ix["http://zaokai456789.daxiutai.com/"],all["http://zaokai456789.daxiutai.com/"])
保存后的结果:
好了,接下来我们将保存所有人的图片以及信息:
def save_all_info(modle_info,modles_photos):
for item in modles_photos:
save_one_info(modle_info.ix[item],modles_photos[item])
3. 完整的爬取过程
python 入手不久,欢迎大神莫喷
#!/usr/bin/python
#! -*- coding:utf-8 -*- import os
import urllib
import urllib2
import re
import numpy as np
import pandas as pd
from pandas import DataFrame,Series class ScrapModel:
def __init__(self):
self.entry_url = "http://www.daxiutai.com/mote/5.html"
self.modle_info = DataFrame()
self.albums_addr = {}
def get_personal_address(self):
try:
print "进入主页中..."
request = urllib2.Request(self.entry_url)
response = urllib2.urlopen(request,timeout=5)
content = response.read()
pattern = re.compile(r"(?:<li\s+class=\"li_01\">).*?<a\s+href=\"(.*?)\".*?>",re.S)
original_add = re.findall(pattern,content)
# 去重复
original_add = list(set(original_add))
redirect_add = []
print "获取重定向地址中..."
for item in original_add:
res = urllib2.urlopen(item,timeout=5)
url = res.geturl()
# 去除不可访问地址
mat = re.match(r".*?www.*?",url)
if not mat:
redirect_add.append(url)
print url
return redirect_add
except Exception,e:
if hasattr(e,"reason"):
print u"连接失败,原因:",e.reason
if hasattr(e,"code"):
print "code:",e.code
return None def get_personal_info(self,redirect_add):
if (len(redirect_add) == 0):
print "传入参数长度为0"
return None
try:
pattern = re.compile(r"<strong>(.*?)(?::)?</strong>(?::)?(.+?)<br\s*/>")
print "获取模特信息中..."
result = []
for item in redirect_add:
response = urllib2.urlopen(item,timeout=10)
content = response.read()
temp = re.findall(pattern,content)
line_list = []
for x in temp:
# list(x) 是将匹配到的二元组变换为二元的list
line_list.append(list(x))
print "获取到 %s 的信息"%line_list[0][1]
# 这里重新设置模特的空间地址
line_list[1][1] = item
# 这个做法会将二元list的第一个元素变成字典的类型的key,对应的第二个会变成value
line_dict = dict(line_list)
result.append(line_dict)
# 将结果转换为DataFrame类型
self.modle_info = DataFrame(result)
self.modle_info = self.modle_info.set_index("空间地址")
print self.modle_info
return self.modle_info
except Exception,e:
print Exception,e
if hasattr(e,"reason"):
print u"连接失败,原因:",e.reason
if hasattr(e,"code"):
print "code:",e.code
return None
#获取每个模特的每个相册的地址,每个模特都会有一个默认相册地址,但是里边可能没有图片
def get_albums_address(self):
try:
redirect_add = self.modle_info.index.tolist()
pattern = re.compile(r"<p><a.*?href=\"(.*?)\".*?img.*?/a></p>")
for item in redirect_add:
response = urllib2.urlopen(item + "album.html",timeout=10)
content = response.read()
albums = re.findall(pattern,content)
print "the albums is:",albums
self.albums_addr[item] = albums
return self.albums_addr
except Exception,e:
print Exception,e
if hasattr(e,"reason"):
print u"连接失败,原因:",e.reason
if hasattr(e,"code"):
print "code:",e.code
return None # 获取一个模特的所有图片地址
def get_album_photos(self,address):
print "获取一个新模特的图片中..."
photos = []
try:
pattern = re.compile(r"<p><a.*?rel=\"(.*?)\".*?/a></p>")
for item in address:
response = urllib2.urlopen(item,timeout=10)
content = response.read()
temp = re.findall(pattern,content)
if temp:
print "获得了MM的%d张照片",len(temp)
photos = photos + temp
if not photos:
print "这家伙太懒了,什么图片都没有留下.."
return None
return photos
except Exception,e:
print Exception,e
if hasattr(e,"reason"):
print u"连接失败,原因:",e.reason
if hasattr(e,"code"):
print "code:",e.code
return None # 获取所有模特的图片地址
def get_all_photos(self,albums_addr):
photos = {}
for key in albums_addr:
temp = self.get_album_photos(albums_addr[key])
if temp:
photos[key] = temp
return photos # 保存一个模特的信息
def save_one_info(self,info,photos):
dir_name = info[" 昵称"]
exists = os.path.exists(dir_name)
if not exists:
print "创建模特文件夹:"+dir_name
os.makedirs(dir_name)
print "保存模特信息中: "+dir_name
info.to_csv(dir_name+"/"+dir_name+".txt",sep=":")
for photo in photos:
photo = re.sub("_thumb","",photo)
file_name = dir_name+"/"+re.split("/",photo)[-1]
print "正在保存图片: "+file_name
res = urllib.urlopen(photo)
data = res.read()
f = open(file_name,"wb")
f.write(data)
f.close()
# 保存所有模特的信息
def save_all_info(self,modle_info,modles_photos):
for item in modles_photos:
self.save_one_info(modle_info.ix[item],modles_photos[item]) spider = ScrapModel()
redirect_add = spider.get_personal_address()
frame = spider.get_personal_info(redirect_add)
albums = spider.get_albums_address()
all_photos = spider.get_all_photos(albums)
spider.save_all_info(frame,all_photos)
Python爬虫学习(6): 爬取MM图片的更多相关文章
- python学习(十七) 爬取MM图片
这一篇巩固前几篇文章的学到的技术,利用urllib库爬取美女图片,其中采用了多线程,文件读写,目录匹配,正则表达式解析,字符串拼接等知识,这些都是前文提到的,综合运用一下,写个爬虫示例爬取美女图片.先 ...
- python爬虫学习(7) —— 爬取你的AC代码
上一篇文章中,我们介绍了python爬虫利器--requests,并且拿HDU做了小测试. 这篇文章,我们来爬取一下自己AC的代码. 1 确定ac代码对应的页面 如下图所示,我们一般情况可以通过该顺序 ...
- Python爬虫学习(二) ——————爬取前程无忧招聘信息并写入excel
作为一名Pythoner,相信大家对Python的就业前景或多或少会有一些关注.索性我们就写一个爬虫去获取一些我们需要的信息,今天我们要爬取的是前程无忧!说干就干!进入到前程无忧的官网,输入关键字&q ...
- python爬虫学习之爬取全国各省市县级城市邮政编码
实例需求:运用python语言在http://www.ip138.com/post/网站爬取全国各个省市县级城市的邮政编码,并且保存在excel文件中 实例环境:python3.7 requests库 ...
- python 爬虫之requests爬取页面图片的url,并将图片下载到本地
大家好我叫hardy 需求:爬取某个页面,并把该页面的图片下载到本地 思考: img标签一个有多少种类型的src值?四种:1.以http开头的网络链接.2.以“//”开头网络地址.3.以“/”开头绝对 ...
- 【转载】教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神
原文:教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神 本博文将带领你从入门到精通爬虫框架Scrapy,最终具备爬取任何网页的数据的能力.本文以校花网为例进行爬取,校花网:http:/ ...
- Python 爬虫入门之爬取妹子图
Python 爬虫入门之爬取妹子图 来源:李英杰 链接: https://segmentfault.com/a/1190000015798452 听说你写代码没动力?本文就给你动力,爬取妹子图.如果 ...
- Python爬虫实战之爬取百度贴吧帖子
大家好,上次我们实验了爬取了糗事百科的段子,那么这次我们来尝试一下爬取百度贴吧的帖子.与上一篇不同的是,这次我们需要用到文件的相关操作. 本篇目标 对百度贴吧的任意帖子进行抓取 指定是否只抓取楼主发帖 ...
- Python爬虫实例:爬取B站《工作细胞》短评——异步加载信息的爬取
很多网页的信息都是通过异步加载的,本文就举例讨论下此类网页的抓取. <工作细胞>最近比较火,bilibili 上目前的短评已经有17000多条. 先看分析下页面 右边 li 标签中的就是短 ...
- Python爬虫实例:爬取猫眼电影——破解字体反爬
字体反爬 字体反爬也就是自定义字体反爬,通过调用自定义的字体文件来渲染网页中的文字,而网页中的文字不再是文字,而是相应的字体编码,通过复制或者简单的采集是无法采集到编码后的文字内容的. 现在貌似不少网 ...
随机推荐
- <<< List<HashMap<String, Object>> 及 HashMap<String, Object> 的用法
//(赋值)最简单的一种hashMap赋值方式 List<HashMap<String, Object>> aMap= new ArrayList<HashMap< ...
- 如何使用iconfont字体代替小图片?
我们以阿里巴巴矢量图标库举例,地址:http://www.iconfont.cn/ 在这里,你可以上传你的矢量图标,也可以直接使用现成的小图标. 为什么要用这些个图标字体,本文就不介绍了,请自行百度. ...
- struts2+hibernate 项目实战:图书管理系统
经典项目,练手必备. 图书管理系统 需求分析(大致,并不专业):1.需要有用户管理: 1.1 用户注册: 1.2 用户登录: 1.3 用户信息修改: 1.4 用户修改密码: 2.需要有书本管理: 2. ...
- 将C#文档注释生成.chm帮助文档
由于最近需要把以前的一个项目写一个文档,但一时又不知道写成怎样的,又恰好发现了可以生成chm的工具,于是乎我就研究了下,感觉还不错,所以也给大家分享下.好了,不多废话,下面就来实现一下吧. 生成前的准 ...
- 大熊君学习html5系列之------requestAnimationFrame(实现动画的另一种方案)
一,开篇分析 Hi,大家好!大熊君又和大家见面了,(*^__^*) 嘻嘻……,这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例, 让大家一步一步的体会" ...
- ios几个重要方法
加载类到内存,程序刚启动的时候调用,调用在main函数之前 1.+(void)load{ } 初始化类,类第一次使用的时候调用一次 2.+(void)initialize{ } 控制器的视图架构,设 ...
- Linux进程间通信(八):流套接字 socket()、bind()、listen()、accept()、connect()、read()、write()、close()
前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程.通常我们使用socket进行网络编 ...
- jquery版小型婚礼(可动态添加祝福语)
前两天在网上不小心看到“js许愿墙”这几个字,我的神经就全部被调动了.然后就开始我的百度生涯,一直寻觅许愿墙背景图片和便利贴图片,觅了好久……一直没找到满意的……无意间看到祝福语和一些卡通婚礼图片.最 ...
- Android Killer工具用法
一.工程信息 工程信息主要是解析的AndroidManifest文件 二.工程管理器 三.配置插入代码 在代码中点右键就可以一键插入代码了 四.字符串搜索功能 支持正则, 比jeb搜索功能强大 来自为 ...
- Python None comparison: should I use “is” or ==?
Use is when you want to check against an object's identity (e.g. checking to see if var is None). Us ...