跟着崔庆才学爬虫2:requests库的使用

安装requests库
pip install requests

可以通过在终端中使用 pip list 指令看有没有安装成功

安装成功后我们写第一个实例

# 安装requests pip install requests
import requests 
r = requests.get('https://www.baidu.com')
print(type(r))
print(r.status_code)
print(type(r.text))
print(r.cookies)
print(r.text[:200])

这里我们调用get方法实现了和urlopen方法相同的操作,返回一个Response对象,并将其存放在变量r中,然后分别输出响应的类型,状态码,响应体的类型,内容以及cookie

 观察运行结果发现,返回的相应类型是<class 'requests.models.Response'>,响应体的类型是字符串str,Cookie的类型是RequestsCookieJar。

使用get方法成功实现一个GET请求不算什么,requests库更方便之处在于其他请求依然可以一句话处理。示例如下

import requests 
resp=requests.get('https://www.httpbin.org/get')
resp=requests.post('https://www.httpbin.org/post')
resp=requests.put('https://www.httpbin.org/put')
resp=requests.delete('https://www.httpbin.org/delete')
resp=requests.patch('https://www.httpbin.org/patch')
resp=requests.patch('https://www.httpbin.org/patch')

这里分别用了post,put,delete,等多种请求。是不是比urllib库简单多了。

GET请求

HTTP 中最常见的请求之一就是GET请求,接下来我们用一个实例详细了解一下利用requests库构建GET请求的方法。

实例代码

import requests
r = requests.get('https://www.httpbin.org/get')
print(r.text)

 运行结果如下

可以发现,我们成功发起了GET请求,返回结果包含请求头,URL,IP等信息。

那么我们想要用GET请求附加额外的信息,要怎么做呢,例如要添加两个参数name和age,name和age的值分别是germey,25,于是URL就可以写成这样

https://www.httpbin.org/get?name=germey&age=25

要构造这个请求链接是不是要写成

r =requests.get("https://www.httpbin.org/get?name=germey&age=25")

虽然也可以,但是我们有更加方便的方法,一般这种情况我们使用params参数就可以传递这种信息了,示例如下

import requests
data={
    'name':'germey',
    'age':25
}
r = requests.get('https://www.httpbin.org/get',params=data)
print(r.text)

 运行结果

 可以看到我们把URL参数以字典形式传给get方法的params参数,通过返回信息我们可以看到请求链接已经被自动构造成 "url": "https://www.httpbin.org/get?name=germey&age=25",这样,我们就不用自己构造URL了。

另外网页返回的类型虽然是str类型,但是它很特殊,是json格式的,所以,如果想直接解析返回结果,得到一个json格式的数据,可以直接调用json方法,示例如下

import requests
resp =requests.get('https://www.httpbin.org/get')
print(type(resp.text))
print(resp.json())

返回结果

可以发现调用json方法可以将返回结果(json格式的字符串)转化为字典。

但是需要注意的是,如果返回结果不是json格式的,就会出现解析错误,抛出json.decoder.JSONDecodeErorr异常。

抓取网页

上面请求链接返回的是json格式的字符串,那么如果请求的是普通页面,就肯定能获取响应的内容。我们写一个实例,实例网站 https://ssr1.scrape.center/,往里面加入一点提取信息的逻辑。

示例如下

import re
import requests

r = requests.get("https://ssr1.scrape.center/")
pattern = re.compile("<h2.*?>(.*?)</h2>",re.S)
title = re.findall(pattern,r.text)
print(title)

返回结果

这个例子我们用最基础的正则完成,关于正则会在下一节讲到。可以通过返回结果发现,这里成功提取了所有电影标题,只需要一个最基础的抓取和提取流程就完成了。

抓取二进制数据

上面的例子我i们抓取的是一个网站的页面,实际上它返回的是一个HTML文档,要是想抓取图片,视频,音频等文件应该怎么办呢。

图片,音频,视频这些文件本质都是二进制编码组成的,由于有特定的保存格式和对应的解析方式,我们才可以看到这些形形色色的多媒体,所以想要抓取他们,就必须拿到他们的二进制数据。

