1.Requests
模块的使用
requests
模块的介绍与安装
作用:发送网络请求,返回响应数据。
中文文档:https://requests.readthedocs.io/projects/cn/zh_CN/latest/
对于爬虫任务,使用requests
模块基本能够解决绝大部分的数据抓取的任务。所以用好requests
至关重要
模块安装
安装命令:
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple
requests
功能特性
Keep-Alive
& 连接池- 国际化域名和
URL
- 带持久
Cookie
的会话 - 浏览器式的
SSL
认证 - 自动内容解码
- 基本/摘要式的身份认证
- 优雅的
key/value Cookie
- 自动解压
Unicode
响应体HTTP(S)
代理支持- 文件分块上传
- 流下载
- 连接超时
- 分块请求
- 支持
.netrc
requests
发送网络请求以及常用的响应属性
需求:通过requests
向百度首页发送请求,获取百度首页数据
import requests
url = "https://www.baidu.com"
response = requests.get(url=url)
print("---状态码如下---")
print(response.status_code)
print("---bytes类型数据:---")
print(response.content)
print("---str类型数据---")
print(response.text)
print("---str类型数据(utf-8)---")
print(response.content.decode("utf-8"))
常用属性如下:
response.text
响应体str
类型respones.content
响应体bytes
类型response.status_code
响应状态码response.request.headers
响应对应的请求头response.headers
响应头response.request.headers.get('cookies')
响应对应请求的cookie
response.cookies
响应的cookie
(经过了set-cookie
动作)response.url
请求的URL
text
与content
方法区别
response.text
- 类型:
str
- 解码类型:
requests
模块根据HTTP
头部对响应的编码推测文本编码类型 - 修改编码方式:
response.encoding = 'gbk'
- 类型:
response.content
- 类型:
bytes
- 解码类型:没有指定
- 修改编码方式:
response.content.decode('utf-8')
- 类型:
获取网页源码的通用方式:
response.encoding = 'utf-8'
response.content.decode('utf-8')
response.text
以上三种方式从前往后依次尝试,百分百可以解决网页编码问题。
import requests
r = requests.get("https://www.baidu.com")
print("-----requests一般能够根据响应自动解码-----")
print(r.text)
print("-----如果不能够解析出想要的真实数据,可以通过设置解码方式-----")
r.encoding = "utf-8"
print(r.text)
下载网络图片
需求:将百度logo
下载到本地
思路分析:
logo
的url
地址:https://www.baidu.com/img/bd_logo1.png- 利用
requests
模块发送请求并获取响应 - 使用二进制写入的方式打开文件并将
response
响应内容写入文件内
import requests
# 图片的url
url = 'https://ywww.baidu.com/img/bd_logo1.png'
# 响应本身就是一个图片,并且是二进制类型
r = requests.get(url)
# print(r.content)
# 以二进制+写入的方式打开文件
with open('baidu.png', 'wb') as f:
# r.content bytes二进制类型
f.write(r.content)
iter_content
方法
如果下载一个较大的资源,例如一个视频,可能需要的下载时间较长,在这个较长的下载过程中程序是不能做别的事情的(当然可以使用多任务来解决),如果在不是多任务的情况下,想要知道下载的进度,此时就可以通过类似迭代的方式下载部分资源。
- 使用
iter_content
在获取数据时,设置属性stream=True
r = requests.get('https://www.baidu.com', stream=True)
with open('test.html', 'wb') as f:
for chunk in r.iter_content(chunk_size=100):
f.write(chunk)
stream=True
说明
- 如果设置了
stream=True
,那么在调用iter_content
方法时才会真正下载内容 - 如果没设置
stream
属性则调用requests.get
就会耗费时间下载
- 显示视频下载进度
import requests
# 视频URL
video_url = "https://v95-bj.douyinvod.com/74d5493171db92a4046a588dde55a9c9/651fbbe5/video/tos/cn/tos-cn-ve-15c001-alinc2/o4NBwAtAz6knVLKFgeq9ZpbDAuAeECDkgQUIsc/?a=1128&ch=0&cr=0&dr=0&er=0&cd=0%7C0%7C0%7C0&cv=1&br=2296&bt=2296&cs=0&ds=4&ft=blh3-IQQqU-mfJ4ZPo0OW_EklpPiX9f22FVJEad.trbPD-I&mime_type=video_mp4&qs=0&rc=NzYzPDY8ZGlkO2U3NWhoZ0BpM3E8dzg6ZnR0bTMzNGkzM0BeNTU0XmNfNTIxX2MtXi4tYSMyYGovcjRfLi5gLS1kLWFzcw%3D%3D&btag=e000a8000&dy_q=1696574824&l=20231006144704E736E605E5E7C30F951B"
# 发送请求
r = requests.get(url=video_url, stream=True)
response_body_length = int(r.headers.get("Content-Length"))
# print("body的数据长度为:", response_body_length)
# 获取响应内容存储到文件
with open("抖音.mp4", 'wb') as fd:
write_length = 0
for chunk in r.iter_content(chunk_size=100):
write_length += fd.write(chunk) # write的返回值为写入到文件内容的多少
print("下载进度: %02.2f%%" % (100 * write_length / response_body_length))
发送请求时需要携带请求头
在请求某些网址时根据不同的浏览器会返回不同的响应内容,所以此时就需要根据需求来修改或添加请求头信息
获取请求头与响应头
import requests
r = requests.get("https://www.baidu.com")
print(r.headers) # 响应头
print(r.request.headers) # 请求头
添加
User-Agent
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
requests.get(url, headers=headers)
携带
User-Agent
请求百度
import requests
url = 'https://www.baidu.com'
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
}
# 在请求头中带上User-Agent,模拟浏览器发送请求
# r = requests.get(url)
r = requests.get(url, headers=headers)
# 打印请求头信息
print(r.request.headers)
# 响应内容
print(r.text)
发送带有URL
参数的请求
我们在使用百度搜索的时候经常发现url
地址中会有一个 ?
,那么该问号后边的就是请求参数,又叫做查询字符串。如果想要做到自动搜索,就应该让发送出去的url
携带参数。
示例地址:https://www.baidu.com/s?wd=python
# 1. 设置需要携带的查询字符串参数
kw = {'wd': 'java'}
# 2. 发送请求
response = requests.get('https://www.baidu.com/s', params=kw)
# 3.查看发送的URL
print(response.url)
当前查询字符串参数可以直接写到url
地址中:
import requests
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
url = 'https://www.baidu.com/s?wd=python'
# url中包含了请求参数,所以此时无需params
response = requests.get(url, headers=headers)
print("请求的URL:", response.url)
print("响应内容如下:", response.content)
使用requests
发送post
请求
在HTTP
请求中,GET
和POST
是使用最为频繁的请求方式。
GET
:获取数据POST
:提交数据
发送
post
请求
requests
模块中能发送多种请求,例如:GET
、POST
、PUT
、DELETE
等等
发送post
请求代码示例:
# 网站首页:http://www.cninfo.com.cn/new/commonUrl?url=disclosure/list/notice#szse
# api地址:http://www.cninfo.com.cn/new/disclosure
import requests
# 获取到url
url = 'http://www.cninfo.com.cn/new/disclosure'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
}
data = {
'column':'szse_latest',
'pageNum':'2',
'pageSize':'30',
'sortName':'',
'sortType':'',
'clusterFlag':'true',
}
response = requests.post(url, headers=headers, data=data)
print(response.json())
过程分析:
- 通过浏览器开发者工具获取当前网站数据
API
- 查询载荷选项卡中的表单数据
- 构建表单数据
- 发送
post
请求
代码练习:百度翻译
import requests
# 当前请求的地址为移动端地址
url = 'https://fanyi.baidu.com/basetrans'
headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 "
"(KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",
"Cookie": 'BIDUPSID=07953C6101318E05197E77AFF3A49007; PSTM=1695298085; '
'ZFY=jAXoBNlaBGlHggda:BLlW8x7pEMyEhiZUIRbuQnnavss:C; '
'APPGUIDE_10_6_5=1; REALTIME_TRANS_SWITCH=1; '
'FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; '
'SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; '
'BAIDUID=37927E8274D89B902DEB6F1A024B3860:FG=1; '
'BAIDUID_BFESS=37927E8274D89B902DEB6F1A024B3860:FG=1; '
'RT="z=1&dm=baidu.com&si=ba30f04e-d552-4a5a-864f-1b2b222ff176&ss=lne882ji&sl=2&tt=1'
'ju&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=3pn&nu='
'1dzl78ujc&cl=3bd&ul=61c&hd=622"; BA_HECTOR=a12g8ka22421al2k80ak21a31ihvc081o; '
'BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; '
'Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1695476554,1696577209; '
'Hm_lvt_afd111fa62852d1f37001d1f980b6800=1695476565,1696577271; '
'Hm_lpvt_afd111fa62852d1f37001d1f980b6800=1696577271; Hm_lpvt_64e'
'cd82404c51e03dc91cb9e8c025574=1696577271; ab_sr=1.0.1_MjZiYjAyZTQ4OTZkNWU0Y2M'
'5YjQxMzZiOTE4Y2ZkOWNmMmI2MTNiMzhlOWQ0MTE4MzU0NDg5Njc5ZWU1ZDVkN2E4ZmM2Zjg3NjA5N2IwYWQ3OG'
'I3ZDBlYWJlMmFmODM3Y2FhZmJkYzgxY2EzZmI1NWRiZDgxNWMxOTU3ZjNhZTk3NzE0ZDg1OGY1MGM4YTM2ZjA1'
'ZTY4MGViOTI2OTlhYQ=='
}
post_data = {
'query': 'happy',
'from': 'en',
'to': 'zh',
'token': '5ff0092d623c21bdb9b429187512af44',
'sign': '221212.492333'
}
response = requests.post(url, headers=headers, data=post_data).json()
print(response['trans'][0]['dst'])
注意:当前示例中的cookie
参数与表单参数需要自行获取。
requests
处理cookie
引入
为了能够通过爬虫获取到登录后的页面,或者是解决通过cookie
的反爬,需要使用request
来处理cookie
相关的请求。
爬虫中使用
cookie
的利弊
- 带上
cookie
的好处- 能够访问登录后的页面
- 能够实现部分反反爬
- 带上
cookie
的坏处- 一套
cookie
往往对应的是一个用户的信息,请求太频繁有更大的可能性被对方识别为爬虫 - 那么上面的问题如何解决?使用多个账号
- 一套
发送请求时添加
cookie
cookie
字符串放在headers
中
# 将cookie添加到headers中
headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 "
"(KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",
"Cookie": 'BIDUPSID=07953C6101318E05197E77AFF3A49007; PSTM=1695298085; '
'ZFY=jAXoBNlaBGlHggda:BLlW8x7pEMyEhiZUIRbuQnnavss:C; '
'APPGUIDE_10_6_5=1; REALTIME_TRANS_SWITCH=1; '
'FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; '
'SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; '
'BAIDUID=37927E8274D89B902DEB6F1A024B3860:FG=1; '
'BAIDUID_BFESS=37927E8274D89B902DEB6F1A024B3860:FG=1; '
'RT="z=1&dm=baidu.com&si=ba30f04e-d552-4a5a-864f-1b2b222ff176&ss=lne882ji&sl=2&tt=1'
'ju&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=3pn&nu='
'1dzl78ujc&cl=3bd&ul=61c&hd=622"; BA_HECTOR=a12g8ka22421al2k80ak21a31ihvc081o; '
'BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; '
'Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1695476554,1696577209; '
'Hm_lvt_afd111fa62852d1f37001d1f980b6800=1695476565,1696577271; '
'Hm_lpvt_afd111fa62852d1f37001d1f980b6800=1696577271; Hm_lpvt_64e'
'cd82404c51e03dc91cb9e8c025574=1696577271; ab_sr=1.0.1_MjZiYjAyZTQ4OTZkNWU0Y2M'
'5YjQxMzZiOTE4Y2ZkOWNmMmI2MTNiMzhlOWQ0MTE4MzU0NDg5Njc5ZWU1ZDVkN2E4ZmM2Zjg3NjA5N2IwYWQ3OG'
'I3ZDBlYWJlMmFmODM3Y2FhZmJkYzgxY2EzZmI1NWRiZDgxNWMxOTU3ZjNhZTk3NzE0ZDg1OGY1MGM4YTM2ZjA1'
'ZTY4MGViOTI2OTlhYQ=='
}
headers
中的cookie
格式:
- 使用分号
;
隔开 - 分号两边的类似
a=b
形式的表示一条cookie
a=b
中,a
表示键name
,b
表示值value
- 在
headers
中仅仅使用了cookie
的name
和value
- 把
cookie
字典传给请求方法的cookies
参数接收
cookie_dict = {"cookie的name": "cookie的value"}
requests.get(url, headers=headers, cookies=cookie_dict)
- 使用
requests
提供的session
模块(后面讲解)
获取响应时提取
cookie
使用requests
获取的resposne
对象,具有cookies
属性,能够获取对方服务器设置在本地的cookie
,但是如何使用这些cookie
呢?
使用requests
模块提供的response.cookies
方法。
response.cookies
是CookieJar
类型- 使用
requests.utils.dict_from_cookiejar
,能够实现把cookiejar
对象转化为字典
import requests
url = "https://www.baidu.com"
# 发送请求,获取resposne
response = requests.get(url)
print(type(response.cookies))
# 使用方法从cookiejar中提取数据
cookies = requests.utils.dict_from_cookiejar(response.cookies)
print(cookies)
重定向与历史请求
测试代码
import requests
headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
}
r = requests.get("http://www.baidu.com", headers=headers)
print(r.url)
# 以上代码打印结果为:https://m.baidu.com/?from=844b&vit=fps
思考:为什么打印出来的URL
不是请求的URL
呢?
想要搞清楚这个问题,就要知道requests
的重定向问题。
Requests
的默认情况
默认情况下,requests
发送的请求除了方式为HEAD
之外,其余的请求例如GET
、POST
等都是能自动进行重定向的
这也就是为什么上面明明访问的是http://www.baidu.com
而打印出来之后是https://m.baidu.com/?from=844b&vit=fps
的原因
取消自动重定向
在发送请求的时候,可以通过如下的设置,取消requests
模块的自动重定向功能
requests.get(url, allow_redirects=False)
示例代码:
import requests
headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
}
r = requests.get("http://www.baidu.com", headers=headers, allow_redirects=False)
print(r.status_code)
print(r.url)
默认情况下获取历史请求
通过response.history
可以获取到请求的历史记录
import requests
headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
}
r = requests.get("http://www.360buy.com", headers=headers)
print("历史请求过程信息:")
print(r.history)
for one_info in r.history:
print(one_info.status_code, one_info.url, one_info.headers)
print("\n\n最后一次的请求信息:")
print(r.status_code, r.url, r.headers)
SSL
证书错误
在浏览网页时,可能会遇到以下这种情况:
出现这个问题的原因是:ssl
的证书不安全导致。
在代码中发起请求的效果
import requests
url = "https://chinasoftinc.com/owa"
response = requests.get(url)
# 当前程序报错:ssl.CertificateError...
解决方案
在代码中设置verify
参数
import requests
url = "https://12306.cn/mormhweb/"
response = requests.get(url, verify=False)
请求超时
在爬虫中,一个请求很久没有结果,就会让整个项目的效率变得非常低。这个时候我们就需要对请求进行强制要求,让他必须在特定的时间内返回结果,否则就报错。
超时参数的使用
r = requests.get(url, timeout=3)
通过添加timeout
参数,能够保证在3秒钟内返回响应,否则会报错。
import requests
# url = "https://www.baidu.com"
url = "https://www.google.com"
response = requests.get(url=url, timeout=1)
这个方法还能够拿来检测代理ip
(代理会在后面讲解)的质量,如果一个代理ip
在很长时间没有响应,那么添加超时之后也会报错,对应的这个ip
就可以从代理ip
池中删除。
retrying
模块的使用
使用超时参数能够加快我们整体的运行速度。但是在普通的生活中当我们使用浏览器访问网页时,如果发生速度很慢的情况,我们会做的选择是刷新页面。那么在代码中,我们是否也可以刷新请求呢?
在本小节中我们使用retrying
模块来完成需求。
retrying
模块的使用
模块地址:https://pypi.org/project/retrying/
安装指令如下:
pip install retrying -i https://pypi.tuna.tsinghua.edu.cn/simple
作用:
- 使用
retrying
模块提供的retry
模块 - 通过装饰器的方式使用,让被装饰的函数反复执行
retry
中可以传入参数stop_max_attempt_number
,让函数报错后继续重新执行,达到最大执行次数的上限,如果每次都报错,整个函数报错,如果中间有一个成功,程序继续往后执行
import time
from retrying import retry
num = 1
@retry(stop_max_attempt_number=3)
def test():
global num
print("num=", num)
num += 1
time.sleep(1)
for i in 100:
print("i", i)
if __name__ == '__main__':
try:
test()
except Exception as ret:
print("产生异常...")
print(ret)
else:
print("没有异常")
retrying
和requests
的简单封装
实现一个发送请求的函数,每次爬虫中直接调用该函数即可实现发送请求
- 使用
timeout
实现超时报错 - 使用
retrying
模块实现重试
示例代码:
import requests
from retrying import retry
num = 1
@retry(stop_max_attempt_number=3)
def _parse_url(url):
global num
print("第%d次尝试" % num)
num += 1
headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
}
# 超时的时候会报错并重试
response = requests.get(url, headers=headers, timeout=3)
# 状态码不是200,也会报错并重试
assert response.status_code == 200 # 此语句是"断言",如果assert 后面的条件为True则呈现继续运行,否则抛出异常
return response
def parse_url(url):
# 进行异常捕获
try:
response = _parse_url(url)
except Exception as e:
print("产生异常:", e)
# 报错返回None
response = None
return response
if __name__ == '__main__':
url = "https://chinasoftinc.com/owa"
# url = "https://www.baidu.com"
print("----开始----")
r = parse_url(url=url)
print("----结束----", "响应内容为:", r)
发送json
格式数据
当我们发送POST
请求的时候,一般会携带数据,之前在学习POST
时,可以通过给data
赋值,从而能够完成传递form
表单数据。
requests.post(url, data={"kw": "python"})
但有很多时候,要向服务器发送的是json
数据,此时应该怎么办呢?
requests.post(url, json={"kw": "python"})
在请求方法中设置json
参数即可。
代码示例:
import requests
headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
}
r = requests.post("https://fanyi.baidu.com/sug", headers=headers, json={"kw": "python"}, timeout=3)
print("请求头是:", r.request.headers)
print("请求体是:", r.request.body)
Session
会话
当我们在爬取某些页面的时候,服务器往往会需要cookie
,而想要得到cookie
就需要先访问某个URL
进行登录,服务器接收到请求之后验证用户名以及密码在登录成功的情况下会返回一个响应,这个响应的header
中一般会有一个set-cookie
的信息,它对应的值就是要设置的cookie
信息。
虽然我们再之前可以通过requests.utils.dict_from_cookiejar(r.cookies)
提取到这个响应信息中设置的新cookie
,但在下一个请求中再携带这个数据的过程较为麻烦,所以requests
有个高级的方式 - 会话Session
Session
的作用
Session
能够跨请求保持某些参数,也会在同一个Session
实例发出的所有请求之间保持cookie
会话保持有两个内涵:
- 保存
cookie
,下一次请求会自动带上前一次的cookie
- 实现和服务端的长连接,加快请求速度
使用方法
# 1. 创建一个session实例对象
s = requests.Session()
# 2. 使用上一步创建的对象发起请求
r = s.get(url1, headers)
r = s.get(url2, headers)
r = s.get(url3, headers)
r = s.get(url4, headers)
session
对象在请求了一个网站后,对方服务器设置在本地的cookie
会保存在session
对象中,下一次再使用session
对象请求对方服务器的时候,会自动带上前一次的cookie
代码示例:
import requests
session = requests.Session()
headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
}
# 发送第一个请求
response = session.get('https://www.baidu.com', headers=headers)
print("第一次请求的请求头为:", response.request.headers)
print("响应头:", response.headers)
print("设置的cookie为:", requests.utils.dict_from_cookiejar(response.cookies))
# 发送第二个请求()
response = session.get("https://www.baidu.com")
print("第二次请求的请求头为:", response.request.headers)
代理
使用代理的原因
当在爬某个网站的时候,如果对方进行了封锁例如将我们电脑的公网ip
封锁了,那么也就意味着只要是这个ip
发送的所有请求这个网站都不会进行响应;此时我们就可以使用代理,绕过它的封锁从而实现继续爬取数据
基本原理
在当前用户电脑中连接其他区域的电脑,每台电脑因为区域不同所以分配的ip
也不相同。使用其他区域的电脑帮助我们发送想要发送的请求。
基本使用
将代理地址与端口配置成字典并使用proxies
参数传递
proxies = {
"http": "http://10.10.1.10:3128",
"https": "http://10.10.1.10:1080",
}
requests.get("https://example.org", proxies=proxies)
如何获取代理
百度查询
免费代理ip
,但一般情况下都不太好用
对于免费代理大部分都是不可用的,建议可以使用付费代理。例如:芝麻代理、快代理等等。
代理案例
import requests
# http代理
ip = "127.0.0.1"
port = 7890
proxies = {
"http": "http://%s:%d" % (ip, port),
"https": "http://%s:%d" % (ip, port)
}
# 请求头
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36"
}
url = "http://httpbin.org/ip"
response = requests.get(url=url, headers=headers, proxies=proxies, timeout=10)
print(response.text)