5.3-python爬虫之下载文件图片及中间件

系列文章目录

python爬虫目录



前言

摘录自B站对应课程笔记
不愧是清华大佬!把Python网络爬虫讲得如此简单明了!从入门到精通保姆级教程(建议收藏)

以下是本篇文章正文内容,下面案例可供参考


一、下载文件和图片

Scrapy 为下载 item 中包含的文件(比如在爬取到产品时,同时也想保存对应的图片)提供了一个可重用的 item pipelines。这写 pipeline 有些共同的地方和结构(我们称之为 media pipeline)。一般来说你会使用 Files Pipelines 或是 Images Pipelines

1、为什么要选择使用 scrapy 内置的下载文件的方法

1、避免重新下载最近已经下载过的文件。
2、可以方便的指定文件存储的路径。
3、可以将下载的图片转换成通用的格式。比如 png, jpg
4、可以方便的生成缩略图
5、可以方便的检测图片的宽和高,确保他们满足最小的限制。
6、异步下载,效率非常高。

2、下载文件的 Files Pipelines

当使用 Files Pipeliens 下载文件的时候,按照以下步骤来完成:
1、定义好一个 Item, 然后在这个 item 中定义两个属性,分别为 file_urls 以及 files, file_urls 是用来存储需要下载的图片的 url 链接,需要给一个列表。
2、当文件下载完成后,会把文件下载的相关信息存储到 item 的 files 属性中。比如下载路径, 下载的url和文件的校验码等。
3、在配置文件 setting.py 中配置 FILES_STORE ,这个配置是用来设置文件下载下来的路径。
4、启动 pipeline: 在文件 setting.py 中的 ITEM_PIPELINES 设置 scrapy.pipeline.files.FilesPipeline:1

3、下载图片的 Images Pipeline:

当使用 Images Pipeline 下载文件的时候,按照以下步骤来完成:
1、定义好一个 Item, 然后在这个 item 中定义两个属性,分别为 image_urls 以及 images 。image_urls 是用来存储需要下载的图片的url链接,需要给一个列表。
2、当文件下载完成后,会把文件下载的相关信息存储到 item 的 images 属性中。比如下载路径、下载的 url 和图片的校验等。
3、在配置文件 setting.py 中配置 IMAGES_STORE, 这个配置是用来设置图片下载下来的路径。
4、启动 pipeline : 在文件 setting.py 中的 ITEM_PIPELINES 设置 scrapy.pipeline.images.ImagesPipeline:1

4、汽车之家 CRV 图片下载实战

通过重写 ImagesPipeline 下载 CRV 这个款车的各类图片,代码如下:
setting.py

import os
 
BOT_NAME = 'crv'
 
SPIDER_MODULES = ['crv.spiders']
NEWSPIDER_MODULE = 'crv.spiders'
 
ROBOTSTXT_OBEY = False
 
DOWNLOAD_DELAY = 1
 
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36',
}
 
ITEM_PIPELINES = {
    'crv.pipelines.CrvImagesPipeline': 1,
}
 
IMAGES_STORE = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "images")

items.py

import scrapy
 
class CrvItem(scrapy.Item):
    title = scrapy.Field()
    image_urls = scrapy.Field()
    images = scrapy.Field()

pipelines.py

import os
from crv import settings
from urllib import request
from scrapy.pipelines.images import ImagesPipeline
 
 
class CrvImagesPipeline(ImagesPipeline):
 
    def file_path(self, request, response=None, info=None, *, item=None):
        # 这个方法是在图片将要被存储的时候调用,来获取这个图片的存储路径。
        category = item["title"]
        category_path = os.path.join(settings.IMAGES_STORE, category)
        image_name = request.url.split("_")[-1]
        image_path = os.path.join(category_path, image_name)
        print("image_path ; {}".format(image_path))
        return image_path

crv_spider.py

import scrapy
from crv.items import CrvItem
 
class CrvSpiderSpider(scrapy.Spider):
    name = 'crv_spider'
    allowed_domains = ['car.autohome.com.cn']
    start_urls = ['https://car.autohome.com.cn/pic/series-s46246/314.html#pvareaid=3454542']
 
    def parse(self, response):
        divs = response.xpath("//div[@class='column grid-16']/div")[2:]  # 过滤掉1,2 行
        for div in divs:
            print(div.xpath(".//div[@class='uibox-title']"))
            title = div.xpath(".//div[@class='uibox-title']/a/text()").get()
            urls = div.xpath(".//ul/li/a/img/@src").getall()
            urls = list(map(response.urljoin, urls))
            item = CrvItem(title=title, image_urls=urls)
            print(item)
            yield item

二、下载中间件

下载器中间件是引擎和下载器之间通信的中间件。在这个中间件中我们可以设置代理、更换请求头等来达到反反爬虫的目的。要写下载器中间件,可以在下载器中实现两个方法。一个是 process_request(self, request, spider), 这个方法是在请求发送之前会执行,还有一个是 process_response(self, request, response, spider), 这个方法是数据下载到引擎之前执行。

