爬虫第一炮-福利网站:妹子图

基础环境

  • python环境:2.7.13
  • python类库:Requests[1]、beautifulsoup[2]、LXML[3]
pip install Requests
pip install beautifulsoup4
pip install LXML

流程示例图

爬虫教程第一炮之流程示意图

  • 爬虫入口:顾名思义我们需要程序从什么地方开始爬取网页
  • 存储数据:如果获取的网页有你需要的内容则取出数据保存
  • 提取页面URL:如果你你获取到的网页没有你需要的数据,但是有前往该数据页面的地址URL,则获取该地址URL,再次循环爬虫入口爬取

准备工作完了 ヽ(●-`Д´-)ノ ,我们马上开搞码代码了。

一个简单爬虫的诞生大慨需要下面几个步骤(图很简陋、将就着看看)。


第一步、获取顶级爬虫入口

好啦!现在来开始看看网站找一个爬虫入口(开始爬取的页面):http://www.mzitu.com/all/

爬虫教程第一炮之入口页面

下面是我们的第一段代码:用作获取 http://www.mzitu.com/all/ 的页面内容。

# -*- coding:utf-8 -*-
# -----------------------
# 载入类型
# -----------------------
# 载入类库[系统]
import sys
# 载入类库[操作系统]
import os
# 载入类库[网络请求]
import requests
# 载入类库[页面美化]
from bs4 import BeautifulSoup





# -----------------------
# 初始化配置
# -----------------------
# 设置文件编码[UTF-8]
reload(sys)
sys.setdefaultencoding('utf-8')





# -----------------------
# 常量定义
# -----------------------
# 浏览器请求头(大部分网站没有这个请求头会报错,请务必加上)
HEADERS  = { 'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" }
# 起始抓取URL
ROOT_URL = 'http://www.mzitu.com/all'





# -----------------------
# 功能处理
# -----------------------
# 发起请求[GET]
html = requests.get(ROOT_URL, headers=HEADERS)
# 打印网页(注意:concent是二进制的数据,一般用于下载图片、视频、音频、等多媒体内容是才使用concent, 对于打印网页内容请使用text)
print(html.text)

如果您使用的IDE是 Sublime Text ,您可以使用 CTRL + B 进行快捷运行Python程序。

运行结果:

爬虫教程第一炮之整页输出

至此,第一部分获取网页内容的部分完成啦!马上进行下一步操作。

第二步、提取页面有效信息

浏览器进入爬虫入口页面(http://www.mzitu.com/all/),按下 F12 调出 Firefox 的开发者调试工具 Firebug(若大家不了解,上网搜索一下 :>)

爬虫教程第一炮之开发者调试工具

通过滑动鼠标定位标签的方法来找到我们需要的数据在哪?!(实例很简陋,看不懂的童鞋百度一下啦!教程很多的)

爬虫教程第一炮之定位元素

观察网页你会发现美女图片页面的地址全部在<li>…</li>标签中,如此有规则,轻松定位。

爬虫教程第一炮之锁定属性

点开 <li> 标签你会发现图片帖子的网址URL在 <a> 标签的 href 属性中、帖子标题是 <a> 标签的内容。

实现逻辑: 先找到页面中的全部 <li> 标签、然后提取出对应 <a> 标签的 href 属性值与 <a> 标签的内容。前者我们用来继续请求html看看会不会有我们需要的图片下载地址,后者我们归类每个帖子的图片用作文件夹命名使用。

注意:为什么不直接查找 <a> 标签?
解答:如果直接查找 <a> 标签,就会筛选出很多我们不需要的内容,先查找 <li> 标签就是限制一下 <a> 标签的有效范围!

通过上面的方法,就可以知道我们需要的数据位置!接下来,该我们的 beautifulsoup 来大展身手了!

下面是我们的第二段代码:用作获取图片帖子信息

# -*- coding:utf-8 -*-
# -----------------------
# 载入类型
# -----------------------
# 载入类库[系统]
import sys
# 载入类库[操作系统]
import os
# 载入类库[网络请求]
import requests
# 载入类库[页面美化]
from bs4 import BeautifulSoup





# -----------------------
# 初始化配置
# -----------------------
# 设置文件编码[UTF-8]
reload(sys)
sys.setdefaultencoding('utf-8')





# -----------------------
# 常量定义
# -----------------------
# 浏览器请求头(大部分网站没有这个请求头会报错,请务必加上)
HEADERS  = { 'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" }
# 起始抓取URL
ROOT_URL = 'http://www.mzitu.com/all'





# -----------------------
# 功能处理
# -----------------------
# 发起请求[GET]
html = requests.get(ROOT_URL, headers=HEADERS)
# 打印网页(注意:concent是二进制的数据,一般用于下载图片、视频、音频、等多媒体内容是才使用concent,对于打印网页内容请使用text)
# print(html.text)

# 解析网页(lxml是指定的解析器)
soup = BeautifulSoup(html.text, 'lxml')
# 定位标签(find_all是查找网页的所有标签)
elements = soup.find_all('li')
# 打印标签
for element in elements:
    print(element)

爬虫教程第一炮之输出标签

抓取到了我们不需要的内容!这可怎么办?!再次分析一下看看。

爬虫教程第一炮之精确定位

仔细分析页面结构之后,我们发现只要先找到 <div class=”all”> 标签,然后再定位找 <a> 标签即可!

注意:路径不是应该是 div.all>li>a 的吗?
解答:仔细瞅瞅源文件! <div class=”all”></div> 中的 <a> 标签的全是我们需要的,就不需要再定位 <a> 标签来限制提取范围了!这样也方便写代码。

继续码代码,代码如下:

# -*- coding:utf-8 -*-
# -----------------------
# 载入类型
# -----------------------
# 载入类库[系统]
import sys
# 载入类库[操作系统]
import os
# 载入类库[网络请求]
import requests
# 载入类库[页面美化]
from bs4 import BeautifulSoup





# -----------------------
# 初始化配置
# -----------------------
# 设置文件编码[UTF-8]
reload(sys)
sys.setdefaultencoding('utf-8')





# -----------------------
# 常量定义
# -----------------------
# 浏览器请求头(大部分网站没有这个请求头会报错,请务必加上)
HEADERS  = { 'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" }
# 起始抓取URL
ROOT_URL = 'http://www.mzitu.com/all'





# -----------------------
# 功能处理
# -----------------------
# 发起请求[GET]
html = requests.get(ROOT_URL, headers=HEADERS)
# 打印网页(注意:concent是二进制的数据,一般用于下载图片、视频、音频、等多媒体内容是才使用concent,对于打印网页内容请使用text)
# print(html.text)

# 解析网页(lxml是指定的解析器)
soup = BeautifulSoup(html.text, 'lxml')
# 定位标签(find_all是查找网页的所有标签)
# elements = soup.find_all('li')
# 定位标签(检索路径:`div.all a`)
elements = soup.find('div', class_='all').find_all('a')
# 打印标签
for element in elements:
    print(element)

API理解:

  • ‘find’: 查找一次给定的标签,返回对象。就算后面还有一样的标签也不会提取出来。
  • ‘find_all’: 查找所有给定的标签,返回list。

看看运行结果:

爬虫教程第一炮之精确定位结果

至此,我们已经找到了所有需要的内容。接下来,我们需要提取出 < a> 标签的 href 属性和文本。

# -*- coding:utf-8 -*-
# -----------------------
# 载入类型
# -----------------------
# 载入类库[系统]
import sys
# 载入类库[操作系统]
import os
# 载入类库[网络请求]
import requests
# 载入类库[页面美化]
from bs4 import BeautifulSoup





# -----------------------
# 初始化配置
# -----------------------
# 设置文件编码[UTF-8]
reload(sys)
sys.setdefaultencoding('utf-8')





# -----------------------
# 常量定义
# -----------------------
# 浏览器请求头(大部分网站没有这个请求头会报错,请务必加上)
HEADERS  = { 'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" }
# 起始抓取URL
ROOT_URL = 'http://www.mzitu.com/all'





# -----------------------
# 功能处理
# -----------------------
# 发起请求[GET]
html = requests.get(ROOT_URL, headers=HEADERS)
# 解析网页(lxml是指定的解析器)
soup = BeautifulSoup(html.text, 'lxml')
# 定位标签(检索路径:`div.all a`)
elements = soup.find('div', class_='all').find_all('a')
# 打印标签
for element in elements:
    # 获得标签文本
    text = element.get_text()
    # 获得标签属性[href]
    href = element['href']

    # 打印结果
    print(text, href)

就多了两行代码!结果就出来了!我们来打印一下结果看看!

爬虫教程第一炮之目标列表数据

好了,我们已经找向目标前进了一半了!至此,列表页的数据全部已经获得到。

上面我们找到了 图片的标题(暂时不管,后面用来创建文件夹的)和 图片页面的网址(这是我们这一步需要做的)

先查看一下图片页面有什么内容,你会发现一个页面只有一张图片!如何下载一整套呢?
点击一下面的 1、2、3、4··· 你会发现地址栏里面的URL在变化啊!这就是我们的入手的地方了!

爬虫教程第一炮之套图分析

疑问:如何获得最大页码?
解答:页码在 < span> 标签中,我们只需要获取最后一个页码, 然后从 1 开始历遍,再拼接捕获的基础URL就是每张图片的页面地址了!

通过分析页面可知,页码定位为:“div.pagenavi span”,即 < div class=”pagenavi”> 下的所有 < span> 元素,最大页码为倒数第二个 < span> 内容,因为最后一个为“下一页”。

再一次更新代码:

# -*- coding:utf-8 -*-
# -----------------------
# 载入类型
# -----------------------
# 载入类库[系统]
import sys
# 载入类库[操作系统]
import os
# 载入类库[网络请求]
import requests
# 载入类库[页面美化]
from bs4 import BeautifulSoup





# -----------------------
# 初始化配置
# -----------------------
# 设置文件编码[UTF-8]
reload(sys)
sys.setdefaultencoding('utf-8')





# -----------------------
# 常量定义
# -----------------------
# 浏览器请求头(大部分网站没有这个请求头会报错,请务必加上)
HEADERS  = { 'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" }
# 起始抓取URL
ROOT_URL = 'http://www.mzitu.com/all'





# -----------------------
# 功能处理
# -----------------------
# 发起请求[GET]
html = requests.get(ROOT_URL, headers=HEADERS)
# 解析网页(lxml是指定的解析器)
soup = BeautifulSoup(html.text, 'lxml')
# 定位标签(检索路径:`div.all a`)
elements = soup.find('div', class_='all').find_all('a')
# 打印标签
for element in elements:
    # 获得标签文本
    text = element.get_text()
    # 获得标签属性[href]
    href = element['href']

    # 调试日志
    # print(text, href)

    # 发起请求[GET]
    html2 = requests.get(href, headers=HEADERS)
    # 解析网页
    soup2 = BeautifulSoup(html2.text, 'lxml')
    # 图片页码(倒二个为最大页码,倒一个为“下一页”)
    max_page = soup2.find('div', class_='pagenavi').find_all('span')[-2].get_text()
    # 遍历页码,拼接套图每页网址
    for page in range(1, int(max_page) + 1):
        # 图片网址(套图中每张图片)
        page_url = href + '/' + str(page)
        # 打印结果(每张图片的页面地址!但还不是实际地址!)
        print(page_url)

运行之后结果如下!已经成功获得每个套图的所有图片:

爬虫教程第一炮之所有套图所有图片

每个页面的地址都出来了!!!
下面开始找图片的实际地址了!
随意打开上面的地址用F12调试工具试试!

爬虫教程第一炮之主图地址

通过分析发现我们需要的主图地址在 < div class=”main-image”> 中的 < img> 标签的 src 属性中。现在应该已经轻车熟路了吧!马上编写:

# -*- coding:utf-8 -*-
# -----------------------
# 载入类型
# -----------------------
# 载入类库[系统]
import sys
# 载入类库[操作系统]
import os
# 载入类库[网络请求]
import requests
# 载入类库[页面美化]
from bs4 import BeautifulSoup





# -----------------------
# 初始化配置
# -----------------------
# 设置文件编码[UTF-8]
reload(sys)
sys.setdefaultencoding('utf-8')





# -----------------------
# 常量定义
# -----------------------
# 浏览器请求头(大部分网站没有这个请求头会报错,请务必加上)
HEADERS  = { 'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" }
# 起始抓取URL
ROOT_URL = 'http://www.mzitu.com/all'





# -----------------------
# 功能处理
# -----------------------
# 发起请求[GET]
html = requests.get(ROOT_URL, headers=HEADERS)
# 解析网页(lxml是指定的解析器)
soup = BeautifulSoup(html.text, 'lxml')
# 定位标签(检索路径:`div.all a`)
elements = soup.find('div', class_='all').find_all('a')
# 打印标签
for element in elements:
    # 获得标签文本
    text = element.get_text()
    # 获得标签属性[href]
    href = element['href']

    # 调试日志
    # print(text, href)

    # 发起请求[GET]
    html2 = requests.get(href, headers=HEADERS)
    # 解析网页
    soup2 = BeautifulSoup(html2.text, 'lxml')
    # 图片页码(倒二个为最大页码,倒一个为“下一页”)
    max_page = soup2.find('div', class_='pagenavi').find_all('span')[-2].get_text()
    # 遍历页码,拼接套图每页网址
    for page in range(1, int(max_page) + 1):
        # 图片网址(套图中每张图片)
        page_url  = href + '/' + str(page)
        # 图片网址内容
        html3 = requests.get(page_url, headers=HEADERS)
        # 解析网页
        soup3 = BeautifulSoup(html3.text, 'lxml')
        # 主图网址
        image_url = soup3.find('div', class_='main-image').find('img')['src']

        # 打印结果
        print(image_url)

运行程序,得到以下结果:

爬虫教程第一炮之打印套图所有图片

完美!输出的就是我们想要的东西,下面就要开始保存了!哈哈!妹子马上就可以到你碗里去了!

第三步、分类保存所有图片

我们需要为每个套图建一个文件夹,然后将下载的图片以URL的 x.jpg 中的x命名保存到这个文件夹里面。直接上代码了!

# -*- coding:utf-8 -*-
# -----------------------
# 载入类型
# -----------------------
# 载入类库[系统]
import sys
# 载入类库[操作系统]
import os
# 载入类库[网络请求]
import requests
# 载入类库[页面美化]
from bs4 import BeautifulSoup





# -----------------------
# 初始化配置
# -----------------------
# 设置文件编码[UTF-8]
reload(sys)
sys.setdefaultencoding('utf-8')





# -----------------------
# 常量定义
# -----------------------
# 浏览器请求头(大部分网站没有这个请求头会报错,请务必加上)
HEADERS     = { 'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" }
# 起始抓取URL
ROOT_URL    = 'http://www.mzitu.com/all'
# 保存路径
ROOT_OUTPUT = 'D:\\mzitu\\'





# -----------------------
# 功能处理
# -----------------------
# 发起请求[GET]
html = requests.get(ROOT_URL, headers=HEADERS)
# 解析网页(lxml是指定的解析器)
soup = BeautifulSoup(html.text, 'lxml')
# 定位标签(检索路径:`div.all a`)
elements = soup.find('div', class_='all').find_all('a')
# 打印标签
for element in elements:
    # 获得标签文本(去除空格,注意:解决\x目录中文问题一定要加decode)
    text = str(element.get_text()).strip().decode('utf-8').replace('?', '_')
    # 获得标签属性[href]
    href = element['href']

    # 调试日志
    # print(text, href)

    # 计算套图路径
    output_folder = os.path.join(ROOT_OUTPUT, text)
    # 创建套图目录
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
    # 切换套图目录
    os.chdir(output_folder)

    # 发起请求[GET]
    html2 = requests.get(href, headers=HEADERS)
    # 解析网页
    soup2 = BeautifulSoup(html2.text, 'lxml')
    # 图片页码(倒二个为最大页码,倒一个为“下一页”)
    max_page = soup2.find('div', class_='pagenavi').find_all('span')[-2].get_text()
    # 遍历页码,拼接套图每页网址
    for page in range(1, int(max_page) + 1):
        # 图片网址(套图中每张图片)
        page_url  = href + '/' + str(page)
        # 图片网址内容
        html3 = requests.get(page_url, headers=HEADERS)
        # 解析网页
        soup3 = BeautifulSoup(html3.text, 'lxml')
        # 主图网址
        image_url = soup3.find('div', class_='main-image').find('img')['src']

        # 调试日志
        # print(image_url)

        # 图片保存名称(取URL倒数第四至第九位做为图片的名称)
        output_name = image_url[-9:-4]
        # 图片文件数据
        output_data = requests.get(image_url, headers=HEADERS)

        # 保存图片文件(写入多媒体文件必须要b这个参数)
        handle = open(output_name+'.jpg', 'ab')
        handle.write(output_data.content) # 多媒体文件要是用conctent
        handle.close()

运行结果:

爬虫教程第一炮之抓取结果

哈哈哈,完美搞定!!!如果仅限于此,那么我们就可以结束了。有兴趣的兄弟姐妹再跟着我一起简单调整一下代码,封装成面向对象的写法。

直接上代码:

# -*- coding:utf-8 -*-
# -----------------------
# 载入类型
# -----------------------
# 载入类库[系统]
import sys
# 载入类库[操作系统]
import os
# 载入类库[网络请求]
import requests
# 载入类库[页面美化]
from bs4 import BeautifulSoup





# -----------------------
# 初始化配置
# -----------------------
# 设置文件编码[UTF-8]
reload(sys)
sys.setdefaultencoding('utf-8')





# -----------------------
# 常量定义
# -----------------------
# 浏览器请求头(大部分网站没有这个请求头会报错,请务必加上)
HEADERS     = { 'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" }
# 起始抓取URL
ROOT_URL    = 'http://www.mzitu.com/all'
# 保存路径
ROOT_OUTPUT = 'D:\\mzitu\\'





# -----------------------
# 类型定义
# -----------------------
class App():

    # 构造方法
    # @param root_url: 起始抓取URL
    # @param root_output: 起始抓取URL
    def __init__(self, root_url, root_output):
        self.root_url = root_url
        self.root_output = root_output

    # 运行程序(入口方法)
    def run(self):
        # 发起请求[GET]
        html = self.request(self.root_url)
        # 解析网页(lxml是指定的解析器)
        soup = BeautifulSoup(html.text, 'lxml')
        # 定位标签(检索路径:`div.all a`)
        elements = soup.find('div', class_='all').find_all('a')
        # 打印标签
        for element in elements:
            # 获得标签文本(去除空格,注意:解决\x目录中文问题一定要加decode)
            text = str(element.get_text()).strip().decode('utf-8').replace('?', '_')
            # 获得标签属性[href]
            href = element['href']

            # 调试日志
            print(u'---------')
            print(u'开始保存:' + text)

            # 进入套图目录
            self.switch_dir(text)
            # 下载套图图片
            self.download(href)

    # 发起请求
    # @param url: 网址URL
    def request(self, url):
        # 发起请求[GET]
        html = requests.get(url, headers=HEADERS)
        # 返回结果
        return html

    # 进入套图目录
    # 若目录不存在则进行创建,然后进入目录
    # @param name: 套图目录名称
    def switch_dir(self, name):
        # 计算套图路径
        folder = os.path.join(self.root_output, name)
        # 创建套图目录
        if not os.path.exists(folder):
            # 创建目录
            os.makedirs(folder)
            # 调试日志
            print(u'创建套图目录:' + name)
            # 切换目录
            os.chdir(folder)
            # 返回结果[真]
            return True
        else:
            # 调试日志
            print(u'忽略创建套图目录:' + name)
            # 切换目录
            os.chdir(folder)
            # 返回结果[假]
            return False

    # 下载套图图片
    # @param url: 套图网址
    def download(self, url):
        # 发起请求[GET]
        html = self.request(url)
        # 解析网页
        soup = BeautifulSoup(html.text, 'lxml')
        # 图片页码(倒二个为最大页码,倒一个为“下一页”)
        max_page = soup.find('div', class_='pagenavi').find_all('span')[-2].get_text()

        # 调试日志
        print(u'套图图片数量:' + max_page)

        # 遍历页码,拼接套图每页网址
        for page in range(1, int(max_page) + 1):
            # 图片网址(套图中每张图片)
            page_url  = url + '/' + str(page)
            # 下载图片
            self.download_image_by_page(page_url)

    # 下载单张图片
    # @param url: 单图网址(页面网址)
    def download_image_by_page(self, url):
        # 图片网址内容
        html = self.request(url)
        # 解析网页
        soup = BeautifulSoup(html.text, 'lxml')
        # 主图网址
        image_url = soup.find('div', class_='main-image').find('img')['src']
        # 保存主图
        self.download_image(image_url)

    # 下载单张图片
    # @param url: 单图网址(图片网址)
    def download_image(self, url):
        # 图片保存名称(取URL倒数第四至第九位做为图片的名称)
        output_name = url[-9:-4]
        # 图片文件数据
        output_data = self.request(url)

        # 保存图片文件(写入多媒体文件必须要b这个参数)
        handle = open(output_name+'.jpg', 'ab')
        handle.write(output_data.content) # 多媒体文件要是用conctent
        handle.close()





# -----------------------
# 入口方法
# -----------------------
# 运行应用程序
App(ROOT_URL, ROOT_OUTPUT).run()

至此,程序改造完成。:) 细心的朋友应该发现,上面的版本如果需要完善必须至少再支持下面两个功能:

  • 断点续载(非再次下载强行覆盖)
  • 错误重试

下面就将我们的代码改造一下,结单吧。

# -*- coding:utf-8 -*-
# -----------------------
# 载入类型
# -----------------------
# 载入类库[系统]
import sys
# 载入类库[操作系统]
import os
# 载入类库[网络请求]
import requests
# 载入类库[页面美化]
from bs4 import BeautifulSoup





# -----------------------
# 初始化配置
# -----------------------
# 设置文件编码[UTF-8]
reload(sys)
sys.setdefaultencoding('utf-8')





# -----------------------
# 常量定义
# -----------------------
# 浏览器请求头(大部分网站没有这个请求头会报错,请务必加上)
HEADERS     = { 'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" }
# 起始抓取URL
ROOT_URL    = 'http://www.mzitu.com/all'
# 保存路径
ROOT_OUTPUT = 'D:\\mzitu\\'
# 错误重试次数
ERROR_RETRY = 3
# 断点续载
IS_CONTINUED = True





# -----------------------
# 类型定义
# -----------------------
class App():

    # 构造方法
    # @param root_url: 起始抓取URL
    # @param root_output: 起始抓取URL
    def __init__(self, root_url, root_output):
        self.root_url = root_url
        self.root_output = root_output
        self.error_retry = ERROR_RETRY
        self.is_continued = IS_CONTINUED

    # 运行程序(入口方法)
    def run(self):
        # 发起请求[GET]
        html = self.request(self.root_url)
        # 解析网页(lxml是指定的解析器)
        soup = BeautifulSoup(html.text, 'lxml')
        # 定位标签(检索路径:`div.all a`)
        elements = soup.find('div', class_='all').find_all('a')
        # 打印标签
        for element in elements:
            # 获得标签文本(去除空格,注意:解决\x目录中文问题一定要加decode)
            text = str(element.get_text()).strip().decode('utf-8').replace('?', '_')
            # 获得标签属性[href]
            href = element['href']

            # 调试日志
            print(u'---------')
            print(u'开始保存:' + text)

            # 进入套图目录
            self.switch_dir(text)
            # 下载套图图片
            self.download(href)

    # 发起请求
    # @param url: 网址URL
    def request(self, url):
        # 发起请求[GET]
        html = requests.get(url, headers=HEADERS)
        # 返回结果
        return html

    # 进入套图目录
    # 若目录不存在则进行创建,然后进入目录
    # @param name: 套图目录名称
    def switch_dir(self, name):
        # 计算套图路径
        folder = os.path.join(self.root_output, name)
        # 创建套图目录
        if not os.path.exists(folder):
            # 创建目录
            os.makedirs(folder)
            # 调试日志
            print(u'创建套图目录:' + name)
            # 切换目录
            os.chdir(folder)
            # 返回结果[真]
            return True
        else:
            # 调试日志
            print(u'忽略创建套图目录:' + name)
            # 切换目录
            os.chdir(folder)
            # 返回结果[假]
            return False

    # 下载套图图片
    # @param url: 套图网址
    def download(self, url):
        # 发起请求[GET]
        html = self.request(url)
        # 解析网页
        soup = BeautifulSoup(html.text, 'lxml')
        # 图片页码(倒二个为最大页码,倒一个为“下一页”)
        max_page = soup.find('div', class_='pagenavi').find_all('span')[-2].get_text()

        # 调试日志
        print(u'套图图片数量:' + max_page)

        # 遍历页码,拼接套图每页网址
        for page in range(1, int(max_page) + 1):
            # 图片网址(套图中每张图片)
            page_url  = url + '/' + str(page)
            # 下载图片
            self.download_image_by_page(page_url, self.error_retry)

    # 下载单张图片
    # @param url: 单图网址(页面网址)
    # @param retry: 错误重试次数
    def download_image_by_page(self, url, retry):
        # 调试日志
        print(u'\t正在下载:' + url)

        # 过滤判断
        if retry <= 0:
            return

        # 启动下载
        try:
            # 图片网址内容
            html = self.request(url)
            # 解析网页
            soup = BeautifulSoup(html.text, 'lxml')
            # 主图网址
            image_url = soup.find('div', class_='main-image').find('img')['src']
            # 保存主图
            self.download_image(image_url)
        except Exception, e:
            # 调试日志
            print(u'\t下载出错重试:' + url + ' - [' + str(self.error_retry - retry + 1) + ']')
            # 再次下载
            self.download_image_by_page(url, --retry)

    # 下载单张图片
    # @param url: 单图网址(图片网址)
    def download_image(self, url):
        # 图片保存名称(取URL倒数第四至第九位做为图片的名称)
        output_name = url[-9:-4]+'.jpg'

        # 判断断点续载
        if self.is_continued and os.path.exists(output_name):
            print(u'\t开启断点续载,本图像已下载当即跳过')
            return

        # 图片文件数据
        output_data = self.request(url)
        # 保存图片文件(写入多媒体文件必须要b这个参数)
        handle = open(output_name, 'ab')
        handle.write(output_data.content) # 多媒体文件要是用conctent
        handle.close()

    # 设置错误重试
    # @param value: 值
    def set_error_retry(self, value):
        self.error_retry = value
        return self

    # 设置断点续载
    # @param value: 值
    def set_continued(self, value):
        self.is_continued = value
        return self





# -----------------------
# 入口方法
# -----------------------
# 运行应用程序
App(ROOT_URL, ROOT_OUTPUT).run()

爬虫教程第一炮之结果运行效果

完整代码均已贴上,有兴趣的同学可以试一下。全部下载下来大概超过8GB。注意身体。


源码下载地址:面向对象编程 & 面向过程编程

脚注

[1] Requests类库urllib 的升级版本,简化了使用方法并完善了功能。传送门

[2] beautifulsoup类库:HTML/XML的解析器,它可以很好的处理不规范标记并生成剖析树。它提供简单又常用的导航,搜索以及修改剖析树的操作。传送门

[3] LXML类库:一个HTML解析包,用于辅助beautifulsoup解析网页。传送门