这次打算使用urllib来着,因为作为小白并没有发现urllib与request的区别,想到requests还要安装,不如用自带的urllib.
但在使用的过程中发现设置urllib每次都要手动设置抓取内容的编码,于是继续用requests
基本逻辑为

  • 爬取网站首页,获得所有类型
  • 遍历爬取类型页面,获得该类型下所有页数
  • 遍历页数爬取每页所有套图封面
  • 遍历该列表页每个套图页,获取图片[根据规则拼接图片网址]
# -*- coding UTF-8 -*- 

import requests
import re
import os

class Craw(object):
    """docstring for Craw"""
    baseurl=r"http://www.mm131b.com/"
    type_name=''
    type_count=1
    page_count=1
    group_count=1
    group_path=''
    imgdir="mm/"
    init=True
    def __init__(self):
        super(Craw, self).__init__()
        self.main()

    #处理分类页
    def types(self,type_name):
        print (r"读取%s类型"%(type_name))
        if not os.path.exists(self.imgdir+type_name):
            os.makedirs(self.imgdir+type_name)
        self.type_name=type_name
        typeurl=self.baseurl+type_name
        type_content=requests.get(typeurl).text
        # 获取该分类下的页数
        max_page=re.findall(r"(?<=<strong>)(\d)",type_content)[0]
        if self.init==False:
            self.page_count=1
        while self.page_count<=int(max_page):
            self.lists()
        self.type_count+=1

    #处理列表页
    def lists(self):
        print(r"处理%s类型第%d页"%(self.type_name,self.page_count))
        url=self.baseurl+self.type_name+"/list_%d_%d.html"%(self.type_count,self.page_count)
        #创建列表页文件夹
        self.group_path="%s%s%s%d%d"%(self.imgdir,self.type_name,"/",self.type_count,self.page_count)
        if not os.path.exists(self.group_path):
            os.makedirs(self.group_path)
        list_page=requests.get(url)
        #处理编码
        list_page.encoding="gbk"
        # 0 链接 2 标题 4 封面图地址
        lists = re.findall(r"(?<=href=\"\/)(.+?)(\".+?pic\sshow\"\stitle=\")(.+?)(\".+?scrollLoading.+?xSrc=\")(.+?.jpg)(\")",list_page.text)
        if self.init==False:
            self.group_count=0
        # print(lists);
        # exit()
        for k,v in enumerate(lists):
            if k<self.group_count:
                print("跳过第%d组套图,历史目标%d组"%(k,self.group_count))
                continue
            self.group(v)
        self.page_count+=1

    #处理套图页
    def group(self,i):
        self.group_count+=1
        self.init=False
        print("处理套图<%s>"%(i[2]))
        img=requests.get(i[4])
        if(img.status_code!=200):
            print("套图<%s>加载失败,跳过"%(i[2]))
            return
        name="%d%d%d"%(self.type_count,self.page_count,self.group_count)
        #封面图
        with open(self.group_path+"/"+name+i[2]+".jpg","wb") as f:
            f.write(img.content)
            f.close()
        imgs=requests.get(self.baseurl+i[0])
        imgs.encoding="gbk"
        img_count=1
        #利用图片地址规则构建单张图片页 本来是用抓取的单页地址解析
        #后来发现图片多的会隐藏一部分,并且select虽然全但是js添加的,无法抓到
        #图片地址格式 数字_序号 如23201_2 首图无序号 即 23201
        img_code=re.findall(r"^.+(?=\.html)",i[0])
        while True:
            #非首图
            if img_count!=1:
                imgs=requests.get("%s%s%s%d%s"%(self.baseurl,img_code[0],"_",img_count,".html"))
                #通过返回长度判断是否跳转 (即已经没有更多图片 跳转回首页了)
                if(int(imgs.headers['Content-Length'])<200):
                    # print("%s%s%s%d"%(self.baseurl,img_code[0],"_",img_count))
                    print("<%s>套图下载完成,共%d张"%(i[2],img_count))
                    return
            #提取图片地址
            img=re.findall(r"src=[\'|\"](.+?)[\'|\"]\salt=[\'|\"]",imgs.text)
            if(not img):
                print("套图<%s>含有无效图片,跳过"%(i[2]))
                return
            #保存图片
            img=requests.get(img[0])
            with open(self.group_path+"/%s%d%s"%(name,img_count,".jpg"),"wb") as f:
                f.write(img.content)
                f.close()
            #记录当前执行位置
            with open(self.imgdir+"log.log","w") as f:
                # type,page,group
                f.write("%d,%d,%d"%(self.type_count,self.page_count,self.group_count))
                f.close()
            img_count+=1

    #主函数
    def main(self):

        #爬到一定数量后会报错连接过多
        #解决这一问题 
        s = requests.session()
        s.keep_alive = False
        #重试次数上限
        requests.adapters.DEFAULT_RETRIES = 15

        main_content = re.findall(r"(?<=href\=\'\/)\w+(?=\/\'\s)",requests.get(self.baseurl).text)
        #读取之前记录 从上次执行的记录继续执行
        with open(self.imgdir+"log.log",'a+') as f:
            f.seek(0)
            log=f.read()
            if log :
                log=log.split(',')
                self.type_count=int(log[0])
                self.page_count=int(log[1])
                self.group_count=int(log[2])
            f.close()
        #该网站的列表页规则为 list_1_1 第一个1是分类 第二个1是页码
        #对于不存在的会自动跳转回首页
        for k,v in enumerate(main_content):
            if k+1 < self.type_count:
                continue
            self.types(v)

Craw()