说到代理,写过爬虫的小伙伴一定都不陌生。但是你的代理真的生效了么

代理主要分为以下几类:

如果是爬虫的话,最常见的选择是高匿代理。

Requests 设置代理非常方便,只需传递一个 proxies 参数即可。如官方示例:

import requestsproxies = {'http': 'http://10.10.1.10:3128','https': 'http://10.10.1.10:1080',
}requests.get('http://example.org', proxies=proxies)

留意一个地方,proxies 字典中有两个 key :https 和 http,为什么要写两个 key,如果只有一个可以么?

试试就知道了

准备验证函数

这个函数会使用代理去访问两个 IP 验证网站,一个是 https,一个是 http。

import requests
from bs4 import BeautifulSoupdef validate(proxies):https_url = 'https://ip.cn'http_url = 'http://ip111.cn/'headers = {'User-Agent': 'curl/7.29.0'}https_r = requests.get(https_url, headers=headers, proxies=proxies, timeout=10)http_r = requests.get(http_url, headers=headers, proxies=proxies, timeout=10)soup = BeautifulSoup(http_r.content, 'html.parser')result = soup.find(class_='card-body').get_text().strip().split('''\n''')[0]print(f"当前使用代理:{proxies.values()}")print(f"访问https网站使用代理:{https_r.json()}")print(f"访问http网站使用代理:{result}")

测试

  • Case 1

    proxies = {'http': '222.189.244.56:48304','https': '222.189.244.56:48304'
    }
    validate(proxies)
    

    输出

    当前使用代理:dict_values(['222.189.244.56:48304', '222.189.244.56:48304'])
    访问https网站使用代理:{'ip': '222.189.244.56', 'country': '江苏省扬州市', 'city': '电信'}
    访问http网站使用代理:222.189.244.56 China / Nanjing
    

    结果: 访问两个网站均使用了代理

  • Case 2

    proxies = {'http': '222.189.244.56:48304'
    }
    validate(proxies)
    

    输出

    当前使用代理:dict_values(['222.189.244.56:48304'])
    访问https网站使用代理:{'ip': '118.24.234.46', 'country': '重庆市', 'city': '腾讯'}
    访问http网站使用代理:222.189.244.56 China / Nanjing
    

    结果: 只有http请求使用了代理

  • Case 3

    proxies = {'https': '222.189.244.56:48304'
    }
    validate(proxies)
    

    输出

    当前使用代理:dict_values(['222.189.244.56:48304'])
    访问https网站使用代理:{'ip': '222.189.244.56', 'country': '江苏省扬州市', 'city': '电信'}
    访问http网站使用代理:118.24.234.46 China / Nanning
    

    结果: 只有https请求使用了代理

其他测试

通过 wireshark 抓包发现,当协议不匹配时,根本不会向代理服务器发起请求。

通过 postman 测试,结果与 Requests 一致,协议不同的情况下,不会走代理。

猜测可能是一种约定或者规则,类似 PAC ?(如果你知道答案,请告诉我)

寻找答案

从源码入手试试?在requests.ultis 中找到了这个函数:

def select_proxy(url, proxies):"""Select a proxy for the url, if applicable.:param url: The url being for the request:param proxies: A dictionary of schemes or schemes and hosts to proxy URLs"""proxies = proxies or {}urlparts = urlparse(url)if urlparts.hostname is None:return proxies.get(urlparts.scheme, proxies.get('all'))proxy_keys = [urlparts.scheme + '://' + urlparts.hostname,urlparts.scheme,'all://' + urlparts.hostname,'all',]proxy = Nonefor proxy_key in proxy_keys:if proxy_key in proxies:proxy = proxies[proxy_key]breakreturn proxy

答案揭晓了,Requests 会根据目标 url 的协议按照一定顺序来为它选择代理。 就拿上面的 Case 2 来说:

proxies = {'http': '222.189.244.56:48304'
}

请求http://ip111.cn/时,按照以下顺序在 proxies 字典中为这个链接选用代理:

  1. 协议+域名 :http://222.189.244.56
  2. 协议:http
  3. all + 域名:all://222.189.244.56
  4. all:all

