本示例使用Python3.5,需要额外安装BeautifulSoup 4
BeautifulSoup 4 安装方法:
Linux:
sudo apt-get install python-bs4
Mac:
sudo easy_install pip
pip install beautifulsoup4
Windows:
下载源码后,
python setup.py install
或者:
pip install beautifulsoup4
具体安装方式见:点这里
因为打算下载全部的网页图片,所以从最小的单元开始,也就是图片集(再小就是单一的图片了,也就可以直接下载了)
先打开首页,随便点开一个图片集,发现图片集的地址是这样的
http://www.meitulu.com/item/7487.html
在图片集中检查页面元素,如下所示
<div class="content">
<center>
![[Ugirls尤果网] U181 陈雅漫 写真套图_第1页/第1张图](http://upload-images.jianshu.io/upload_images/2475481-8cdfce535296ab31.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
center>
<center>
![[Ugirls尤果网] U181 陈雅漫 写真套图_第1页/第3张图](http://upload-images.jianshu.io/upload_images/2475481-43e882deb2d0c0cf.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
center>
<center>
![[Ugirls尤果网] U181 陈雅漫 写真套图_第1页/第4张图](http://upload-images.jianshu.io/upload_images/2475481-2d5cb01257ad639e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
center>
<center>
![[Ugirls尤果网] U181 陈雅漫 写真套图_第1页/第5张图](http://upload-images.jianshu.io/upload_images/2475481-8e773c5ec770c466.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
center>
div>
发现每一张主要图片资源链接都在center标签中,这样就可以在这个页面上提取图片链接并下载了
继续向下,发现下图所示,图片并不是存放在一个页面中的
而检查这里的html代码可以看到
<div id="pages">
<a class="a1" href="http://www.meitulu.com/item/7487.html">上一页a>
<span>1span>
<a href="http://www.meitulu.com/item/7487_2.html">2a>
<a href="http://www.meitulu.com/item/7487_4.html">4a>
<a href="http://www.meitulu.com/item/7487_5.html">5a>
<a href="http://www.meitulu.com/item/7487_6.html">6a>
<a href="http://www.meitulu.com/item/7487_7.html">7a>
<a href="http://www.meitulu.com/item/7487_8.html">8a>
<a href="http://www.meitulu.com/item/7487_9.html">9a>
<a href="http://www.meitulu.com/item/7487_10.html">10a>
".."
<a href="http://www.meitulu.com/item/7487_16.html">16a>
<a class="a1" href="http://www.meitulu.com/item/7487_2.html">下一页a>
div>
这个页面列表在class=”pages”的div标签中,当前页是用span标签装饰的,我们可以通过提取 下一页 按钮的链接来继续下载下一个页面的图片,但是我们怎么知道什么时候会到最后一页呢?点击最后一个页面的按钮,这里就是16页。再次检查这一部分的html代码
<div id="pages">
<a class="a1" href="http://www.meitulu.com/item/7487_15.html">上一页a>
<a href="http://www.meitulu.com/item/7487.html">1a>
".."
<a href="http://www.meitulu.com/item/7487_7.html">7a>
<a href="http://www.meitulu.com/item/7487_8.html">8a>
<a href="http://www.meitulu.com/item/7487_9.html">9a>
<a href="http://www.meitulu.com/item/7487_10.html">10a>
<a href="http://www.meitulu.com/item/7487_11.html">11a>
<a href="http://www.meitulu.com/item/7487_12.html">12a>
<a href="http://www.meitulu.com/item/7487_13.html">13a>
<a href="http://www.meitulu.com/item/7487_14.html">14a>
<a href="http://www.meitulu.com/item/7487_15.html">15a>
<span>16span>
<a class="a1" href="http://www.meitulu.com/item/7487_16.html">下一页a>
div>
从这段代码中可以看到,下一页 按钮的链接指向的是16页,也就是当前页,而前面的页面指向的都是当前页的下一页。所以我们可以利用这一点来判断是否到最后一页。这样我们就有了下载一个完整图片集的思路了。
发现网站首页有一个图集分类,我们可以认为他把网站上所有的资源都放在这里分好类了,随便点开一个分类,可以看到里面有排列整齐的图集,检查html代码
<div class="boxs">
<ul class="img">
<li>
<a href="http://www.meitulu.com/item/8144.html" target="_blank">
![[尤蜜荟] 可乐Vicky 苏梅岛旅拍 第二刊 ~[43]](http://upload-images.jianshu.io/upload_images/2475481-1915763ae66ee8ad.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
a>
<p><span>3span>图片: 43 张(1600X2400)p>
<p>机构:
<a href="http://www.meitulu.com/t/tgod/" target="_blank" class="tags">推女神a>
p>
<p>模特:
<a href="http://www.meitulu.com/t/kele-vicky/" target="_blank" class="tags">可乐Vickya>
p>
<p>标签:
<a href="http://www.meitulu.com/t/jipin/" target="_blank" class="tags">极品a>
<a href="http://www.meitulu.com/t/nvshen/" target="_blank" class="tags">女神a>
<a href="http://www.meitulu.com/t/qingxin/" target="_blank" class="tags">清新a>
<a href="http://www.meitulu.com/t/qingchun/" target="_blank" class="tags">清纯a>
<a href="http://www.meitulu.com/t/weimei/" target="_blank" class="tags">唯美a>
<a href="http://www.meitulu.com/t/huwai/" target="_blank" class="tags">户外a>
<a href="http://www.meitulu.com/t/yangyan/" target="_blank" class="tags">养眼a>
p>
<p class="p_title">
<a href="http://www.meitulu.com/item/8144.html" target="_blank">[尤蜜荟] 可乐Vicky 苏梅岛旅拍 第二刊 ~a>
p>
li>
"..."
ul>
div>
从这段代码中可以发现,所有的图集被放在了 另外,对于某些只有一个图集的人来说,他没有对应的分类页面,对于这些人要另外处理 根据这些特征,我们遍历分类页面中的所有图集,通过字典记录人名对应的链接,如果遇到没有分类页面的人,则直接创建文件夹,下载图集。这样我们前期的分析工作就完成了,下面 先初始化几个要用到的全局变量 首先,我们要下载网站上所有的图片,所以需要有一个给定图片链接就能下载下来的函数: 但这还不够,因为经常会碰到链接没有响应的情况,所以加上异常处理 更进一步的,我们要处理一个给定链接的图集,首先我们写一个下载当前页面的主要图片的功能 但这还没完,记得前面提到的页面列表么,我们还要继续下载 下一页 的图片。于是继续 完善一下代码,添加异常捕捉和延时 完善代码,添加异常捕捉和延时,这里因为同一个人没有发现有多页的情况,所以没有处理页面列表的代码 完整代码在这里:simplespider.py
这段页面的下方也是一个页面列表,检查html元素会发现与图集的列表模式相同。
小结
开始写爬虫吧
categaries = {} # 分类列表
person = {} # 人名列表
PATH = os.getcwd() # 根目录路径
forbidchar = r'<|>|/|\\|\||:|"|\*|\?' # 系统禁止用作文件名的字符,正则表达式
一、图片下载函数
def downloadimg(link, name): # link为图片链接,name为图片名字
data = urlopen(link, timeout=10) # 打开连接
tname = name+".jpg" # 给图片命名
with open(tname, "ab") as code: # 以追加二进制模式打开文件,并保存数据
code.write(data.read())
print(tname+" is done.") # 打印提示文字
def downloadimg(link, name):
name = re.split(forbidchar, name)
name = '.'.join(name) # 通过re模块的split,将windows不支持的文件名符号,全部换成'.'
for i in range(10):
time.sleep(0.5) # 照顾别人服务器的带宽,适当加点延时。。。加多少看你心情
try:
data = urlopen(link, timeout=10)
tname = name+".jpg"
with open(tname, "ab") as code:
code.write(data.read())
print(tname+" is done.")
break
except Exception:
time.sleep(3) # 多数情况下,上面的语句中只有urlopen会出现无响应的异常,这时等待三秒,重新发送请求
二、图集下载函数
def downloaditem(link, ):
html = urlopen(link, timeout=100) # 打开链接
bsObj = BeautifulSoup(html, "html.parser") # 用bs解析html
for center in bsObj.findAll("center"): # 找到所有的center标签
for img in center.findAll("img"): # 找到其中包含img标签的
boola = downloadimg(img.attrs['src'], img.attrs['alt'])
# 下载image,并以图片的alt属性内容给图片命名
def downloaditem(link, ):
html = urlopen(link, timeout=100)
bsObj = BeautifulSoup(html, "html.parser")
for center in bsObj.findAll("center"):
for img in center.findAll("img"):
boola = downloadimg(img.attrs['src'], img.attrs['alt'])
#---------------------------------------------------------------------------
page = bsObj.find("div", {"id":"pages"}) # 找到所有id属性为pages的div标签
for a in page.findAll("a", {"class":"a1"}):
# 找到其中class属性为a1的a标签
if re.search(re.compile(r'下一页'), a.getText()):
# 如果标签内容包含下一页
number = re.search(re.compile(r"http://www\.meitulu\.com/.*?_([0-9]*?)\.html"), a.attrs['href'])
#用正则表达式匹配链接中的页码
if number: #如果匹配成功,失败时number为None
link = number.group(0) #提取页面链接
number = number.group(1) #提取页码
if number != page.find('span').getText():
#如果链接的页码跟当前页码不同,则不是最后一页,
print("download deeper...")#输出提示信息
downloaditem(link) #继续下载下一页
def downloaditem(link, ):
for i in range(10):
time.sleep(1)
try:
html = urlopen(link, timeout=100)
break
except Exception:
print("Url Erroe")
time.sleep(2)
for i in range(10):
try:
bsObj = BeautifulSoup(html, "html.parser")
break
except Exception:
print("Soup Error")
for center in bsObj.findAll("center"):
for img in center.findAll("img"):
boola = downloadimg(img.attrs['src'], img.attrs['alt'])
time.sleep(2)
page = bsObj.find("div", {"id":"pages"})
for a in page.findAll("a", {"class":"a1"}):
if re.search(re.compile(r'下一页'), a.getText()):
number = re.search(re.compile(r"http://www\.meitulu\.com/.*?_([0-9]*?)\.html"), a.attrs['href'])
if number:
link = number.group(0)
number = number.group(1)
if number != page.find('span').getText():
print("download deeper...")
downloaditem(link)
三、获取人名分类下的所有图集链接
def downloadperson(link, name):
name = re.split(forbidchar, name)
name = '.'.join(name) # 跟图片文件名原理一样,替换被禁止的字符
personitems = {}
if not os.path.exists(name): # 检查这个人的文件夹之前有没有创建
os.mkdir(name) # 如果没有就创建一个
os.chdir(name) # 进入这个目录
html = urlopen(link, timeout=100) # 打开链接
bsObj = BeautifulSoup(html, "html.parser") # 用bs解析
for boxs in bsObj.findAll("div", {"class":"boxs"}): # 找到装载图片集的
def downloadperson(link, name):
name = re.split(forbidchar, name)
name = '.'.join(name)
personitems = {}
if not os.path.exists(name):
os.mkdir(name)
os.chdir(name)
for i in range(10):
time.sleep(1)
try:
html = urlopen(link, timeout=100)
break
except Exception:
time.sleep(2)
print("Url Erroe")
for i in range(10):
try:
bsObj = BeautifulSoup(html, "html.parser")
break
except Exception:
print("Soup Error")
for boxs in bsObj.findAll("div", {"class":"boxs"}):
for li in boxs.findAll("li"):
try:
for p in li.findAll('p', {"class":"p_title"}):
print('\n',p,'\n')
psn = p.find('a')
personitems[psn.getText()] = psn.attrs['href']
except:
print("Find Error")
PATHtmp = os.getcwd()
for key in personitems:
print('\n', "downloading ", key, '\n')
if not os.path.exists(key):
os.mkdir(key)
os.chdir(key)
downloaditem(personitems[key])
os.chdir(PATHtmp)
os.chdir(PATH)
四、获得分类下所有人名的分类链接
def getperson(link,):
for i in range(10):
time.sleep(1)
try:
html = urlopen(link, timeout=100) # 打开连接
break
except Exception:
time.sleep(2)
print("Url Erroe")
for i in range(10):
try:
bsObj = BeautifulSoup(html, "html.parser") # bs解析
break
except Exception:
print("Soup Error")
for boxs in bsObj.findAll("div", {"class":"boxs"}): # 获取分类下包含图集的标签
for li in boxs.findAll("li"): # 逐个图集处理
try:
for a in li.findAll('p'):
print(a.getText()) # 输出图集提示信息
name = re.search(re.compile(r'^模特:(.*?)$'), a.getText())
if name:
psn = a.find('a') # 尝试查找人名分类页面链接
person[psn.getText()] = psn.attrs['href']
except: # 如果找不到分类页面,则直接下载图集
print("downloading item..."+name.group(1))
item = li.find('p', {"class":"p_title"}).find("a")
print(item.getText())
if not os.path.exists(name.group(1)):
os.mkdir(name.group(1)) # 创建人名文件夹
os.chdir(name.group(1)) # 进入人名文件夹
print(name.group(1))
name = item.getText() # 提取图集
name = re.split(forbidchar, name) # 处理图集名(文件夹名)
name = '.'.join(name)
if not os.path.exists(name):
os.mkdir(name) # 创建图集文件夹
os.chdir(name) # 进入图集文件夹
downloaditem(item.attrs['href']) # 下载图集
os.chdir(PATH) # 回到根目录
time.sleep(3) # 延时
page = bsObj.find("div", {"id":"pages"}) # 处理下一页问题,原理同downloaditem函数
for a in page.findAll("a", {"class":"a1"}):
if re.search(re.compile(r'下一页'), a.getText()):
number = re.search(re.compile(r"http://www\.meitulu\.com/t/.*?([0-9]*?)\.html"), a.attrs['href'])
link = number.group(0)
number = number.group(1)
if number != page.find('span').getText():
print("scrap deeper...")
getperson(link)
break
五、主函数
if __name__ == "__main__":
for i in range(10):
time.sleep(1)
try:
html = urlopen("http://www.meitulu.com", timeout=100) # 打开首页链接
break
except Exception:
print("Url Erroe")
time.sleep(2)
for i in range(10):
try:
bsObj = BeautifulSoup(html, "html.parser") # bs解析
break
except Exception:
print("Soup Error")
for a in bsObj.find("li", {"id":"tag"}).find("ul", {"id":"tag_ul"}).findAll("a"):
categaries[a.getText()] = a.attrs['href'] # 获取所有分类首页的链接,以分类名为key
for key in categaries:
time.sleep(3)
print(i,"loading page..."+key)
getperson(categaries[key]) # 获取每一个分类下的所有人名链接
for key in person:
downloadperson(person[key], key) # 下载每一个人名下的所有图集
总结
我在代码中延时加的比较多,所以运行起来有些慢,但毕竟这只是个练习,照顾一下别人服务器比较好= =。