这里写个实例给大家看一下(大家可以用其他网站尝试一下)
 

import requests
resp = requests.get('https://scrape.center/favicon.ico')# 访问的是图片内容
print(resp.text)
print(resp.content)

可以很明显的看到r.text出现了代码,r.content的前面出现了b,代表着是bytes类型的数据,由于图片是二进制数据,所有前者打印时会转化为str类型,也就是图片直接转化字符串,理所应当会出现乱码。

上面的代码并不能看到,它实际上是图片的二进制数据,不过没有关系,我们将刚才提取到的信息保存下来就好了

代码如下

import requests
resp = requests.get('https://scrape.center/favicon.ico')# 访问的是图片内容
with open('favicon.ico','wb') as f:# 保存数据,将二进制数据保存至ico文件
    f.write(resp.content)

这里用了open方法,其第一个参数是文件名称,第二个参数代表以二进制的形式打开文件,可以向文件里写入二进制数据。运行结束后就可以发现文件夹多出一个favicon.ico文件,点开可以发现是一个图标。

添加请求头

我们知道,在发送HTTP请求时,会有一个请求头Request Headers ,那么怎么设置这个请求头呢?

在requests库中,有一个专门处理请求头的参数headers

如果我们想为一个请求添加一个User-Agent字段,就可以这么写

这里介绍一个自动创建User-Agent的库使用方法

from fake_useragent import UserAgent
 # 外部库。可随机生成UA,安装 pip install fake-useragent

使用方法

import requests
from fake_useragent import UserAgent # 外部库。可随机生成UA,安装 pip install fake-useragent
ua =UserAgent()
url = "https://www.httpbin.org/post"
data = {'name':"cat"}
headers = {
    "User-Agent":ua.chrome
}
resp = requests.post(url,data=data,headers=headers)
print(resp.text)

可以发现form部分就是我们提交的数据,而headers里的UA不在是之前的 "User-Agent": "python-requests/2.31.0"

响应

请求成功后,自然就会得到响应,在上面的实例中,我们使用text和content获取了响应的内容,此外,还有很多属性和方法可以用来获取其他信息,例如获取状态码,响应头,cookie等。

实例如下

import requests 
r = requests.get('https://ssr1.scrape.center/')
print(r.status_code,type(r.status_code))
print(r.headers,type(r.headers))
print(r.cookies,type(r.cookies))
print(r.url,type(r.url))
print(r.history,type(r.history))

通过status_code属性得到状态码,通过headers属性得到响应头,通过cookie属性得到Cookie,通过url得到URL,通过history属性得到请求历史,并将这些信息打印输出到控制台。

可以看到headers和cookies这两个属性结果分别是CaseInsensitiveDict和RequestsCookieJar对象/

由之前章节我们知道状态码是响应状态的,例如200代表访问成功,requests库中还提供了一个内置的状态码查询对象requests.codes

示例如下

import requests
r=requests.get('https://ssr1.scrape.center/')
exit() if not r.status_code == requests.codes.ok else print("Request Successfully")

这里通过比较返回码和内置的表示成功的状态码,来保证请求是否得到了正常响应,如果是,就输出请求成功的信息。否则程序终止允许,这里我们用的requests.codes.ok得到的成功状态码是200。

这样我们就不需要在程序里写状态码对应的数字了,用字符串表示状态码就显得更加直观。

大家也可以去网上查询一下状态码和相应的查询条件。

文件上传

我们知道使用requests库可以模拟提交一些数据,除此之外。要是网站需要上传文件,也可以用它来实现。实例如下

# 文件上传
import requests
files = {'file': open('favicon.ico','rb')}
r =requests.post('https://www.httpbin.org/post',files=files)
print(r.text)

前面我们保存了一个favicon.ico文件。就使用它模拟文件上传过程。需要注意文件要在同一目录下。运行结果如下

文件上传后,网站会得到返回相应,响应中包含files字段和form字段,而form字段是空的,这证明文件上传部分会单独用一个files字段来标识。

Cookie设置