1、process_request(self, request, spider)

这个方法是下载器在发送请求之前会执行的。一般可以在这个方法里面设置随机代理ip等
1、参数:
request:发送请求的 request对象
spider:发送请求的 spider对象

2、返回值:
返回Node :如果返回None,Scrapy 将继续处理该 request, 执行其他中间件中的相应方法,直到合适的下载器处理函数被调用。
返回Response对象 :Scrapy 将不会调用任何其他的 process_request 方法,将直接返回这个 response对象。已经激活的中间件的 process_response()方法则会在每个 response返回时被调用。
返回 Request对象 :不再使用之前的 request 对象去下载数据,而是根据现在返回的 request 对象返回数据。
如果这个方法中抛出了异常,则会调用 process_exception 方法。

在这里插入图片描述

2、process_response(self, request, response, spider)

这个是下载器下载的数据到引擎中间会执行的方法。
1、参数:
request : request对象
response :被处理的 response对象
spider : spider对象

2、返回值:
返回Response对象: 会将这个新的 response 对象传给其他中间件,最终传给爬虫。
返回Request对象:下载器链接被切断,返回的 request 会重新被下载器调度下载。
如果抛出一个异常,那么调用 request 的 errback 方法,如果没有指定这个方法,那么会抛出一个异常

3、随机请求头中间件

爬虫在频繁访问一个页面的时候,这个请求头如果一直保持一致,那么很容易被服务器发现,从而禁止这个请求头的访问。因此我们要在访问这个页面之前随机的更改请求头吗,这样才可以避免爬虫被抓。
随机更改请求头,可以在下载中间件中实现。在请求发送给服务器之前,,随机的选择一个请求头。这样就可以避免总使用一个请求头了。示例代码如下:
setting.py

#打开中间件
DOWNLOADER_MIDDLEWARES = {
   'useragent.middlewares.UseragentDownloaderMiddleware': 543,
}

middlewares.py

#随机选择请求头
class UseragentDownloaderMiddleware:
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the downloader middleware does not modify the
    # passed objects.
 
    USER_AGENT = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36",
        "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER",
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0",
        "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko",
    ]
 
    def process_request(self, request, spider):
        # Called for each request that goes through the downloader
        # middleware.
 
        # Must either:
        # - return None: continue processing this request
        # - or return a Response object
        # - or return a Request object
        # - or raise IgnoreRequest: process_exception() methods of
        #   installed downloader middleware will be called
 
        user_agent = random.choice(self.USER_AGENT)
        request.headers["User-Agent"] = user_agent
        return None

httpbin.py

#拿到结果并打印
import scrapy
 
class HttpbinSpider(scrapy.Spider):
    name = 'httpbin'
    allowed_domains = ['httpbin.org']
    start_urls = ['http://httpbin.org/user-agent']
 
    def parse(self, response):
        ua = response.json()
        print("*" * 30)
        print(ua)
        print("*" * 30)
        return scrapy.Request(self.start_urls[0], dont_filter=True)

4、ip代理池中间件

1、购买代理

  1. 芝麻代理 https://zhimahttp.com/
  2. 太阳代理 http://http.taiyangruanjian.com/
  3. 快代理 https://www.kuaidaili.com/
  4. 讯代理 https://jahttp.zhimaruanjian.com/

2、使用ip代理池

**setting.py **

#打开中间件
ITEM_PIPELINES = {
   'useragent.pipelines.UseragentPipeline': 300,
}

middlewares.py

#随机选择请求头
class IpPorxyDownloaderMiddleware(object):
 
    IPPROXY = [
        "http://101.18.121.42:9999",
        "http://175.44.108.56:9999",
        "http://218.88.205.161:3256",
        "http://114.99.9.251:1133",
    ]
 
    def process_request(self, request, spider):
        proxy = random.choice(self.IPPROXY)
        request.meta['proxy'] = proxy

ipproxy.py

#拿到结果并打印
import scrapy
 
class IpproxySpider(scrapy.Spider):
    name = 'ipproxy'
    allowed_domains = ['httpbin.org']
    start_urls = ['http://httpbin.org/ip']
 
    def parse(self, response):
        ua = response.json()
        print("*" * 30)
        print(ua)
        print("*" * 30)
        return scrapy.Request(self.start_urls[0], dont_filter=True)
# 使用的是免费代理,不是很稳定,没能获取到结果

3、独享代理池

使用快代理的测试

class IPProxyDownloadMiddleware(object):
    def process_request(self, request,spider):
        proxy = '111.111.222.222:8080'
        user_password = "123123123:kod231"
        request.meta["proxy"] = proxy
        #bytes
        b64_user_password = base64.b64encode(user_password.encode('utf-8'))
        request.headers["Proxy-Authorization"] = "Basic" + b64_user_password.decode('utf-8')

下载中间件实战案例

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nosimper

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值