Python爬虫篇:HTTP库requests

Posted 风流 少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python爬虫篇:HTTP库requests相关的知识,希望对你有一定的参考价值。

一:简介

1.1 预请求 PreparedRequest

参数描述
url请求地址(除url外其它参数都是可选的)。
params查询字符串Query String(字典,列表,元组)
databody体 (字段,列表,元组,字节或者文件)
"Content-Type": "application/x-www-form-urlencoded"
jsonjson参数 "Content-Type": "application/json"
headers请求头(dict)
cookiesCookie (RequestsCookieJar) 常用于保持用户登录状态
timeout设置超时时间,单位
proxies代理
verifySSL 验证
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
rawhttp响应的原始值 HTTPResponse
headers响应头
cookiesCookie (RequestsCookieJar)
encodingtext 时的编码
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

# 请求头中如果包含了User-Agent,对方可能就认为该请求是从浏览器中发出的,将自己伪装成浏览器
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)
# ISO-8859-1
print(res.encoding)
# utf-8
print(res.apparent_encoding)
# '百度一下,你就知道' 如果不设置encoding,res.text中的中文会乱码
res.encoding = res.apparent_encoding
print(res.text)

# res.text是requests模块按照chardet模块推测出的编码字符集进行解码的结果
# 网络传输的字符串都是bytes类型的,所以res.text = res.content.decode('推测出的字符集编码')
# 我们可以在网页源码中搜索charset, 尝试参考编码字符串,注意存在不准确的情况
# decode(charset) 接收一个字符编码集的参数,默认是'utf-8'
content = res.content.decode('utf-8')

三:get

# 参数也可以直接放到url后面,如 https://www.baidu.com/s?wd=python
# timeout在指定时间内没有响应会报连接错误 ConnectTimeout
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)
# 不包含域名
# dict -> cookiejar
cookiejar = requests.utils.dict_from_cookiejar(res.cookies)
# cookiejar -> dict
cookiedict = requests.utils.cookiejar_from_dict(cookiejar)

重定向

res = requests.get('http://github.com', allow_redirects=True)
# 302 表示重定向
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')
# 全局header
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

# HTTP Basic Auth 可以在url中指定用户名和密码 http://user:pass@123.171.1.78:8089
# 免费代理经常不可用
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次请求),然后比较两次请求哪些参数是变化的,哪些参数是不变的。

# data可以是dict或tuple
# data是"Content-Type": "application/x-www-form-urlencoded",
res = requests.post('http://httpbin.org/post', data='key': 'value')

payload = (('key1', 'value1'), ('key1', 'value2'))
res = requests.post('http://httpbin.org/post', data=payload)


# json参数使用的是"Content-Type": "application/json"
res = requests.post('http://httpbin.org/post', json='key': 'value')
print(res.text)


# data也可以传入json
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)
# 设置Basic Auth:http://httpbin.org/basic-auth
# session.auth = ('user', 'passwd')
res = session.get('https://www.baidu.com/')
# 
#     'User-Agent': 'python-requests/2.28.1',
#     'Accept-Encoding': 'gzip, deflate',
#     'Accept': '*/*',
#     'Connection': 'keep-alive'
# 
print(res.request.headers)
session.close()

# with代码块结束销毁session
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()
# 1.获取token(注意:一定要先退出自己的账号,如果账号应登录则请求会一直没有响应)
content_login = session.get('https://github.com/login').content.decode()
# <input type="hidden" name="authenticity_token" value="MPoH_UoMCducxg_iNdl7b2r9cGxGwsunkrYBN-XCUJC_dzW78zc2U-OLQ5d2I5pPv92FErXziG_yT-uRdg_QQA" />
authenticity_token = re.findall('name="authenticity_token" value="(.*?)" />', content_login)[0]
print(authenticity_token)

# 2.登录
data = 
    'commit': 'Sign in',
    'authenticity_token': authenticity_token,
    'login': '账号',
    'password': '密码',
    'webauthn-support': 'supported'

session.post('https://github.com/session', data=data)

# 3.profile 获取用户信息
profile = session.get('https://github.com/账号').content
with open('github.com', 'wb') as f:
    f.write(profile)

以上是关于Python爬虫篇:HTTP库requests的主要内容,如果未能解决你的问题,请参考以下文章

Python爬虫篇:HTTP库requests

Python网络爬虫入门篇

Python爬虫编程思想(20):requests网络库的基本用法

Python爬虫:HTTP协议Requests库

python爬虫之requests库

Python爬虫之Requests库入门