项目地址:https://github.com/Centurywang/spider_DownloadMeizituPictures/tree/master/scrapy_meizitu
注意:需要事先安装好redis数据库并开启远程访问 (方法百度)
步骤一 创建项目
# 安装 scrapy pip install scrapy # 安装 scrapy-redis pip install scrapy-redis # 安装 redis包 pip install redis # 创建项目 scrapy startproject meizitu_spider # 生成爬虫文件 spiders/meizi.py (功能:上传url队列 ) scrapy genspider meizi mzitu.com # 生成爬虫文件 spiders/meizi_download.py (功能:读取url队列进行爬取并下载) scrapy genspider meiziDownload mzitu.com
步骤二 分析网页
1.百度搜索 “妹子图” 点击第一个结果

2.分析网页可以发现,前四个分类网页结构相同

3.在每一页都有大量套图,每个套图url在 id=”pins” 的 ul 标签下的 li 标签下的第一个 a 标签的 href 属性

4.下一页的url地址在 标签文字为 “下一页»” 的 a 标签的 href 属性

5.点击进入一个套图 分析网页结构
发现每张图片占一页,获取所有图片需要循环套图内所有页面
图片url在 class=”main-image” 的 div 标签下的 img 标签的 src 属性

下一页url地址在 文字为 “下一页»” 的 span 的父标签 a 的 href 属性

最后一页没有 “下一页” 而是 “下一组”,所以循环获取”下一页”就可以获得该套图的所有图片null

步骤三 编辑爬虫文件
上传需要爬取的url队列
meizi.py
# -*- coding: utf-8 -*- import scrapy class MeiziSpider(scrapy.Spider): '''功能: 获取套图url并存入redis 数据库(数据类型list)''' # 爬虫名 用于执行爬虫时使用 name = 'meizi' # 允许爬取的网址限制 allowed_domains = ['mzitu.com'] # 四个分类的url地址 start_urls = ['https://www.mzitu.com/xinggan/','https://www.mzitu.com/japan/','https://www.mzitu.com/taiwan/','https://www.mzitu.com/mm/'] def parse(self, response): '''解析函数 获取套图url地址''' # 通过xpath语法获取每个li标签内容 (每个套图信息在不同li标签下) page_img_content = response.xpath('//div[@class="postlist"]//ul//li') # 循环获取的li标签内容 for img_content in page_img_content: # 字典 用于保存单个套图url地址 item = {} # 套图url在li标签下的第一个a标签的href属性 "extract_first()" 代表提取第一个 item['url'] = img_content.xpath('./a[1]/@href').extract_first() # 返回 item yield item # 获取下一页 下一页的url地址在 标签文字为 "下一页»" 的 a 标签的 href 属性 next_page_url = response.xpath('//a[text()="下一页»"]/@href').extract_first() # 如果下一页地址存在 if next_page_url is not None: # 请求下一页 调用parse函数 yield scrapy.Request( url=next_page_url, callback=self.parse )
在settings.py文件内加入
# 启用在redis中调度存储请求队列。 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 确保所有爬行器通过redis共享相同的副本。 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" 目管道序列化并将项目存储在这个redis键中。 #REDIS_ITEMS_KEY = '%(spider)s:items' # 默认情况下,条目序列化器是ScrapyJSONEncoder。您可以使用任何可导入路径到可调用对象。 #REDIS_ITEMS_SERIALIZER = 'json.dumps' # 指定连接到Redis的完整url # root:用户名 password:密码 localhost:redis服务器的ip地址 6379:redis端口 REDIS_URL = 'redis://root:password@localhost:6379'
现在可以在创建的项目执行上传请求url的功能
# 进入项目目录 cd meizitu_spider # 执行命令 # scrapy crawl:执行爬虫 # meizi:爬虫名 scrapy crawl meizi
获取请求url并下载图片
meiziDownload.py
# -*- coding: utf-8 -*- import scrapy # 导入redis库 import redis class MeiziDownloadSpider(scrapy.Spider): '''获取套图url''' # 以下同上一个meizi.py文件 name = 'meizi_d' allowed_domains = ['mzitu.com'] # 重写start_requests函数 def start_requests(self): # 连接redis数据库 # password:密码 host:redis服务器ip地址 port:端口 decode_response=True 以字符串形式返回结果 r = redis.Redis(password='password',host='localhost',port=6379,decode_responses=True) # 设置循环 循环获取redis数据库内的url地址 start_url = True while start_url is not None: # 从redis list 循环取出爬取url地址 作为开始url start_url = eval(r.lpop('meizi:items'))['url'] # 发起请求,调用parse函数 yield scrapy.Request(url=start_url,callback=self.parse) def parse(self, response): '''获取套图所有图片地址''' # 获取图片地址 item['image_urls'] = response.xpath('//div[@class="main-image"]//img/@src').extract() item = {} # 获取套图名 item['name'] = response.xpath('//div[@class="currentpath"]//text()').extract()[-1][3:] print(item) # 返回item yield item # 获取下一页url地址 下一页url地址在 文字为 "下一页»" 的 span 的父标签 a 的 href 属性 next_page_url = response.xpath('//a[./span/text()="下一页»"]/@href').extract_first() # 如果下一页存在 if next_page_url is not None: # 请求下一页url 调用parse函数 yield scrapy.Request(url=next_page_url,callback=self.parse)

编写pipelines.py文件 实现下载图片功能
class ImagesrenamePipeline(ImagesPipeline): '''保存图片''' def get_media_requests(self, item, info): # 添加headers是因为下载图片需要headers headers = { 'Referer': 'https://www.mzitu.com/', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36' } # 循环每一张图片地址下载,若传过来的不是集合则无需循环直接yield for image_url in item['image_urls']: # meta里面的数据是从spider获取,然后通过meta传递给下面方法:file_path yield scrapy.Request(image_url,headers=headers, meta={'name': item['name']}) # 重命名,若不重写这函数,图片名为哈希,就是一串乱七八糟的名字 def file_path(self, request, response=None, info=None): # 提取url前面名称作为图片名。 image_guid = request.url[-8:] # 接收上面meta传递过来的图片名称 name = request.meta['name'] # 分文件夹存储的关键:{0}对应着name;{1}对应着image_guid filename = u'{0}/{1}'.format(name, image_guid) return filename
将settings.py文件内 的ITEM_PIPELINES改为 同时加入一行 IMAGES_STORE = ‘./Picture’
ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 300, 'scrapy_meizitu.pipelines.ImagesrenamePipeline':301, } # 该行代表的是保存图片的地址 此处代表保存在该目录下的Picture目录 IMAGES_STORE = './Picture'
注意:执行上传url队列时需要删掉ITEM_PIPELINES第二行,下载时需要增加第二行
执行下载图片命令
scrapy crawl meizi_d
此时可以看到项目目录下出现Picture目录,目录内正在保存下载图片

如需在其它机器执行爬虫,只需安装好所需的python包并将项目复制,进入项目目录并执行爬虫命令 scrapy crawl meizi_d 即可
需要注意:redis的配置需正确
到此项目完成