前言

在学会scrapy之前,都是用requests + BeautifulSoup + lxml来爬取的,这样也能爬到想要的东西,但缺点是代码有些乱,可能需要自己对项目进行梳理归类。而scrapy框架很好的解决了这个问题,它将爬虫的整个工序都分离开,各司其职,项目结构看起来很优雅。并且框架提供了很多非常实用的方法,不必再自己去单独写了,简直是良心。爬虫的乐趣在于爬取感兴趣的东西,下面将以爬取妹子图(meizitu.com)来实践下。

了解网站,理清爬虫思路

进入妹子图,可以看到网站首页,中间有一条美女分类的标签,如图:

然后当点进某个分类之后,会得到很多分页,每个分页有很多图片专辑,点击每个专辑进去就会看到很多图片,这个图片就是我们需要的,那大致思路可以出来了,即:

  1. 通过首页 (http://www.meizitu.com/),爬取标签名称tag_name和标签链接tag_href
  2. 通过标签链接,爬取当前标签下全部页面page_list
  3. 通过页面,爬取当前页面的图片专辑名称album_name和图片专辑链接album_href
  4. 通过专辑链接,爬取该专辑里面所有图片名称img_title、图片链接img_src及图片链接列表img_urls
  5. 通过图片链接,ImagesPipeline下载图片到设定的文件夹

通过以上思路,可以确定几点,

  1. items应该包含哪些?

    毫无疑问,tag_name tag_href page_list album_name album_href imgs img_title img_urls就是需要定义的item

  2. 爬虫的入口是什么?

    网站首页,即http://www.meizitu.com/

  3. 爬虫应该分几层?

    根据思路,我们前面 4 步,都是通过不同的链接爬取相关信息,那爬虫也相应的需要 4 层。

    第一层,爬取标签链接:parse_tag

    第二层,爬取标签下页面链接:parse_page

    第三层,爬取页面下专辑链接:parse_album

    第四层,爬取专辑下图片链接:parse_img

  4. 怎么保存图片?

    scrapy框架提供一个item pipeline来保存图片,即ImagesPipeline,我们只需要重写一个管道继承ImagesPipeline,并且重写get_media_requests(item, info) 和item_completed(results, items, info) 这两个方法即可

代码实践

1、首先定义item

items.py

import scrapyclass MeizituItem(scrapy.Item):# 标签名称tag_name = scrapy.Field()# 标签链接tag_href = scrapy.Field()# 进入某标签后的所有链接,加页码的page_list = scrapy.Field()# 图片专辑名称album_name = scrapy.Field()# 图片专辑链接album_href = scrapy.Field()# 照片标题img_title = scrapy.Field()# 照片链接img_src = scrapy.Field()# 照片链接集合,用于ImagesPipeline下载图片img_urls = scrapy.Field()

2、完成提取数据代码

mzt.py

# -*- coding: utf-8 -*-
import scrapyfrom meizitu.items import MeizituItemclass MztSpider(scrapy.Spider):name = 'mzt'allowed_domains = ['meizitu.com']# start_urls:爬虫入口start_urls = ['http://meizitu.com/']def parse_tag(self, response):"""提取标签名称和链接:param response::return:"""tags = response.xpath(".//*[@class='tags']/span/a")for i in tags:item = MeizituItem()tag_href = i.xpath(".//@href").extract()[0]tag_name = i.xpath(".//@title").extract()[0]item['tag_name'] = tag_nameitem['tag_href'] = tag_hrefyield scrapy.Request(url=item['tag_href'], meta={'item': item}, callback=self.parse_page)def parse_page(self, response):"""提取标签下链接:param response::return:"""item = response.meta['item']# 进入某个标签后,爬取底部分页按钮page_lists = response.xpath(".//*[@id='wp_page_numbers']/ul/li")# 获取底部分页按钮上的文字,根据文字来判断当前标签页下总共有多少分页page_list = page_lists.xpath('.//text()')# 如果当前标签页下有多个页面,则再根据第一个按钮是否为“首页”来进行再次提取,因为这里有的页面第一个按钮是首页,有的第一个按钮是“1”if len(page_lists) > 0:if page_list[0].extract() == '首页':page_num = len(page_lists) - 3else:page_num = len(page_lists) - 2else:page_num = 1# 根据当前标签页的链接,来拼成带页码的链接if '_' in item['tag_href']:index = item['tag_href'][::-1].index('_')href_pre = item['tag_href'][:-index]else:if page_num == 1:href_pre = item['tag_href'].split('.html')[0]else:href_pre = item['tag_href'].split('.html')[0] + '_'for i in range(1, page_num + 1):item = response.meta['item']if page_num == 1:href = href_pre + '.html'else:href = href_pre + str(i) + '.html'item['page_list'] = hrefyield scrapy.Request(url=item['page_list'], meta={'item': item}, callback=self.parse_album)def parse_album(self, response):"""提取专辑名称和专辑链接:param response::return:"""albums = response.xpath(".//*[@class='pic']")for album in albums:item = response.meta['item']album_href = album.xpath(".//a/@href").extract()[0]album_name = album.xpath(".//a/img/@alt").extract()[0]item['album_name'] = album_nameitem['album_href'] = album_hrefyield scrapy.Request(url=item['album_href'], meta={'item': item}, callback=self.parse_img)def parse_img(self, response):"""提取图片名称和链接:param response::return:"""img_list = response.xpath(".//*/p/img")for img in img_list:item = response.meta['item']img_title = img.xpath(".//@alt").extract()[0]if img_title == '':for i in range (1, len(img_list+1)):img_title = item['album_name'] + '_' + str(i)else:img_title = img_titleimg_urls = img.xpath(".//@src").extract()img_src = img.xpath(".//@src").extract()[0]item['img_title'] = img_titleitem['img_src'] = img_srcitem['img_urls'] = img_urlsyield item

这里面都是数据提取的过程,比较麻烦的在parse_page,各个标签下的链接结构不一样,导致在拼链接的时候需要判断很多种情况,这些的话可以一步一步的调试,遇到错误就多加判断。

下面说下我在学习scrapy时不太理解的地方:

  1. yield是干嘛的,大概就是通过yield 可以给 item 返回数据 也可以发送下一个的 request 请求
  2. parse_tagyield scrapy.Request(url=item['tag_href'], meta={'item': item}, callback=self.parse_page),可以理解为把item['tag_href']作为url,传递给parse_page这个request请求,得到新的response用以提取数据,meta={'item': item}可以把之前收集到的item数据传递到下一个方法继续使用和收集
  3. item = response.meta['item']就是接收传递过来的item数据,可以继续使用和收集

3、保存图片

以下为抄其他博主的:

保存图片需要在自定义的 ImagePipeline 类中重载方法:get_media_requests(item, info)item_completed(results, items, info)Pipeline将从 item 中获取图片的 URLs 并下载它们,所以必须重载get_media_requests,并返回一个Request对象,这些请求对象将被 Pipeline 处理,当完成下载后,结果将发送到item_completed方法,这些结果为一个二元组的 list,每个元祖的包含(success, image_info_or_failure)。 * success: boolean值,true表示成功下载 * image_info_or_error:如果success=trueimage_info_or_error词典包含以下键值对。失败则包含一些出错信息。 * url:原始 URL * path:本地存储路径 * checksum:校验码

pipelines.py

import scrapy
from scrapy import log
from scrapy.contrib.pipeline.images import ImagesPipeline
from scrapy.exceptions import DropItemclass MztImagesPipeline(ImagesPipeline):def get_media_requests(self, item, info):for image_url in item['img_urls']:yield scrapy.Request(image_url)def item_completed(self, results, item, info):image_paths = [x['path'] for ok, x in results if ok]if not image_paths:raise DropItem("该Item没有图片")return item

仅仅这些还是不够的,你还需要设置下图片保存的路径、图片大小限制、过期天数等等,在settings.py中添加以下代码

IMAGES_STORE = r'E:\\mzt'    # 图片存储路径
IMAGES_EXPIRES = 90             # 过期天数
IMAGES_MIN_HEIGHT = 100         # 图片的最小高度
IMAGES_MIN_WIDTH = 100          # 图片的最小宽度

并且在settings.py中的ITEM_PIPELINES加上'meizitu.pipelines.MztImagesPipeline': 301

这样当图片的宽带或高度小于最小的时候就不会下载了,下载成功的图片会保存在E:\\\mzt\\full中。

4、爬虫运行

默认的运行需要在命令行中执行 scrapy crawl spider_name,这样的缺点是不能在IDE里面debug代码,比较不方便。所以,可以自己在项目里面新建一个run.py,以后执行这个文件就相当于启动爬虫。

run.py

from scrapy import cmdline# cmdline.execute("scrapy crawl mzt".split())    # 直接执行,log显示在控制台
cmdline.execute("scrapy crawl mzt -s LOG_FILE=mzt.log".split())  # log保存在项目里面的mzt.log文件

以上两条语句都可以启动爬虫,可根据是否需要保存 log 来选择,没有选择的注释掉。

爬虫结果展示

迷之马赛克

后续优化

  1. 本来我的本意是图片按标签分类,放在不同的文件夹,然后名称以网页中的名称命名,后续可以按此归类
  2. 当我写这篇文章的时候,才发现meizitu网站首页底部是有分页的,尼玛我爬的时候没把浏览器最大化没看到,导致走了无数个弯路,所以如果纯粹的为了爬取结果的话还是多观察观察网站,如果是练手的话怎么麻烦怎么搞吧,当作练习了。

python3 + scrapy爬取妹子图(meizitu.com)相关推荐

  1. python scrapy 爬取妹子图的照片

    主要描述在windows 上如何用scrapy抓取煎蛋网妹子图所有的图片下载. 软件准备:winpython,啥都不说了,ipython很好用. 安装scrapy,进入winpython 执行scra ...

  2. 用scrapy爬取妹子图网的图片,附上源代码

    实现这个是因为之前在谋个公众号里面看到一篇文章,关注了也拿不到源代码 ,所以就自己写了一个爬取这个网站图片的功能.个人觉得这个网站的图片就一般吧. 开始 环境,py3, win, linux下运行都是 ...

  3. Scrapy爬取妹子图保存到不同目录下

    进行设置settings #启动图片管道 ITEM_PIPELINES = {'mztu.pipelines.ImagesPipelinse': 300, } #设置默认目录地址 注意下载图片的话默认 ...

  4. python爬虫爬妹子图_【爬虫】直接上干货-爬取妹子图整站图片

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #coding=utf-8 import os import requests from lxml import etree import time cl ...

  5. python爬取妹子图片1_【爬虫】直接上干货-爬取妹子图整站图片

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #coding=utf-8 import os import requests from lxml import etree import time cl ...

  6. scrapy爬取斗图表情

    用scrapy爬取斗图表情,其实呀,我是运用别人的博客写的,里面的东西改了改就好了,推存链接" http://www.cnblogs.com/jiaoyu121/p/6992587.html ...

  7. Python爬虫入门教程:爬取妹子图网站 - 独行大佬

    妹子图网站---- 安装requests打开终端:使用命令pip3 install requests等待安装完毕即可使用接下来在终端中键入如下命令?123# mkdir demo # cd demo# ...

  8. 【Python】从爬虫开始吧——爬取妹子图整站

    首先得解决环境和工具的问题 Python基础教程 Python3基础教程 大家也可以去慕课网看视频学习哦,关于选择Python2还是Python3的问题,上手的话还是直接选择3吧. 关于爬虫 爬虫就是 ...

  9. python多线程爬取妹子图网站_python爬取妹子图全站全部图片-可自行添加-线程-进程爬取,图片去重...

    from bs4 import BeautifulSoup import sys,os,requests,pymongo,time from lxml import etree def get_fen ...

最新文章

  1. 超时流式处理 - 没有消息流入的数据异常监控
  2. Xamarin提示Build-tools版本过老
  3. 【开源项目】一个GitHub项目,囊括人脸图像要读的重要论文
  4. 如何应对数据库CPU打满?最优解在这里...
  5. count返回0_你是一直认为 count(1) 比 count(*) 效率高么?
  6. Linux学习之磁盘操作
  7. 米度教育零基础三个月学会机器学习视频总结
  8. 【正则表达式系列】零宽断言
  9. mupdf嵌入 html页面,MuPDF Command Line Tools
  10. DataFrame与Dataset 的区别
  11. 动机才是需求,问题只是现象
  12. 栅格数据矢量化(附有完整代码)
  13. Linux下rpm软件包rpm命令的安装及卸载
  14. A Survey on Knowledge Graph-Based Recommender
  15. CF632E-Thief in a Shop-生成函数,FFT,多项式快速幂
  16. 调查计算机游戏的目的有哪些,幼儿成长手册我参与的调查_计算机游戏对幼儿成长影响的调查分析...
  17. 摊牌了!我要手写一个“Spring Boot”
  18. php imp,Imp_在线英语听力室
  19. C语言字母的组合,C语言求字母的全部组合
  20. 信息安全之加密域可逆信息隐藏

热门文章

  1. 大学生活:贫穷而快乐的日子
  2. 不会编程,别着急!免编程工具助你快速开发App
  3. Android判断当前系统时间是否在指定时间的范围内(免消息打扰)
  4. 使用opencv批量裁剪保存图片
  5. 2020下半年(小学)教师资格证笔试教育教学知识与能力真题与答案
  6. 谷歌地图(Google Maps)接入基础篇
  7. Revit二次开发之绘制钢筋
  8. 批处理使用WinRAR压缩某类型的文件,一个文件压缩成一个压缩包,压缩后名称与原文件同名,压缩后删除原文件
  9. matlab如何画极零图,用MATLAB画零极点图.ppt
  10. 计算机应用基础网上作业2,华东理工 计算机应用基础(本)网上作业2