之前用urllib库中也处理cookie,但是写法比较复杂,但是有了requests后,获取和设置cookie一步即可完成。
 

import requests
r =requests.get('https://www.baidu.com')
print(r.cookies)
for key,value in r.cookies.items():
    print(key+":"+value)

运行结果如下

 我们首先调用cookies属性,成功得到Cookie,可以发现它属于RequestsCookieJar类型。然后调用items方法将cookie转化为元组组成的列表,遍历输出每一个cookie条目的名称和值,实现对cookie的遍历和解析。

当然我们也可以用cookie来维持登录状态,这里没有找到合适的网站,只发示例代码

import requests


headers = {
    'Cookie': 'BIDUPSID=CEFA1431FA3035D8A88CA01E5272D0DA; BAIDUID=336DACAF5F265965F2A2C6D7B124134B:FG=1; PSTM=1688692387; BAIDUID_BFESS=336DACAF5F265965F2A2C6D7B124134B:FG=1; ZFY=yZT:B1N:BaD8f3gV7rPcMUJ4LCxXrrW2IvKTIZ9Bg5Ak4:C; __bid_n=18baa405c23115289e20f7; RT="z=1&dm=baidu.com&si=cef43f1d-b4e0-4690-8ef3-006d148611e9&ss=loofwynn&sl=28&tt=xtl&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=1r5d1&ul=1rw7h&hd=1rwap"; H_PS_PSSID=39636; BD_UPN=12314753; BA_HECTOR=2504802h848l250hag0l85831iks68d1r; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598',
}

response = requests.get('https://www.baidu.com/', headers=headers)
print(response.text)
import requests
cookies = 'BIDUPSID=CEFA1431FA3035D8A88CA01E5272D0DA; BAIDUID=336DACAF5F265965F2A2C6D7B124134B:FG=1; PSTM=1688692387; BAIDUID_BFESS=336DACAF5F265965F2A2C6D7B124134B:FG=1; ZFY=yZT:B1N:BaD8f3gV7rPcMUJ4LCxXrrW2IvKTIZ9Bg5Ak4:C; __bid_n=18baa405c23115289e20f7; RT="z=1&dm=baidu.com&si=cef43f1d-b4e0-4690-8ef3-006d148611e9&ss=loofwynn&sl=28&tt=xtl&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=1r5d1&ul=1rw7h&hd=1rwap"; H_PS_PSSID=39636; BD_UPN=12314753; BA_HECTOR=2504802h848l250hag0l85831iks68d1r; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598'
jar = requests.cookies.RequestsCookieJar()
headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
}
for cookie in cookies.split(";"):
    key,value = cookie.split('=',1)
    jar.set(key,value)
r= requests.get('https://www.baidu.com',cookies=jar,headers=headers)
print(r.text)
session维持

上面我们直接利用requests库中的get或post方法确实可以做到模拟登录网页的请求。但是这两种方法实际上相当于两种不同的session,或者说是用了两个浏览器打开了不同的页面。

设想一个场景,第一次请求利用requests库方法登录了网站,第二次想获取网站登录后的个人信息,于是有一次用requests的get方法去请求个人信息页面。能成功吗,显然不能,这相当于打开了两个不同的浏览器。

那么,设置一个cookie可以吗,可以,但是这样显得代码很繁琐,我们有更简单的解决方案。

究其原因解决这个问题的主要方法是维持同一个session,也就是第二次请求的时候是打开一个新的浏览器选项卡,而不是重新打开一个浏览器,但是又不想每次都设置cookie该怎么办呢,这是就出现了新的利器——session对象。

利用session对象,我们可以方便地维护一个session而不是担心cookie的问题,它会自动帮我们处理好

小案例,如果我们沿用之前的写法,实例如下

import requests
requests.get("https://httpbin.org/cookie/set/number/123456789")
r = requests.get('https://www.httpbin.org/cookies')
print(r.text)

这里我们请求一个测试网站,请求这个网址时,设置了一个cookie条目,名称时number,内容时123456789,随后又请求了https://www.httpbin.org/cookies用来获取当前的cookie信息。

