在本篇文章中,我以图片类爬虫项目为例,讲解如何通过Scrapy框架实现图片爬虫项目。
一、功能分析
假如我们现在需要做一个图片设计或者需要将互联网上的一些图片进行分析和参考,需要下载互联网中的一些素材,此时若通过互联网一个一个网页地打开查看或者一个一个地下载,这样会比较麻烦,这种情况下我们就可以将相应网站中相关栏目下的素材图片全部爬到本地使用。
在本项目中,主要需要实现的功能有:
- 获取目标网站下的图片素材。
- 将原图片素材(非缩略图)下载并保存到本地的对应目录中。
由于网站列表页中显示的图片URL为对应图片的缩略图URL地址,而缩略图的像素显然没有原图高,不够清晰,所以我们在项目中需要爬取对应图片的原图URL,而缩略图和原图的URL之间是有一定规律的,这个规律在接下来的实现过程中将具体分析。
二、项目实现思路
为了提高项目开发的效率,避免在项目开发的过程中思路混乱,我们需要在项目开发前首先理清该项目的实现思路及实现步骤。本项目的实现思路及实现步骤如下所示:
- 对要爬取的网页进行分析,发现要获取的内容的规律,总结出提取对应数据的表达式,并且发现不同图片列表页URL之间的规律,总结出自动爬取各页的方式。
- 创建Scrapy爬虫项目。
- 编写好项目对应的items.py、pipelines.py、settings.py文件。
- 创建并编写项目中的爬虫文件,实现爬取当前列表页面的所有原图,以及自动爬取指定页数的各图片列表页。
三、图片类爬虫项目编写实战
目标网页:http://699pic.com/tupian/kaixue.html
分析:
每个图片放在一个class = list的div里面,其中src和data-original中均为该图片的缩略图地址,我们通过scrapy shell命令可以看出:
所有的src中的URL全部变成了blank.png,可能是该网站的某种反爬虫机制,但data-original属性依然还是图片的缩略图地址,那么就通过该属性对图片URL进行爬取。
下面来看看某一张图片的缩略图地址和原图的地址比较:
缩略图地址:http://img95.699pic.com/photo/50038/3415.jpg_wh300.jpg
原图地址:http://seopic.699pic.com/photo/50038/3415.jpg_wh1200.jpg
通过查看若干图片的两个URL,我们可以看出,将缩略图中的"img95"替换成"seopic",然后把"wh_300"换成"wh1200"就变成了原图的URL。
分析得差不多,接下来就通过以下命令行创建爬虫项目:
scrapy startproject picture
首先,编写items.py文件,将默认items.py文件修改如下,关键部分已给出注释:
import scrapy
class PictrueItem(scrapy.Item):
# define the fields for your item here like:
picurl = scrapy.Field() #存储图片的地址
name = scrapy.Field() #存储图片名以构造本地文件名
下面编写pipelines.py文件,将默认pipelines.py文件修改如下,关键部分已给出注释:
import urllib.request
class PictruePipeline(object):
def process_item(self, item, spider):
for i in range(0,len(item["picurl"])): #遍历item,并将缩略图url根据规律变成原图的url
url = item["picurl"][i] #得到缩略图的url
realurl = url.replace("img95","seopic") + ".jpg_wh1200.jpg"
name = item["name"][i] #得到图片的名字
localpath = "E://picture//" + name + ".jpg" #将要保存到的本地路径
# print(realurl + " " + localpath)
urllib.request.urlretrieve(realurl,filename = localpath) #将图片下载到本地
return item
然后,修改配置文件settings.py,将配置文件中关于pipelines的配置部分修改为如下所示,这样就可以开启使用pipelines.py文件了:
# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'pictrue.pipelines.PicturePipeline': 300,
}
为了避免爬虫被服务器通过我们的Cookie信息识别从而将我们的爬虫禁止,可以关闭使用Cookie,将设置文件中的COOKIES_ENABLED修改为如下所示:
# Disable cookies (enabled by default)
COOKIES_ENABLED = False
为了避免服务器的robots.txt文件对我们的爬虫进行限制,可以在文件中设置不遵循robots协议进行爬取,我们将设置文件中的ROBOTSTXT_OBEY部分设置为如下所示:
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
最后,编写爬虫文件如下,关键部分代码已给出注释:
import scrapy
import re
from scrapy.http import Request
from pictrue.items import PictrueItem
class PictureSpider(scrapy.Spider):
name = "picture" #爬虫的名字叫picture
start_urls = [ 'http://699pic.com/tupian/kaixue.html'] #目标网页的url
def parse(self, response):
items = PictrueItem()
url = "(http://img95.699pic.com/photo/.*?/.*?).jpg_wh300.jpg" #通过正则表达式找出所有图片缩略图的url
items["picurl"] = re.compile(url).findall(str(response.body)) #匹配得到所有url
name = "http://img95.699pic.com/photo/.*?/(.*?).jpg_wh300.jpg" #通过正则表达式找出所有图片的名字
items["name"] = re.compile(name).findall(str(response.body)) #匹配得到所有name
yield items
for i in range(2,52): 爬取从第2页到末页的所有图片列表页
nexturl = "http://699pic.com/sousuo-265126-0-" + str(i) + "-0-0-0.html"
yield Request(nexturl, callback=self.parse)
其中每一个列表页的网址形如:
http://699pic.com/sousuo-265126-0-2-0-0-0.html(第2页)
http://699pic.com/sousuo-265126-0-3-0-0-0.html(第3页)
那么nexturl就可以通过改变其中的数字来不断地向后爬取网页,因此:
nexturl = "http://699pic.com/sousuo-265126-0-" + str(i) + "-0-0-0.html"
四、运行与总结
通过以下命令行执行爬虫项目:
scrapy crawl picture
可以看到,此时成功实现了图片爬虫项目,并且此时的图片都是高质量清晰版的。
小结:
- 由于文章列表页中显示的图片URL为对应图片的缩略图URL地址,而缩略图的效果不如原图效果好,比如不够清晰,所以我们在本项目中会爬去对应图片的原图URL,而缩略图和原图的URL之间是有一定规律的,需要我们自己去分析与总结。
- 掌握该项目中的urllib.request.urlretrieve()方法。