【Scrapy学习心得】爬虫实战三(异步下载宝马5系高清图片)
声明:仅供技术交流,请勿用于非法用途,如有其它非法用途造成损失,和本博客无关
爬取的网站:汽车之家的宝马5系所有高清图片 点击跳转
一、配置环境
python3.7
pycharm
Scrapy1.7.3
win10
pymysql
二、准备工作
- 在
cmd
命令行中进入需要创建项目的目录运行scrapy startproject hehe
- 创建成功后继续执行
cd hehe
- 然后执行
scrapy genspider bmw car.autohome.com.cn
- 最后在spider文件夹下可以看到刚创建的
bmw.py
爬虫文件
三、分析网页
不难发现,宝马5系的那些车身外观啊、中控方向盘啊等等分类都在这个uibox
的div
标签中,除了全景看车那个,我这都把各个分类中每张图片对应的高清url
地址都要拿到,我先把每个分类的url
地址给拿到,
然后再通过翻页拿到全部图片的高清图片地址,就可以轻松拿到所有宝马5系的高清图片了,完美!
先放上爬取的部分高清图片
所以总共我要爬取的内容有:
- 分类的名称以及其具体的
url
地址 - 所有高清图片
查找元素的那些操作我就不放上来了,因为没什么难度的,会来学scrapy
框架的同学肯定是跟我一样那些什么requests
啊,urllib
啊,selenium
啊等等都是用腻了才来的,是吧
四、爬取数据
下面先定义item.py
文件:
import scrapy
class HeheItem(scrapy.Item):
title = scrapy.Field() #分类名称
url = scrapy.Field() #分类的具体地址
gq_url = scrapy.Field() #高清图片的地址
image_urls = scrapy.Field() #真正要去请求的获取高清图片的地址
下面直接放上bmw.py
的代码:
# -*- coding: utf-8 -*-
import scrapy
from copy import deepcopy
from hehe.items import HeheItem
class BmwSpider(scrapy.Spider):
name = 'bmw'
allowed_domains = ['car.autohome.com.cn']
start_urls = ['https://car.autohome.com.cn/pic/series/65.html#pvareaid=3454438']
def parse(self, response):
uibox_list=response.xpath('//div[@class="uibox"]')[1:] #去掉全景观车
for uibox in uibox_list:
item=HeheItem()
item['title']=uibox.xpath('./div[@class="uibox-title"]/a/text()').get()
item['url'] = uibox.xpath('./div[@class="uibox-title"]/a/@href').get()
item['url']=response.urljoin(item['url'])
#下面去请求进入到分类的地址当中
yield scrapy.Request(
item['url'],
callback=self.parse_list,
meta={'item':deepcopy(item)}
)
def parse_list(self,response):
item=response.meta['item']
li_list=response.xpath('//div[@class="uibox-con carpic-list03 border-b-solid"]/ul/li')
for li in li_list:
item['gq_url']=response.urljoin(li.xpath('./a/@href').get())
#下面去请求进入高清图片的地址当中
yield scrapy.Request(
item['gq_url'],
callback=self.parse_gq,
meta={'item':deepcopy(item)}
)
#下面进行翻页的操作
next_page=response.xpath('//a[@class="page-item-next"]/@href').get()
if next_page != 'javascript:void(0);': #当有下一页的时候才去翻页
next_page=response.urljoin(next_page)
yield scrapy.Request(
next_page,
callback=self.parse_list, #翻页操作时的callback函数是自己
meta={'item':item}
)
def parse_gq(self,response):
item=response.meta['item']
item['image_urls']=response.xpath('//img[@id="img"]/@src').getall()
item['image_urls']=[response.urljoin(item['image_urls'][0])] #需要把它改成一个列表,不然后面用urlretrieve会报错
yield item
五、保存数据(同步下载图片)
这里先用传统的保存图片的方法来保存,修改pipeline.py
文件如下:
# -*- coding: utf-8 -*-
import os
from urllib.request import urlretrieve #用来下载图片
class HehePipeline(object):
def __init__(self): #下面是创建保存图片的文件夹images
self.path=os.path.join(os.path.dirname(os.path.dirname(__file__)),'images')
if not os.path.exists(self.path):
os.mkdir(self.path)
def process_item(self, item, spider):
if spider.name == 'bmw':
cate=item['title']
url=item['image_urls']
cate_path=os.path.join(self.path,cate)
#按分类来保存图片
if not os.path.exists(cate_path):
os.mkdir(cate_path)
name=url.split('__')[-1] #取url后面部分来作为图片的名称
urlretrieve(url, os.path.join(cate_path, name))
现在我们的爬虫大致已经是写完了,不过我还要修改一下setting.py
文件的一些设置,需要增加的语句有:
LOG_LEVEL='WARNING' #设置日志输出级别
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36' #设置请求头
ROBOTSTXT_OBEY = False #把这个设置成False,就不会去请求网页的robots.txt,因为不改为False的话,scrapy就会去访问该网站的robots.txt协议,如果网站没有这个协议,那么它就不会去访问该网站,就会跳过,进而爬不到数据
ITEM_PIPELINES = {
'hehe.pipelines.HehePipeline': 300,
}
最后在cmd
中先进入到这个项目的根目录下,即有scrapy.cfg
文件的目录下,然后输入并运行scrapy crawl bmw
,最后静静等待就行了,不过下载的速度的确是有点慢
六、保存数据(异步下载图片)
然后这里采用scrapy
内置的pipeline
来进行保存图片,用这个来保存图片呢有下面几个好处:
scrapy
本身就有url
去重的功能,所以就不会出现重复下载同一张图片的情况- 它采用的是异步下载,下载速度大大提高
- 而且它还会自动把图片保存为合适的格式
- 等等等等
下面在pipeline.py
文件中添加一个类,代码如下:
# -*- coding: utf-8 -*-
import os
from scrapy.pipelines.images import ImagesPipeline #使用scrapy自带的pipeline
from hehe import settings #导入配置文件
#只需重新复写以下两个方法就行
class HahaPipeline(ImagesPipeline):
def get_media_requests(self, item, info):
request_objs=super(HahaPipeline,self).get_media_requests(item,info)
for request_obj in request_objs:
request_obj.item=item
return request_objs
def file_path(self, request, response=None, info=None):
#这个方法是图片将要被存储的时候调用,来获取图片的存储路径
path=super(HahaPipeline,self).file_path(request,response,info)
cate=request.item.get('title')
images_store=settings.IMAGES_STORE #获取配置文件当中的文件路径,如果不存在,会自动创建
cate_path=os.path.join(images_store,cate)
if not os.path.exists(cate_path):
os.mkdir(cate_path)
name=path.replace('full/','') #去掉scrapy中这个pipeline自己定义的文件夹路径,这里你们可以去看看源码就知道了
images_path=os.path.join(cate_path,name) #重新定义文件夹路径
return images_path #返回自定义的图片存放路径
同样需要在setting.py
文件中设置修改pipeline
才能把这个新的pipeline
给生效,如下添加一行并把之前的给注释掉,并且增加保存文件的路径一行:
import os
IMAGES_STORE=os.path.join(os.path.dirname(os.path.dirname(__file__)),'images')
ITEM_PIPELINES = {
# 'hehe.pipelines.HehePipeline': 300,
'hehe.pipelines.HahaPipeline': 300,
}
把之前下载的图片删除,重新运行一遍这个爬虫,会发现速度明显比之前要快得多,这就是异步下载的威力啊哈哈
写在最后
怎么说呢,当你试过这两种下载图片的方法之后,你会恍然大悟,会喜欢上scrapy
框架,但是,其实那些异步下载啊、多线程啊什么的,如果有能力自己敲代码也是能够实现的,但是,我又觉得,既然scrapy
已经帮你弄好了一整套可用的东西,你非要去自己编写,那不就是重复造轮子么,除非你想发展为爬虫架构师的那种级别,一般我们还是用别人的东西,学会用别人的东西就已经很不错了我觉得。而且我又觉得,当我们使用的多了之后,估计自然而然地也就清楚地知道那些框架是怎么回事了吧