这样能获取到cookie吗             

  运行结果发现cookie为空。

我们在用刚刚说的session方法试试
 

import requests
s=requests.Session()
s.get('https://www.httpbin.org/cookies/set/number/123456789')
r=s.get('https://www.httpbin.org/cookies')
print(r.text)

 运行

 成功获取到了cookie信息了。

session在平常用的非常广泛,可以用于模拟在一个浏览器中打开同一站点的不同页面。后面我们会专门讲解这部分内容

SSL证书验证

现在很多网址要求使用HTTPS协议,但是有些网站可能并没有设置好HTTPS证书,或者网站的HTTPS证书可能不被CA机构认可,这时这些网站就可能会出现SSL证书错误的提示。

例如https://ssr2.scrape.center浏览器打开会出现一个警告

我们可以在浏览器中通过设置来忽略证书验证。但是我们写爬虫代码又要怎么处理呢。

先用requests库试一下
 

import requests
resp=requests.get("https://ssr2.scrape.center")
print(resp.status_code)

运行结果如下

raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='ssr2.scrape.center', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1002)'))) 

可以看出直接抛出SSLErorr错误,原因时我们请求的URL证书时无效的

如果我们一定要爬取这个网站的话,就可以使用verify参数控制是否验证证书,如果这个参数设置为false,那么请求时就不会再验证证书是否有效,如果不设置verify参数,其默认值时True,会自动验证,改写代码如下

import requests
resp=requests.get("https://ssr2.scrape.center",verify=False)
print(resp.status_code)

这样我们就可以打印出请求成功的状态码了