在第 2 步匹配到222.189.244.56:48304,然后就使用这个代理去访问目标地址。

而在请求https://ip.cn时,按照上面顺序匹配不到任何内容,就使用本地的 ip 去访问目标地址了。

这样也就能说明上面 3 个例子了。

扩展

官方示例中的代理包含协议,而我们测试的例子中没有但同样能够成功访问。这又是为什么呢?

# 官方的
proxies = {'http': 'http://10.10.1.10:3128','https': 'http://10.10.1.10:1080',
}
# 我们的
proxies = {'http': '222.189.244.56:48304','https': '222.189.244.56:48304'
}

答案同样可以在源码里找到,请看下面这两个函数:

requests.apdpters

def get_connection(self, url, proxies=None):"""Returns a urllib3 connection for the given URL. This should not becalled from user code, and is only exposed for use when subclassing the:class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.:param url: The URL to connect to.:param proxies: (optional) A Requests-style dictionary of proxies used on this request.:rtype: urllib3.ConnectionPool"""proxy = select_proxy(url, proxies)if proxy:proxy = prepend_scheme_if_needed(proxy, 'http')proxy_url = parse_url(proxy)if not proxy_url.host:raise InvalidProxyURL("Please check proxy URL. It is malformed"" and could be missing the host.")proxy_manager = self.proxy_manager_for(proxy)conn = proxy_manager.connection_from_url(url)else:# Only scheme should be lower caseparsed = urlparse(url)url = parsed.geturl()conn = self.poolmanager.connection_from_url(url)return conn

看这一行代码:proxy = prepend_scheme_if_needed(proxy, 'http'),找到这个函数的定义:

def prepend_scheme_if_needed(url, new_scheme):"""Given a URL that may or may not have a scheme, prepend the given scheme.Does not replace a present scheme with the one provided as an argument.:rtype: str"""scheme, netloc, path, params, query, fragment = urlparse(url, new_scheme)# urlparse is a finicky beast, and sometimes decides that there isn't a# netloc present. Assume that it's being over-cautious, and switch netloc# and path if urlparse decided there was no netloc.if not netloc:netloc, path = path, netlocreturn urlunparse((scheme, netloc, path, params, query, fragment))

从注释中可以找到答案:

如果代理提供了协议,不做改变;如果代理没有协议的话,就为代理加上http协议。

结论

  1. Requests 会按照目标url的协议来为它配置代理。基于此你可以为不同的协议甚至不同域名设置不同的代理,如果想为所有请求使用同一个代理,那直接使用 all 作为 key 来设置即可。
  2. 代理地址如果没有指明协议,则默认使用 http 请求。

参考链接

  • HTTP 代理原理及实现(一)
  • HTTP 代理原理及实现(二)
  • 什么是透明、匿名、高匿代理?详解!
  • HTTP代理和HTTPS代理的区别

