scrapy框架真的比request库写爬虫麻烦挺多,但是作为一个框架,他有自己的优势,今天就试着用scrapy爬取汽车之家的图片,改名爬一下pixiv的图片试试hh,这次也是网易云课程的项目实践。

准备工作

首先创建项目
image.png
这里是用的基本创建scrapy框架的步骤:
1.先创建project
2.将创建相应的启动程序,固定套路。
3.进去去除机器人协议
4.设置请求头headers(这两步在settings文件下设定)

  1. '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'

请求头user-agent都是固定的,所以我拿过来。
然后创建一个cmd_starts.py,方便代码的调试。

  1. from scrapy import cmdline
  2. cmdline.execute(("scrapy crawl coolcar").split())

正式开始-一种基础的下载方法

coolcar.py

  1. # -*- coding: utf-8 -*-
  2. import scrapy
  3. from bmw.items import BmwItem
  4. class CoolcarSpider(scrapy.Spider):
  5. name = 'coolcar'
  6. allowed_domains = ['car.autohome.com.cn/']
  7. start_urls = ['https://car.autohome.com.cn/pic/series/4867.html#pvareaid=2042194']
  8. def parse(self, response):
  9. uiboxs = response.xpath("//div[@class = 'uibox']")[1:]
  10. for uibox in uiboxs:
  11. category = uibox.xpath(".//div[@class = 'uibox-title']/a/text()").get()
  12. urls = uibox.xpath(".//ul/li/a/img/@src").getall()
  13. urls = list(map(lambda url:response.urljoin(url),urls) ) #匿名函数,执行代码,加入https://,但是要注意转换成list
  14. item = BmwItem(category= category,urls = urls)
  15. yield item #这里使用生成器,当然也可以总的生成一个列表返还回去

上面是爬虫的主体部分,负责爬虫。
然后还要指定结构体,item。
items.py

  1. # -*- coding: utf-8 -*-
  2. # See documentation in:
  3. # https://doc.scrapy.org/en/latest/topics/items.html
  4. import scrapy
  5. class BmwItem(scrapy.Item):
  6. category = scrapy.Field()
  7. urls = scrapy.Field()

这样就得到了相应的url了。

  1. # -*- coding: utf-8 -*-
  2. # Define your item pipelines here
  3. #
  4. # Don't forget to add your pipeline to the ITEM_PIPELINES setting
  5. # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
  6. import os
  7. from urllib import request
  8. class BmwPipeline(object):
  9. def __init__(self):
  10. self.path = os.path.join(os.path.dirname(os.path.dirname(__file__)),'imges')
  11. if not os.path.exists(self.path):
  12. os.mkdir(self.path) #判断有没有文件夹,没有的话就创建一个
  13. def process_item(self, item, spider):
  14. category = item['category']
  15. urls = item['urls']
  16. category_path = os.path.join(self.path,category)
  17. if not os.path.exists(category_path):
  18. os.mkdir(category_path)
  19. for url in urls:
  20. image_name = url.split("_")[-1] #得到图片名字
  21. request.urlretrieve(url,os.path.join(category_path,image_name))
  22. return item

这样运行start就可以下载到文件夹里了。

异步操作-更快更高更强

image.png
image.png
懒得输入了,之间搬截图,可以看出这个方法是指定的方法。
下面用简单的下载方法表示一下:
修改的地方有下面两个:
image.pngimage.png
分别在items和主程序进行一定修改。
然后settings修改一下如下:

  1. ITEM_PIPELINES = {
  2. # 'bmw.pipelines.BmwPipeline': 300,
  3. 'scrapy.pipelines.images.ImagesPipeline':1,
  4. }
  5. #在最后面要制定下载路径
  6. IMAGES_STORE = os.path.join(os.path.dirname(os.path.dirname(__file__)),'images')

其实就是用的上面的方法,但是速度直接提升了几倍。
但是缺点是下载下来的图片是这样滴。
image.png
呕吼,没有分类撒。别急,接下来还要操作一番。要想实现需求,就要自己重写一下pipeline。
这样就很难很难了我觉得。
首先,先放代码:

  1. class Bmw_pipeline(ImagesPipeline):
  2. def get_media_requests(self, item, info):
  3. #这个方法实在发送下载请求之前调用
  4. #其实这个方法本身就是去发送下面的请求的
  5. request_objs = super(Bmw_pipeline, self).get_media_requests(item,info) #返回有request对象的一个列表
  6. for request_obj in request_objs:
  7. request_obj.item = item #这里把item绑定在request上来
  8. return request_objs
  9. def file_path(self, request, response=None, info=None):
  10. #这个方法是在图片将要被图片存储的时候调用,来获取图片的存储路径
  11. path = super(Bmw_pipeline, self).file_path(request,response,info)
  12. category = request.item.get('category') #这里其实传递进来了
  13. images_store = settings.IMAGES_STORE #这里取基础目录
  14. category_path = os.path.join(images_store,category)
  15. #加入一个路径,文件夹+下属的文件夹名字
  16. image_name = path.replace("full/","")
  17. image_path = os.path.join(category_path,image_name)
  18. return image_path

将pipeline1内的class类完成替换(后面还是要在settings内再把pipeline替换成我们的新的class:

  1. ITEM_PIPELINES = {
  2. # 'bmw.pipelines.BmwPipeline': 300,
  3. #'scrapy.pipelines.images.ImagesPipeline':1,
  4. 'bmw.pipelines.Bmw_pipeline':1,
  5. }

饱经沧桑的pipeline。。。这里的思路是将images函数里面的方法进行改写,继承,太难受了,pipeline下载的时候不同通道可以一起下载,也算一个小发现吧。其中最难理解的是:
request_obj.item = item
这里之前得到了request_objs,是一个装有request请求的列表,这里将item属性给其加了上去。item其实就是urls。执行了一个request.get()请求,将category内容传递了过来,item = BmwItem(``category``= category,``image_urls ``= urls)
把item进行了修改。
最后得到的是如下的情况:
image.png
啊啊啊啊,终于弄清楚了这个东西,累死了,改明用这个爬虫试着改下,爬取pixiv图片hh,这波先放个大大的插图做封面,ovo。帅帅帅!