d:\跟着崔庆才学爬虫\.venv\Lib\site-packages\urllib3\connectionpool.py:1100: InsecureRequestWarning: Unverified HTTPS request is being made to host 'ssr2.scrape.center'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings
  warnings.warn(
200

不过我们还是发现了一处警告,它建议我们给它指定证书,我们可以通过设置忽略警告的方式屏蔽该警告:代码如下

from requests.packages import urllib3
import requests
urllib3.disable_warnings()
resp=requests.get("https://ssr2.scrape.center",verify=False)
print(resp.status_code)

这是返回的响应只有一个200了

或者我们可以通过捕获警告到日志的方式忽略警告
 

import logging
import requests
logging.captureWarnings(True)
resp = requests.get("https://ssr2.scrape.center",verify=False)
print(resp.status_code)

可以得到上面一样的结果,当然我们也可以指定一个本地证书用作客户端证书,这可以是个单个文件(包含密钥和证书)或一个包含两个路劲的元组

超时设置

见名知意,在网络状况不好或者服务器响应太慢甚至没有响应时,我们可能需要很长时间才能得到响应,甚至到最后因为接收不到信息报错,为了防止服务器不能及时响应,应该设置一个超时时间,如果超过时间没有响应,则报错,这就要用到timeut参数

实例如下

import requests
r = requests.get('https://www.httpbin.org/get',timeout=1)
print(r.status_code)

这里我们设置超时时间时1秒,超过这个时间就抛出异常。

实际上,请求分为两个阶段:连接(connect)和读取(read)

上面设置的timeout是用作连接和读取的总和。

如果分别指定用作连接和读取的timeout,可以传入一个元组

r=requests.get('https://www.httpbin.org/get',timeout=(5,30))
print(r.status_code)

如果想一直等待,可以设置timeout=None,或者不设置该参数。

身份认证

在访问启用了基本身份认证的网站时(例如 https://ssr3.scrape.center)首先会直接弹出一个登录页面

之前我们使用urllib库实现过身份的校验,但是实现起来很繁琐,那么requests库中怎么做呢

我们可以使用requests库自带的身份认证功能,通过auth参数即可设置,实例如下

import requests
from requests.auth import HTTPBasicAuth
r = requests.get('https://ssr3.scrape.center/',auth=HTTPBasicAuth("admin",'admin'))
print(r.status_code)

如果密码正确则会返回状态码200,错误则返回401,当然如果参数都传一个HTTPBasicAuth会显得有些繁琐,所有requests库提供一个更简单的写法,直接写一个元组,它会默认使用HTTPBasicAuth这个类来认证。

上面代码简写如下
 

import requests
r = requests.get("https://ssr3.scrape.center",auth=('admin','admin'))
print(r.status_code)

此外requests库还提供了OAuth认证,不过此时需要安装oauth包,安装命令

pip install requests_oauthlib        

使用实例如下
 

import requests
from requests_oauthlib import OAuth1
url = "https://api.twitter.com/1.1/account/verify_credentials.json"
auth =OAuth1('YOUR_APP_KEY','YOUR_APP_SECRET',
             'USER_OAUTH_TOKEN','USER_OAUTH_TOKEN_SECRET')
requests.get(url,auth=auth)
代理设置

某些网站测试的时候请求都可以成功获取内容,但是到大规模请求时,这些网站就会弹出验证码,或者跳转到登录验证界面,更甚者还会直接封禁客户端的IP,导致一段时间无法访问。

这时候我们就需要设置代理来解决这个问题,requests库提供了一个proxies参数,可以用这样的方式设置

import requests
proxies={
    'http':'http://10.10.10.10:1080',
    'https':'http://10.10.10.10.1080'
    # 语法 http://user:password@10.10.10.10:1080/
}
requests.get('https://www.httpbin.org/get',proxies=proxies)

当然直接运行这个实例不行的,我们可以去网上找免费的代理ip测试,如小象代理,快代理等,都有免费代理提供。

另外,如果代理需要使用上文所述的身份认证。可以使用类似http://user:password@host:post这样的语法来设置代理,实例如下

# 实例
import requests
proxies={
    'http':'http://user:password@10.10.10.10:1080/',

}
requests.get('https://www.httpbin.org/get',proxies=proxies)

除了基本的HTTP代理外,requests库还支持SOCKS协议的代理

首先安装socks这个库

pip install "requests[socks]"

 实例如下

import requests
proxies = {
    "http":"socks5://user:password@host:port",
    "https":"socks5://user:password@host:port"
}
r=requests.get('https://www.httpbin.org/get',proxies=proxies)
print(r.text)
Prepard Request

我们已经知道可以直接使用requests库的get和post方式发送请求,但有没有想过,这个请求是怎么在requests内部实现的呢

实际上,requests在发送请求的时候,是在内部构造一个Request对象,并且给这个对象赋予各种参数,包括url,headers,data等,然后直接把这个Request对象发送出去,请求成功后会再得到一个Response对象,解析这个对象即可

那么Request对象是什么类型呢,实际上他就是Prepard Request

我们深入一下,不用get方法,直接构造一个Prepard Request对象试试,代码如下。

from requests import Request,Session
from fake_useragent import UserAgent # 外部库。可随机生成UA,安装 pip install fake-useragent
ua =UserAgent()
url = "https://www.httpbin.org/post"
data = {'name':"cat"}
headers = {
    "User-Agent":ua.chrome
}
s = Session()
req=Request("POST",url,data=data,headers=headers)
prepped = s.prepare_request(req)
r=s.send(prepped)
print(r.text)

这里我们引入乐乐Reques类,然后用url,data和headers参数构造了一个Request对象,这是需要再调用一个session类的prepard_request方法将其转换为一个Prepard Request对象,再调用send方法发送运行结果如下

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "name": "cat"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "8", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "www.httpbin.org", 
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", 
    "X-Amzn-Trace-Id": "Root=1-654e551e-5750c10020e7300c021b3317"
  }, 
  "json": null, 
  "origin": "112.32.64.129", 
  "url": "https://www.httpbin.org/post"
}

可以看到我们达到了和POST方法同样的效果。有了Request这个对象,就可以将请求当作独立的对象看待,这样在一些场景我们可以直接操作Request对象,更加灵活的实现请求的调度和各种操作。

总结

没错,关于requests库的基本用法已经讲完了,用法和语法上都比urllib库更方便。明天我们继续讲解爬虫之正则篇。

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值