Scrapy爬虫框架之———— 多页爬取图片的信息
ok, 接下来我们要将怎样多页爬取图片的信息,以及如何下载图片。
知识点涉及到:
-
自动的翻页爬取
-
多个parse 之间的request 传递
-
构建图片爬取的通道
さあ!始めようぜ!
首先我们要爬取的网站是这个: 知名的动漫壁纸网 Konachan.net
确定了目标之后,我们的第一个任务是创建一个爬虫项目以及一个爬虫
scrapy startproject konachan
scrapy genspider kona konachan.net
然后就是我们要解析这个网页,主页给的都是缩略图,我们要高清大图,就像点开这样:
所以我们还需要一个内置的网页的url, 我们可以在主页中进行爬取
那么我们任务开始,首先确定要爬取的内容,在items.py规定:(item.py文件如下)
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class KonachanItem(scrapy.Item):
# define the fields for your item here like:
#由于我们使用的是scrapy 自带的图片下载通道,所以url 和图片名称必须按照配置文件设置
# 即 Item里面 url 信息设置为 image_urls, 图片名称信息 设置为images
image_urls = scrapy.Field() # 即 Item里面 url 信息设置为 image_urls
images=scrapy.Field() # 图片名称信息 设置为images
detailed=scrapy.Field() # 高清页面的url
#由于我们使用的是scrapy 自带的图片下载通道,所以url 和图片名称必须按照配置文件设置
# 即 Item里面 url 信息设置为 image_urls, 图片名称信息 设置为images
然后是观察我们爬取信息的元素,使用F12(鼠标右键——检查) 进行元素的查看:
通过检查我们可以发现,在每个class为inner的div下的一个class="thumb" 里面的href属性对应的 url地址(相对于http://kona.net的相对地址),我们可以通过xpath进行提取:
def parse(self, response):
#获得要爬取的url的相对地址
url_list = response.xpath("//div[@class='inner']//a[@class='thumb']/@href").extract()
# 获得url的绝对地址
for url in url_list:
item1=KonachanItem()
item1["detailed"] = url
item1["detailed"] = "http://konachan.net" + item1["detailed"]
然后我们还要爬取下一页信息,我们同样可以进行检查:
我们看到了,在这个里面 Next对应的网址是 在class="next_page"的a标签中。那么,我们同样可以通过xpath进行提取,
next_url= response.xpath("//a[@class='next_page']/@href").extract_first()
next_url='http://konachan.net'+ next_url
#这里仅仅是测试哈,考虑内存只爬取两页
if(self.cnt<2):
self.cnt+=1
# 回调给自己,继续解析
yield scrapy.Request(
next_url,
callback=self.parse
)
然后,我们需要在写一个parse 函数爬取详情页的图片地址,我们将其命名为parse_detail
我们首先观察详情页:
对应的图片信息的url在class=content的div 下的 id为image的image标签里面的src属性,同样用xpath爬取。不过parse_detail函数必须首先获得parse里面爬取到detail 的url 的request请求,并且获得item里面的url信息,并且以此为爬取的网页。因此,我们补充parse函数的具体内容:
def parse(self, response):
#获得要爬取的url的相对地址
url_list = response.xpath("//div[@class='inner']//a[@class='thumb']/@href").extract()
# 获得url的绝对地址
for url in url_list:
item1=KonachanItem()
item1["detailed"] = url
item1["detailed"] = "http://konachan.net" + item1["detailed"]
#将绝对地址给第二个解析函数 parse_detail 进行解析
yield scrapy.Request(
item1["detailed"],
callback = self.parse_detail,
meta={"item":item1} #meta 以字典的形式传递item信息
)
我们加入的如下部分,构造了一个Request请求,给pars_detail执行,并且把url信息用meta传递。
yield scrapy.Request(
item1["detailed"],
callback = self.parse_detail,
meta={"item":item1} #meta 以字典的形式传递item信息
)
结合上述所写,我们来写parse_detail 函数:
#定义解析详情页的函数
def parse_detail(self,response):
#接受parse函数传递的请求,接受item信息
item1=response.meta["item"]
#解析网页
item1["image_urls"] = response.xpath("//div[@class='content']//img/@src").extract()
#确定每次都传一个url
if len(item1["image_urls"])<2:
item1["image_urls"] = item1["image_urls"]
yield item1
ok,写完后,我们去写pipline.py
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import logging
logger= logging.getLogger(__name__)
class KonachanPipeline(object):
def process_item(self, item, spider):
logger.warning(item["inner_url"])
return item
这里不过是让它把爬到的信息 以日志的形式输出而已(便于查看),可以不写不改。
接下来我们要使用scrapy自带的图片管道去下载图片,首先在spider中插入引用:
# -*- coding: utf-8 -*-
import scrapy
#引入定义的item
from konachan.items import KonachanItem
# 引入 scrapy 自带的图片爬取通道,注意在setting里面要进行注释。
from scrapy.pipelines.images import ImagesPipeline
这个scrapy.pipelins.image.ImagePipeline需要在settings.py里面注册:
ITEM_PIPELINES = {
'konachan.pipelines.KonachanPipeline': 300,
# 对图片通道进行注册
'scrapy.pipelines.images.ImagesPipeline':299
}
然后我们需要在settings.py 里面设置图片存取的文件名地址,以及用item的什么字段做需要下载的url.
我们可以看一个scrapy自带的ImagePiplines里面的source code:
MEDIA_NAME = 'image'
# Uppercase attributes kept for backward compatibility with code that subclasses
# ImagesPipeline. They may be overridden by settings.
MIN_WIDTH = 0
MIN_HEIGHT = 0
EXPIRES = 90
THUMBS = {}
#这就是之前我们设置item属性为 image_urls以及images的原因:
DEFAULT_IMAGES_URLS_FIELD = 'image_urls'
DEFAULT_IMAGES_RESULT_FIELD = 'images'
def __init__(self, store_uri, download_func=None, settings=None):
super(ImagesPipeline, self).__init__(store_uri, settings=settings,
download_func=download_func)
if isinstance(settings, dict) or settings is None:
settings = Settings(settings)
resolve = functools.partial(self._key_for_pipe,
base_class_name="ImagesPipeline",
settings=settings)
self.expires = settings.getint(
resolve("IMAGES_EXPIRES"), self.EXPIRES
)
if not hasattr(self, "IMAGES_RESULT_FIELD"):
self.IMAGES_RESULT_FIELD = self.DEFAULT_IMAGES_RESULT_FIELD
if not hasattr(self, "IMAGES_URLS_FIELD"):
self.IMAGES_URLS_FIELD = self.DEFAULT_IMAGES_URLS_FIELD
self.images_urls_field = settings.get(
resolve('IMAGES_URLS_FIELD'),
self.IMAGES_URLS_FIELD
)
self.images_result_field = settings.get(
resolve('IMAGES_RESULT_FIELD'),
self.IMAGES_RESULT_FIELD
)
self.min_width = settings.getint(
resolve('IMAGES_MIN_WIDTH'), self.MIN_WIDTH
)
self.min_height = settings.getint(
resolve('IMAGES_MIN_HEIGHT'), self.MIN_HEIGHT
)
self.thumbs = settings.get(
resolve('IMAGES_THUMBS'), self.THUMBS
)
所以按照固定,我们还要在settings.py写图片的存储地址:
import os
BOT_NAME = 'konachan'
SPIDER_MODULES = ['konachan.spiders']
NEWSPIDER_MODULE = 'konachan.spiders'
# 定义log等级,只显示warning
LOG_LEVEL="WARNING"
project_dir=os.path.abspath(os.path.dirname(__file__)) #获取当前爬虫项目的绝对路径
IMAGES_STORE = os.path.join(project_dir,'images') #组装新的图片路径
IMAGES_URLS_FIELD='image_urls' #图片使用的字段
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/66.0'
# Obey robots.txt rules
ROBOTSTXT_OBEY = True
ok,完事大吉,我们可以运行我们的爬虫了!
scrapy crawl kona
结果 输出为:
我们可以看懂,yield 返回了许多item ,并且都打印出来的item里面的url
我们查看我们保存图片的文件:
可以,看到图片被很好download了。
查看完全代码,可以查看我的github
https://github.com/Magicboomliu/ScrapyImage