python3 + scrapy爬取妹子图(meizitu.com)
前言
在学会scrapy
之前,都是用requests + BeautifulSoup + lxml
来爬取的,这样也能爬到想要的东西,但缺点是代码有些乱,可能需要自己对项目进行梳理归类。而scrapy
框架很好的解决了这个问题,它将爬虫的整个工序都分离开,各司其职,项目结构看起来很优雅。并且框架提供了很多非常实用的方法,不必再自己去单独写了,简直是良心。爬虫的乐趣在于爬取感兴趣的东西,下面将以爬取妹子图(meizitu.com)
来实践下。
了解网站,理清爬虫思路
进入妹子图,可以看到网站首页,中间有一条美女分类的标签,如图:
然后当点进某个分类之后,会得到很多分页,每个分页有很多图片专辑,点击每个专辑进去就会看到很多图片,这个图片就是我们需要的,那大致思路可以出来了,即:
- 通过首页 (
http://www.meizitu.com/
),爬取标签名称tag_name
和标签链接tag_href
- 通过标签链接,爬取当前标签下全部页面
page_list
- 通过页面,爬取当前页面的图片专辑名称
album_name
和图片专辑链接album_href
- 通过专辑链接,爬取该专辑里面所有图片名称
img_title
、图片链接img_src
及图片链接列表img_urls
- 通过图片链接,
ImagesPipeline
下载图片到设定的文件夹
通过以上思路,可以确定几点,
items
应该包含哪些?毫无疑问,
tag_name
tag_href
page_list
album_name
album_href
imgs
img_title
img_urls
就是需要定义的item
爬虫的入口是什么?
网站首页,即
http://www.meizitu.com/
爬虫应该分几层?
根据思路,我们前面 4 步,都是通过不同的链接爬取相关信息,那爬虫也相应的需要 4 层。
第一层,爬取标签链接:
parse_tag
第二层,爬取标签下页面链接:
parse_page
第三层,爬取页面下专辑链接:
parse_album
第四层,爬取专辑下图片链接:
parse_img
怎么保存图片?
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
时不太理解的地方:
yield
是干嘛的,大概就是通过yield
可以给item
返回数据 也可以发送下一个的request
请求parse_tag
中yield 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
数据传递到下一个方法继续使用和收集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=true
,image_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 来选择,没有选择的注释掉。
爬虫结果展示
迷之马赛克
后续优化
- 本来我的本意是图片按标签分类,放在不同的文件夹,然后名称以网页中的名称命名,后续可以按此归类
- 当我写这篇文章的时候,才发现
meizitu
网站首页底部是有分页的,尼玛我爬的时候没把浏览器最大化没看到,导致走了无数个弯路,所以如果纯粹的为了爬取结果的话还是多观察观察网站,如果是练手的话怎么麻烦怎么搞吧,当作练习了。
python3 + scrapy爬取妹子图(meizitu.com)相关推荐
- python scrapy 爬取妹子图的照片
主要描述在windows 上如何用scrapy抓取煎蛋网妹子图所有的图片下载. 软件准备:winpython,啥都不说了,ipython很好用. 安装scrapy,进入winpython 执行scra ...
- 用scrapy爬取妹子图网的图片,附上源代码
实现这个是因为之前在谋个公众号里面看到一篇文章,关注了也拿不到源代码 ,所以就自己写了一个爬取这个网站图片的功能.个人觉得这个网站的图片就一般吧. 开始 环境,py3, win, linux下运行都是 ...
- Scrapy爬取妹子图保存到不同目录下
进行设置settings #启动图片管道 ITEM_PIPELINES = {'mztu.pipelines.ImagesPipelinse': 300, } #设置默认目录地址 注意下载图片的话默认 ...
- python爬虫爬妹子图_【爬虫】直接上干货-爬取妹子图整站图片
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #coding=utf-8 import os import requests from lxml import etree import time cl ...
- python爬取妹子图片1_【爬虫】直接上干货-爬取妹子图整站图片
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #coding=utf-8 import os import requests from lxml import etree import time cl ...
- scrapy爬取斗图表情
用scrapy爬取斗图表情,其实呀,我是运用别人的博客写的,里面的东西改了改就好了,推存链接" http://www.cnblogs.com/jiaoyu121/p/6992587.html ...
- Python爬虫入门教程:爬取妹子图网站 - 独行大佬
妹子图网站---- 安装requests打开终端:使用命令pip3 install requests等待安装完毕即可使用接下来在终端中键入如下命令?123# mkdir demo # cd demo# ...
- 【Python】从爬虫开始吧——爬取妹子图整站
首先得解决环境和工具的问题 Python基础教程 Python3基础教程 大家也可以去慕课网看视频学习哦,关于选择Python2还是Python3的问题,上手的话还是直接选择3吧. 关于爬虫 爬虫就是 ...
- python多线程爬取妹子图网站_python爬取妹子图全站全部图片-可自行添加-线程-进程爬取,图片去重...
from bs4 import BeautifulSoup import sys,os,requests,pymongo,time from lxml import etree def get_fen ...
最新文章
- 超时流式处理 - 没有消息流入的数据异常监控
- Xamarin提示Build-tools版本过老
- 【开源项目】一个GitHub项目,囊括人脸图像要读的重要论文
- 如何应对数据库CPU打满?最优解在这里...
- count返回0_你是一直认为 count(1) 比 count(*) 效率高么?
- Linux学习之磁盘操作
- 米度教育零基础三个月学会机器学习视频总结
- 【正则表达式系列】零宽断言
- mupdf嵌入 html页面,MuPDF Command Line Tools
- DataFrame与Dataset 的区别
- 动机才是需求,问题只是现象
- 栅格数据矢量化(附有完整代码)
- Linux下rpm软件包rpm命令的安装及卸载
- A Survey on Knowledge Graph-Based Recommender
- CF632E-Thief in a Shop-生成函数,FFT,多项式快速幂
- 调查计算机游戏的目的有哪些,幼儿成长手册我参与的调查_计算机游戏对幼儿成长影响的调查分析...
- 摊牌了!我要手写一个“Spring Boot”
- php imp,Imp_在线英语听力室
- C语言字母的组合,C语言求字母的全部组合
- 信息安全之加密域可逆信息隐藏
热门文章
- 大学生活:贫穷而快乐的日子
- 不会编程,别着急!免编程工具助你快速开发App
- Android判断当前系统时间是否在指定时间的范围内(免消息打扰)
- 使用opencv批量裁剪保存图片
- 2020下半年(小学)教师资格证笔试教育教学知识与能力真题与答案
- 谷歌地图(Google Maps)接入基础篇
- Revit二次开发之绘制钢筋
- 批处理使用WinRAR压缩某类型的文件,一个文件压缩成一个压缩包,压缩后名称与原文件同名,压缩后删除原文件
- matlab如何画极零图,用MATLAB画零极点图.ppt
- 计算机应用基础网上作业2,华东理工 计算机应用基础(本)网上作业2