一:简介
1.1 预请求 PreparedRequest
参数 | 描述 |
---|
url | 请求地址(除url外其它参数都是可选的)。 | params | 查询字符串Query String(字典,列表,元组) | data | body体 (字段,列表,元组,字节或者文件) "Content-Type": "application/x-www-form-urlencoded" | json | json参数 "Content-Type": "application/json" | headers | 请求头(dict) | cookies | Cookie (RequestsCookieJar ) 常用于保持用户登录状态 | timeout | 设置超时时间,单位秒 | proxies | 代理 | verify | SSL 验证 | cert | 证书 | files | 文件 | auth | 指定身份验证机制 Basic Auth | allow_redirects | 是否允许重定向 | stream | 流式请求,主要对接流式 API |
1.2 响应 Response
参数 | 描述 |
---|
url | 响应的最终URL位置,重定向之后的地址 | status_code | 响应状态码 | ok | 只要状态码 status_code 小于 400,都会返回 True | content | 响应内容 bytes ,如获取图片时会使用 | text | 响应内容 str | json() | 响应内容 dict | raw | http响应的原始值 HTTPResponse | headers | 响应头 | cookies | Cookie (RequestsCookieJar ) | encoding | text 时的编码 | is_redirect | 重定向属性 | history | 重定向历史 | reason | 地址是否有效: OK 、NOT FOUND | request | 请求对象 | request.headers | 请求对象的请求头 | request.url | 请求对象的请求url |
二:基础案例
2.1 get | post | put | delete | head | options
import requests
res = requests.request('get', 'https://api.github.com/events')
help(res)
print(dir(res))
print(res.text)
res = requests.get('https://api.github.com/events')
res = requests.post('http://httpbin.org/post', data={'key': 'value'})
requests.put('http://httpbin.org/put', data = {'key':'value'})
requests.delete('http://httpbin.org/delete')
requests.head('http://httpbin.org/get')
requests.options('http://httpbin.org/get')
2.2 乱码
- 如果乱码时设置encoding。
- 如果header中不存在charset字段,默认编码为ISO-8859-1,此时的编码输出text中的中文将是乱码。
- apparent_encoding:会根据HTTP网页的内容分析出应该使用的编码。
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'
}
res = requests.get('http://www.baidu.com', headers=headers)
print(res.encoding)
print(res.apparent_encoding)
res.encoding = res.apparent_encoding
print(res.text)
content = res.content.decode('utf-8')
三:get
payload = {'key1': 'value1', 'key2': 'value2', 'key3': None}
res = requests.get("http://httpbin.org/get", params=payload, timeout=3)
res.encoding=res.apparent_encoding
print(res.url)
print(res.status_code, requests.codes.ok)
print(res.headers)
print(res.headers['Content-Type'])
print(res.request.headers)
print(res.text)
print(content)
print(res.json())
请求头
注意:爬虫一般都必须要携带User-Agent 头。
import requests
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Host': 'httpbin.org',
'Pragma': 'no-cache',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36',
}
res = requests.get('http://httpbin.org/get', headers=headers)
print(res.text)
通常我们会粘贴浏览器中的Request Headers,但是粘贴过来的有两个问题,一个问题是没有缩进,另一个问题是Key和Value没有被字符串单引号包括住,可以使用PyCharm的正则表达式替换。首先选中要操作的字符串,然后选择匹配模式为正则表达式模式,输入查找的字符串和替换的字符串,然后Replace all。
. 表示单个任意字符。* 表示匹配任意次。? 表示匹配0次或多次。() 表示正则表达式为一个整体。$数字 :表示匹配到的结果,数字从1开始。
请求图片
import requests
from io import BytesIO
from PIL import Image
res = requests.get('https://profile-avatar.csdnimg.cn/8b6439a0bcb34188953be722a564c8cc_vbirdbest.jpg')
img = Image.open(BytesIO(res.content))
print(img)
Cookie
- Cookie可以放入到请求头headers中。
- Cookie也可以作为某个请求的参数 cookies。
- Cookie常用于保存用户的登录状态。
headers = {
'Cookie': 'key1=value1;key2=value2'
}
res = requests.get('http://httpbin.org/cookies', headers=headers)
res = requests.get('http://httpbin.org/cookies', cookies=dict(key1='value1', key2='value2'))
print(res.text)
import requests
cookies = requests.cookies.RequestsCookieJar()
cookies.set('cookie1', 'value1', domain='httpbin.org', path='/cookies')
cookies.set('cookie2', 'value2', domain='httpbin.org', path='/cookies')
session = requests.Session()
res = session.get('http://httpbin.org/cookies', cookies=cookies)
print(res.text)
res = requests.get('http://www.baidu.com')
print(res.text)
cookiejar = requests.utils.dict_from_cookiejar(res.cookies)
cookiedict = requests.utils.cookiejar_from_dict(cookiejar)
重定向
res = requests.get('http://github.com', allow_redirects=True)
print(res.status_code)
print(res.text)
钩子函数
def print_url(r, *args, **kwargs):
print(r.url)
hooks=dict(response=print_url)
res = requests.get('http://httpbin.org', hooks=dict(response=print_url))
print(res)
证书
访问一些网站时有时候会提示”您的连接不是私密连接 “,很多证书都是官方颁布的而是自己颁布的,自己颁布的这些证书是可以关闭认证的(只是会提示一个警告), 有些证书是绕不过去的还需要提供证书。
r = requests.get("https://sam.huat.edu.cn:8443/selfservice/", verify = False)
print(r.text)
requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key'))
import requests
session = requests.Session()
session.auth = ('user', 'pass')
session.headers.update({'token': '123456789'})
res = session.get('http://httpbin.org/headers', headers={'sign': 'xxx'})
print(res.text)
代理
根据方向来分类
- 正向代理: 知道服务器的地址。
- 反向代理:不知道服务器的地址,如nginx。
根据协议来分类
- HTTP代理。
- HTTPS代理。
- Socks隧道代理:在socket层设置的代理。
根据透明度来分类
-
透明代理(Transparent Proxy):透明代理虽然可以直接”隐藏“你的IP地址,但是还是可以查到你是谁。 REMOTE_ADDR = Proxy IP
HTTP_VIA = Proxy IP
HTTP_X_FORWARDED_FOR = Your IP
-
匿名代理(Anonymous Proxy):匿名代理只能知道你用了代理,不知道你是谁。 REMOTE_ADDR = Proxy IP
HTTP_VIA = Proxy IP
HTTP_X_FORWARDED_FOR = Proxy IP
-
高匿代理(High Anonymous Proxy):高级代理别人根本不知道你是不是在使用代理,所以是最好的选择。 REMOTE_ADDR = Proxy IP
HTTP_VIA = not determined
HTTP_X_FORWARDED_FOR = not determined
免费代理网站:一般能够代理http的也能代理https
proxies = {
'http': '223.96.90.216:8085'
}
res = requests.get('https://www.baidu.com/', proxies=proxies)
print(res.text)
四:post
请求值的一般来源:
- 固定值:参数值是固定不变的
- 输入值:一般是输入参数。
- 预设值-隐藏在静态文件中:需要从html中通过正则获取
- 预设值-发送请求:如获取token
- 在客户端生成的:如签名sign,可能会随着时间戳ts(timestamp)、岩(salt)等和其它参数拼接成一个字符串来生成的。
爬虫时一般要发送大于1次请求(如发送2次请求),然后比较两次请求哪些参数是变化的,哪些参数是不变的。
res = requests.post('http://httpbin.org/post', data={'key': 'value'})
payload = (('key1', 'value1'), ('key1', 'value2'))
res = requests.post('http://httpbin.org/post', data=payload)
res = requests.post('http://httpbin.org/post', json={'key': 'value'})
print(res.text)
import json
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
requests.post(url, data=payload)
requests.post(url, data=json.dumps(payload))
url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=files)
print(r.text)
文件
url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}
files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
r = requests.post(url, files=files)
print(r.text)
多个文件
<input type="file" name="images" multiple="true" required="true"/>
multiple_files = [
('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
五:Session
-
使用Session连续发送多个请求性能更好:底层的 TCP 连接将会被重用。 -
Session用于保持登录会话,下一次请求会携带上一次Response的Cookie。实际使用时只需要调用一次登录接口获取返回的Cookie(如JSESSIONID等),后面再发其它请求就会自动携带登录返回的Cookie,这样后面的接口就可以调通了。无论以什么样的方式发送请求方法最终会调动session.get() -> request() -> prepare_request(req) -> cookies处理 。 -
Session会默认添加4个请求头,并对请求头进行按字母排序。
- 注意:注意:注意:有些接口在请求时对Headers的顺序是有严格的要求的(可能是为了防止爬虫吧),如果顺序不对结果就不对,浏览器默认会按照字母进行排序。所以我们在发送请求时一定要点击 【View source】 来获取浏览器没有排过续的请求头,以后要养成习惯。
session = requests.Session()
session.headers.clear()
session.headers.update(headers)
res = session.get('https://www.baidu.com/')
print(res.request.headers)
session.close()
with requests.Session() as s:
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
六:GitHub登录
注意:一定要先退出自己的账号,如果账号应已经在网页中登录了则login接口会一直没有响应。
import re
import requests
headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'
}
session = requests.Session()
content_login = session.get('https://github.com/login').content.decode()
authenticity_token = re.findall('name="authenticity_token" value="(.*?)" />', content_login)[0]
print(authenticity_token)
data = {
'commit': 'Sign in',
'authenticity_token': authenticity_token,
'login': '账号',
'password': '密码',
'webauthn-support': 'supported'
}
session.post('https://github.com/session', data=data)
profile = session.get('https://github.com/账号').content
with open('github.com', 'wb') as f:
f.write(profile)
|