环境:windows7 + python2.7
相关库:lxml + json + urllib
爬取的网站地址:http://www.mzitu.com/ (。。。捂脸)
本人是社会主义好青年,本次抓取只将所有图片的原始地址抓到后保存为json文件,并不下载图片!
好了开始吧
首先需要一个可以抓取页面的函数
#获取网页
def getHtml(url):
res = urllib.urlopen(url)
html = res.read().encode('utf8')
return html
打开网页即可在首页下方看到所有页面的数,最大值就是我们所需要的
Paste_Image.png
审查元素发现这个值放在一个a标签下,要拿到这个页面数值,我们使用xpath解析网页
#获取一共有多少页专题
def getAllPages(url):
html = etree.HTML(getHtml(url))
pages = html.xpath('/html/body/div[2]/div[1]/div[2]/nav/div/a[4]/text()')
pages = int(pages[0])
return pages
使用审查元素查看网页代码可以发现,每一个页面有多个专题,这些专题存放在id值为pins的ul列表里,每一个li标签存放一个专题
Paste_Image.png
想要得到每个专题中所有的图片我们需要获取每个专题的名称和链接,使用代码
#根据传进来的页面地址获取当页所有专题的链接和名称
def everyPage(page):
url = 'http://www.mzitu.com/page/%d'%page
html = etree.HTML(getHtml(url))
pins_list = html.xpath('//*[@id="pins"]/li') #获取每个页面所有专题xpath列表
for pins in pins_list:
mkdirs = pins.xpath('a/@href') #专题链接
mkdirs_name = pins.xpath('a/img/@alt') #专题名称
得到专题的链接之后我们进入专题
Paste_Image.png
可以发现每个妹子所拥有的图片数量不一致,且每一个页面只有一张图。多浏览几张图片,可以看出专题内的图片很有规律,第二张的页面地址是这样的
http://www.mzitu.com/86102/2
,第三张的页面地址http://www.mzitu.com/86102/3
,所以我们只要得出这个专题一共有多少页面就能知道有多少张图和每张图所存放的地址了。
#获取每个专题所有图片的地址
def everySemImgUrls(sem_name,url):
html = etree.HTML(getHtml(url))
images = html.xpath('//div[@class="pagenavi"]/a[last()-1]/span/text()') #每个专题图片数量
mmpags = [url+'/'+str(x) for x in range(1,int(images[0])+1)] #生成图片页面列表
拿到了每张图所在的页面地址,那么就剩下获取图片的原始地址了
Paste_Image.png
同样使用xpath
#获取单个页面下的图片地址
def getImageUrl(url):
html = etree.HTML(getHtml(url))
src = html.xpath('//div[@class="main-image"]/p/a/img/@src')
src = src[0]
return src #返回每张图片的地址
最后就是保存到json文件
所有代码如下
#-*- coding:utf-8 -*-
import urllib
import threadpool
from lxml import etree
import json
#获取网页
def getHtml(url):
res = urllib.urlopen(url)
html = res.read().encode('utf8')
return html
#获取一共有多少页专题
def getAllPages(url):
html = etree.HTML(getHtml(url))
pages = html.xpath('/html/body/div[2]/div[1]/div[2]/nav/div/a[4]/text()')
pages = int(pages[0])
return pages
#获取单个页面下的图片地址
def getImageUrl(url):
html = etree.HTML(getHtml(url))
src = html.xpath('//div[@class="main-image"]/p/a/img/@src')
try:
src = src[0]
except IndexError,e:
print e
print src
return src #返回每张图片的地址
#获取每个专题所有图片的地址
def everySemImgUrls(sem_name,url):
html = etree.HTML(getHtml(url))
images = html.xpath('//div[@class="pagenavi"]/a[last()-1]/span/text()') #每个专题图片数量
mmpags = [url+'/'+str(x) for x in range(1,int(images[0])+1)] #生成图片页面列表
sem_image = []
for jpgUrl in mmpags:
imgUrl = getImageUrl(jpgUrl)
sem_image.append(imgUrl)
pageMMurls = {}
pageMMurls[sem_name] = {}
pageMMurls[sem_name]['sem_url'] = url
pageMMurls[sem_name]['sem_images'] = sem_image
readed = {}
try:
readed = json.load(open('mzitu.json','r'))
except Exception,e:
pass
with open('mzitu.json','w') as f:
readed[sem_name] = pageMMurls[sem_name]
json.dump(readed,f,sort_keys=True,indent=4,separators=(',',': '),encoding="utf8",ensure_ascii=False)
print sem_name+' -'+images[0]+'-张'
#获取一个页面中所有专题名及连接
def everyPage(page):
url = 'http://www.mzitu.com/page/%d'%page
html = etree.HTML(getHtml(url))
pins_list = html.xpath('//*[@id="pins"]/li') #获取每个页面所有专题xpath列表
print '本页共有专题--%d--个'%pins_list.__len__()
for pins in pins_list:
mkdirs = pins.xpath('a/@href') #专题链接
mkdirs_name = pins.xpath('a/img/@alt') #专题名称
everySemImgUrls(mkdirs_name[0],mkdirs[0])
def main():
pages = getAllPages('http://www.mzitu.com/') #从主页获取所有页面数量
print '共发现--%d--页专题'%pages
for page in range(1,pages+1):
print '准备下载第--%d--页'%page
everyPageDict = everyPage(page)
if __name__ == '__main__':
main()
总结:
1、本次爬虫为单线程,速度慢且偶尔有中途停车现象。下次来玩儿再来优化