关于Requests代理,你应该知道的相关推荐

  1. SQL Server 2005:你应该知道的13件事情

    距离微软的SQL Server 2005正式版的推出,已经将近一年的时间.随着最近两份研究报告的出炉,SQL Server 2005又引起了业界的关注和评论--微软凭借SQL Server 2005取 ...

  2. C#开发人员应该知道的13件事情

    C#开发人员应该知道的13件事情 本文讲述了C#开发人员应该了解到的13件事情,希望对C#开发人员有所帮助. 1. 开发过程 开发过程是错误和缺陷开始的地方.使用工具可以帮助你在发布之后,解决掉一些问 ...

  3. 网络服务器最基本的是文件,你可能想知道的15个网络常用基础知识

    原标题:你可能想知道的15个网络常用基础知识 网络是一个复杂的系统,涉及知识很多.现在腾正小超人给大家分享15个常用的网络基础知识: 1) 如何查看本机所开端口 用netstat -a -n命令查看! ...

  4. C# Development 13 Things Every C# Developer Should Know--C#开发人员应该知道的13件事情

    原文链接:https://dzone.com/refcardz/csharp 本文讲述了C#开发人员应该了解到的13件事情,希望对C#开发人员有所帮助. 1. 开发过程 开发过程是错误和缺陷开始的地方 ...

  5. 程序员应该知道的10大编程格言

    作者 | BarryWang 来源 | https://www.cnblogs.com/barrywxx/p/4399007.html 每个程序员都该知道的10大编程格言(Kevin Pang): 编 ...

  6. 2019-11-29-git-需要知道的1000个问题

    title author date CreateTime categories git 需要知道的1000个问题 lindexi 2019-11-29 8:36:7 +0800 2018-2-13 1 ...

  7. iOS 开发者一定要知道的 14 个知识点

    本文讲的是iOS 开发者一定要知道的 14 个知识点, 作为一个 iOS 开发者(现在对 Swift 中毒颇深 ).我从零开始创建应用.维护应用,并且在很多团队待过.在我的职业生涯中,一句话一直响彻耳 ...

  8. 每个团队都应知道的API安全威胁

    原文发表于kubernetes中文社区,为作者原创翻译 ,原文地址 更多kubernetes文章,请多关注kubernetes中文社区 目录 每个团队都应知道的API安全威胁 分页和资源限制不安全 如 ...

  9. 你应该知道的25个非常有用的CSS技巧

    在我们的前端CSS编码当中,经常要设置特殊的字体效果,边框圆角等等,还要考虑兼容性的问题, CSS网页布局,说难,其实很简单.说它容易,往往有很多问题困扰着新手,在中介绍了非常多的技巧,这些小技巧与知 ...

  10. 关于机器学习,你应该知道的3个热门专业术语

    https://www.toutiao.com/a6683842829510246923/ 2019-04-25 22:43:48 关于机器学习,你应该知道的3个热门专业术语 原创: 吴郦军.罗人千 ...

最新文章

  1. OSPF中第一类外部路由和第二类外部路由的区别
  2. 【Java Web前端开发】web概念概述和HTML基础部分
  3. [bzoj2242][SDOI2011]计算器
  4. 考公专业科目计算机,2017国考中国证监会专业科目考试大纲(计算机类)
  5. php把语音转成帧,[转载]用TCP/IP实现自己简单的应用程序协议:成帧器部分
  6. 对github的初步认识以及对软件技术基础课程的期待
  7. Eclipse去除js(JavaScript)验证错误
  8. Thymeleaf 模板 js和css引入的方式
  9. 离线安装CDH5集群及相关软件
  10. UEFI模式下安装ubuntu以及重装ubuntu教程
  11. jpg图片太大怎么压缩?jpg图片怎么压缩大小?
  12. Atitit q2016 qa doc list on home ntpc.docx
  13. 微软Windows商店会变得更像Steam ,Xbox可自由安装PC游戏
  14. java RSA生成公钥对象和私钥对象
  15. canvas实现蜘蛛网动态背景特效
  16. 用uniapp搞了个小说阅读器
  17. ThinkPHP的车辆租赁管理系统
  18. 使用Hprose制作一个简单的分布式应用程序
  19. [转]深度分析中国移动、中国联通、中国电信的3G胜算
  20. 【eos系列】eos系统合约介绍 — 发币合约eosio.token

热门文章

  1. 嵌入式单片机基础篇(三十六)之STM32F1SPI标准接口程序以及模拟SPI标准接口程序讲解
  2. sklearn与其他算法集合使用步骤
  3. 2021年美容师(初级)找解析及美容师(初级)模拟考试题
  4. java atan atan2_Java Math atan2() 使用方法及示例
  5. 使用FastStone Capture进行长截图(滚动截图)
  6. 购买二手计算机信息询问英语作文,英语作文:学生是否应该买二手书
  7. Sleep()函数的理解、使用、意义
  8. java的jvm和事务并发的关系_Java程序员岗面试总结
  9. 人声合成效果器 – iZotope VocalSynth 2 v2.1.0 WiN-MAC
  10. 2019勒索病毒攻击盘点,企业该如何做好防范?