1、scrapy下载中间件
中间件中有两个类一个用于爬虫,一个用于下载,爬虫几乎用spider就能实现,重要的是下载中间件
1.1下载中间件的含义
下载中间件是scrapy提供用于用于在爬虫过程中可修改Request和Response,用于扩展scrapy的功能
1.2下载中间件的内容
主要用到request与response
1.2.1process_request(self, request, spider)
当每个request通过下载中间件时,该方法被调用,优先级越高的中间件,越先调用;该方法应该返回以下对象:None/Response对象/Request对象/抛出IgnoreRequest异常
None:scrapy会继续执行其他中间件相应的方法;
Response对象:scrapy不会再调用其他中间件的process_request方法,也不会去发起下载,而是直接返回该Response对象
Request对象:scrapy不会再调用其他中间件的process_request()方法,而是将其放置调度器待调度下载
如果这个方法抛出异常,则会调用process_exception方法
1.2.2process_response(self, request, response, spider)
当下载器完成http请求,传递Response经过下载中间件响应给引擎的时候调用,优先级越高的中间件,越晚被调用,与process_request()相反;该方法返回以下对象:Response对象/Request对象/抛出IgnoreRequest异常。
返回Response对象:scrapy会继续调用其他中间件的process_response方法;
返回Request对象:停止中间器调用,将其放置到调度器待调度下载;
抛出IgnoreRequest异常:Request.errback会被调用来处理函数,如果没有处理,它将会被忽略且不会写进日志。
2、设置随机请求头
请求头大全网址:所有的请求头点击查看
测试请求头网址:点击查看自己的请求头
测试请求头网址不仅可以测试ua还可以测试ip
2.1为什么要设置ua
2.1.1设置ua方式一
直接在setting当中设置
2.1.2通过下载中间件
自定义中间件,查看它当中内容
设置随机ua
在setting中定义一个ua列表,在下载中间件中通过random模块随机设置一个ua添加到request中,这样就完成了随机ua的添加
class RandomUseragent(object):
def process_request(self, request, spider):
ualist = spider.settings.get('USER_AGENTS')
# print(ualist)
user_agent = random.choice(ualist)
# print(user_agent)
request.headers['user-agent'] = user_agent
3、爬取汽车之家
3.1下载图片案例 爬取汽车之家图片
3.1.1spider代码
import scrapy
class AodiSpider(scrapy.Spider):
name = 'aodi'
allowed_domains = ['car.autohome.com.cn']
start_urls = ['https://car.autohome.com.cn/photolist/series/43102/5304105.html#pvareaid=3454450']
def parse(self, response):
ul = response.xpath('//ul[@id="imgList"]/li')
item = {}
for li in ul:
src = li.xpath('./a/img/@src').extract_first()
# print(item)
url = 'https:'+ src
item['url'] = url
yield item
3.1.2pipeline代码
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
from urllib import request
import os
class PicPipeline:
def process_item(self, item, spider):
name = 'images/' + item['url'].split('__')[-1]
# D:\studyPC\text3\pic\images
# __file__:具体到文件的位置,包含文件名
# os.path.dirname(__file__):返回当前文件的上级目录路径,相当于cd ..,不包含文件名
file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)),name)
request.urlretrieve(item['url'],file_path)
return item
4、选择使用scrapy内置的下载文件的方法
优点:
1:避免重新下载最近已经下载过的数据
2:可以方便的指定文件存储的路径
3:可以将下载的图片转换成通用的格式。如:png,jpg
4:可以方便的生成缩略图
5:可以方便的检测图片的宽和高,确保他们满足最小限制
6:异步下载,效率非常高
4.1下载文件的步骤Files Pipeline
①:定义好一个Item,然后在这个item中定义两个属性,分别为file_urls以及files。files_urls是用来存储需要下载的文件的url链接,需要给一个列表
②:当文件下载完成后,会把文件下载的相关信息存储到item的files属性中。如下载路径、下载的url和文件校验码等
③:在配置文件settings.py中配置FILES_STORE,这个配置用来设置文件下载路径
④:启动pipeline:在ITEM_PIPELINES中设置scrapy.piplines.files.FilesPipeline:1
4.2下载图片的步骤Images Pipeline
①:定义好一个Item,然后在这个item中定义两个属性,分别为image_urls以及images下载路径。image_urls是用来存储需要下载的文件的url链接,需要给一个列表
②:当文件下载完成后,会把文件下载的相关信息存储到item的images属性中。如下载路径、下载的url和图片校验码等
③:在配置文件settings.py中配置IMAGES_STORE,这个配置用来设置文件下载路径
④:启动pipeline:在ITEM_PIPELINES中设置scrapy.pipelines.images.ImagesPipeline:1
5、用内置方法爬取汽车图片
优点:快速爬取,代码量少,命名等全不用自己管就可以实现快速爬取图片
spider代码
import scrapy
from neizhi.items import NeizhiItem
class AdSpider(scrapy.Spider):
name = 'ad'
allowed_domains = ['car.autohome.com.cn']
start_urls = ['https://car.autohome.com.cn/photolist/series/43102/5304105.html#pvareaid=3454450']
def parse(self, response):
item = NeizhiItem()
ul = response.xpath('//ul[@id="imgList"]/li')
for li in ul:
src = li.xpath('./a/img/@src').extract_first()
# print(item)
url = ['https:' + src]
item['image_urls'] = url
yield item
setting中的代码,打开内置管道,设置保存路径
import os
IMAGES_STORE = os.path.join(os.path.dirname(os.path.dirname(__file__)),'images')
ITEM_PIPELINES = {
'neizhi.pipelines.NeizhiPipeline': 300,
'scrapy.pipelines.images.ImagesPipeline':1
}
6、爬取苏宁图书
6.1找到爬取目标
6.2分析页面结构
发现网页源代码中有所需要的数据直接请求就ok
6.3创建scrapy框架普通爬虫
scrapy startproject book
cd book
scrapy genspider snbook book.suning.com
6.4写爬虫逻辑,在pipeline中保存
import scrapy
from copy import deepcopy
# import re
class SnbookSpider(scrapy.Spider):
name = 'snbook'
allowed_domains = ['suning.com']
start_urls = ['https://book.suning.com/']
def parse(self, response):
dl_list = response.xpath('//div[@class="menu-list"]/div/dl')
# print(dl_list)
item = {}
for dl in dl_list:
item['b_cate'] = dl.xpath('./dt/h3/a/text()').extract_first()
dd_list = dl.xpath('./dd/a')
for dd in dd_list:
item['s_href'] = dd.xpath('./@href').extract_first()
item['s_cate'] = dd.xpath('./text()').extract_first()
# print(item)
yield scrapy.Request(
url=item['s_href'],
callback=self.parse_book_list,
meta={'item': deepcopy(item)}
)
def parse_book_list(self, response):
item = response.meta.get('item')
li_list = response.xpath('//ul[@class="clearfix"]/li')
for li in li_list:
item['book_name'] = li.xpath('//div[@class="res-img"]/div/a/img/@alt').extract_first()
item['book_image'] = 'https:' + li.xpath('//div[@class="res-img"]/div/a/img/@src2').extract_first()
item['book_href'] = 'https:' + li.xpath('//div[@class="res-img"]/div/a/@href').extract_first()
yield scrapy.Request(
url=item['book_href'],
callback=self.parse_book_detail,
meta={'item': deepcopy(item)}
)
def parse_book_detail(self, response):
item = response.meta.get('item')
# ul = response.xpath('//ul[@class="bk-publish clearfix"]/li')
# for ul in ul
item['book_author'] = response.xpath('//ul[@class="bk-publish clearfix"]/li[1]/text()').extract_first()
item['book_press'] = response.xpath('//ul[@class="bk-publish clearfix"]/li[2]/text()').extract_first()
item['book_author'] = item['book_author'].replace('\n','').replace('\t','').replace('\t','').strip()
item['book_press'] = item['book_press'].replace('\n','').replace('\t','').replace('\t','').strip()
yield item