python爬虫(3)——cookie与requests库


在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie 的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的 cookie 数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie 存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过 4KB。因此使用 cookie 只能存储一些小量的数据。
cookie的一般格式如下:
Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
参数的描述如下表:

参数名 参数描述
NAME cookie的名字
VALUE cookie的值
Expires cookie的过期时间
Path cookie作用的路径
Domain cookie作用的域名
SECURE 是否只在https协议下起作用

浏览器保存了cookie,后面每次访问时就方便,如果要用代码来向那些需要登录才能访问的(进行更多操作)网站,就需要把cookie信息传给目标服务器,登录说白了也就是要有cookie信息。要获取cookie信息,首先第一想法就是直接去网站上登录,然后按F12,就能找到cookie信息,以人人网(访问演员大鹏主页,需要登录才能访问)为例子:

from urllib import request,parse
#先注释掉cookie
headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)\
         AppleWebKit/537.36 (KHTML, like Gecko) \
         Chrome/83.0.4103.116 Safari/537.36 Edg/83.0.478.58',
         # 'Cookie': 'ick_login=0ddad9f3-7fa0-4787-b916-5248ea8bb154; anonymid=kca04u42-rmbvi0; depovince=GW; _r01_=1; JSESSIONID=abchsJm52fkNjfdE5xImx; taihe_bi_sdk_uid=15a8a286885699bb6771e6212cc23aa5; taihe_bi_sdk_session=d83833b4a0fb72a6a466205c9329e993; ick=07bea91b-c6d1-4955-ad33-0980db50a672; t=c2a3a8d10309229b0555eb589c8482575; societyguester=c2a3a8d10309229b0555eb589c8482575; id=974715915; xnsid=dd9ddee7; XNESSESSIONID=6c76a75ff812; WebOnLineNotice_974715915=1; ver=7.0; loginfrom=null; jebe_key=060c174f-c2df-4669-9a2c-584b47a0e4a8%7C032338e00e79b21248aaa07a19d3e44d%7C1594009812653%7C1%7C1594009810029; jebe_key=060c174f-c2df-4669-9a2c-584b47a0e4a8%7C032338e00e79b21248aaa07a19d3e44d%7C1594009812653%7C1%7C1594009810031; wp_fold=0; jebecookies=ba0612a2-0ce7-4a4d-95d1-1f71f38ee8ce|||||'
    }
url="http://www.renren.com/880151247/profile"
req = request.Request(url ,headers=headers)
resp = request.urlopen(req)
with open('result.html','w',encoding = 'utf-8') as f:
    f.writelines(resp.read().decode('utf-8'))

运行代码,会生成一个html文件,我们用浏览器打开它,发现结果如下:

这并不是我们想要的页面,然后将上面的代码中cookie部分取消注释,再运行,打开result.html:

可以看到出现了我们想要的页面!这就很好的体现出cookie的作用。

http.cookiejar模块

上面介绍了一种可行的方法,不过我写爬虫不就是为了提高效率嘛,你还每次让我手动去复制粘贴cookie信息?再想想,我们能通过请求获得状态码之类的网站信息,cookie也能用同样的方式获得呀,那不就完事了。这里我们的http.cookiejar模块就闪亮登场了,该模块主要的类有 CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar。这四个类的作用分别如下:

类名 描述
CookieJar 管理 HTTP cookie 值、存储 HTTP 请求生成的 cookie、向传出的 HTTP 请求添加 cookie 的对象。整个 cookie 都存储在内存中,对 CookieJar 实例进行垃圾回收后 cookie也将丢失。
FileCookieJar (filename,delayload=None,policy=None) 从 CookieJar 派生而来,用创建 FileCookieJar 实例,检索 cookie 信息并将 cookie 存储到文件中。filename 是存储cookie的文件名。delayload 为 True 时支持延迟访问访问文件,即只有在需要时才读取文件或在文件中存储数据。
MozillaCookieJar (filename,delayload=None,policy=None) 从 FileCookieJar 派生而来,创建与 Mozilla 浏览器 cookies.txt 兼容的 FileCookieJar 实例。
LWPCookieJar (filename,delayload=None,policy=None) 从 FileCookieJar 派生而来,创建与 libwww-perl 标准的 Set-Cookie3 文件格式兼容的 FileCookieJar 实例。

再用该模块实现访问人人网大鹏的主页:

from urllib import request,parse
from http.cookiejar import CookieJar

headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)\
         AppleWebKit/537.36 (KHTML, like Gecko) \
         Chrome/83.0.4103.116 Safari/537.36 Edg/83.0.478.58'
    }
#创造一个opener
def get_opener():
    cookjar=CookieJar()
    handler=request.HTTPCookieProcessor(cookjar)
    opener=request.build_opener(handler)
    return opener

#利用创造好的opener发送请求,请求返回的数据中就有cookie信息,他会保存到cookiejar类中
def save_cookie(opener):
    login_url="http://www.renren.com/PLogin.do"
    #账号密码不能泄露啊😂😂😂
    data={"email":"##########",
          'password':"##########"
        }
    res = request.Request(login_url,data= parse.urlencode(data).encode('utf8'),method='POST',headers=headers)
    opener.open(res)

#访问大鹏主页
def get_profile(opener):
    url="http://www.renren.com/880151247/profile"
    res=request.Request(url,headers=headers)
    resp=opener.open(res)
    with open('result2.html','w',encoding = 'utf-8') as f:
        f.writelines(resp.read().decode('utf-8'))

if __name__=='__main__':
    opener=get_opener()
    save_cookie(opener)
    get_profile(opener)

结果如下:

cookie的保存与加载

保存到本地

保存 cookie 到本地,可以使用 MozillaCookieJar 的 save 方法,并且需要指定一个文件名。这里我们再用http://httpbin.org这个网站来演示,该网站可以让我们自定义该网站的cookie信息,话不多说,先上图;
主页是这样的,先点击cookie选项:

跟着步骤来:

设置好后是这样:
如果想重新设置,可以先清除该网站的cookie数据哦,怎么清除点

from urllib import request,parse
from http.cookiejar import MozillaCookieJar

headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)\
         AppleWebKit/537.36 (KHTML, like Gecko) \
         Chrome/83.0.4103.116 Safari/537.36 Edg/83.0.478.58'
}
url="http://httpbin.org/cookies/set/python/spyder"
    
cookiejar=MozillaCookieJar()
handler=request.HTTPCookieProcessor(cookiejar)    
opener=request.build_opener(handler)
req=request.Request(url,headers=headers)
opener.open(req)
cookiejar.save('cookie.txt',ignore_discard=True,ignore_expires=True)
#由于该网站的cookie不会可能会过期或者被丢弃,所以这里得设置一下参数
#ignore_discard 的意思是即使 cookies 将被丢弃也将它保存下来
#ignore_expires 的意思是如果 cookies 已经过期也将它保存并且文件已存在时将覆盖
with open('cookie.txt','r') as f:
    print(f.read())

可以看到已经生成了cookie.txt文件,里边就存储着cookie信息,结果如下(出现这种格式应该是save方法的问题):

加载cookie信息

然后再来看看加载cookie信息,跟上边很类似:

headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)\
         AppleWebKit/537.36 (KHTML, like Gecko) \
         Chrome/83.0.4103.116 Safari/537.36 Edg/83.0.478.58'
}
url="http://httpbin.org/cookies"
cookiejar=MozillaCookieJar()
cookiejar.load('cookie.txt',ignore_discard=True,ignore_expires=True)
handler=request.HTTPCookieProcessor(cookiejar)    
opener=request.build_opener(handler)
req=request.Request(url,headers=headers)
resp=opener.open(req)
print(resp.read().decode())

输出:

Requests库

虽然 Python 的标准库中 urllib 模块已经包含了平常我们使用的大多数功能,但是它的 API使用起来让人感觉不太好,而 Requests 宣传是 “HTTP for Humans”,说明使用更简洁方便。接下来我们就用requests库来实现和urllib同样的功能

发送get请求

requests库发送get请求直接使用get方法即可,返回的是一个response对象,如果想添加 headers,可以传入 headers 参数来增加请求头中的 headers 信息。如果要将参数放在 url 中传递,可以利用params 参数

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/83.0.4103.116 Safari/537.36 Edg/83.0.478.58'
}
kw={'wd':'高考'}
# params 是一个字典或者字符串的查询参数,字典自动转换为 url 编码,不需要urlencode()
response = requests.get(url, params = kw, headers = hea
ders)
# 查看响应内容,response.text 返回的是 Unicode 格式的数据(python 会利用自己猜测的编码方式解码,可能会产生乱码的问题)
print(response.text)
# 查看响应头部字符编码
print(response.encoding)
# python 会根据网页内容来得到一个字符编码
print(response.apparent_encoding)
# 如果 response.text 乱码了,可以先设置
response.encoding= response.apparent_encoding
# 查看响应内容,response.content 返回的字节流 bytes 数据
print(response.content)
print(response.content .decode('utf-8'))
# 查看完整 url 地址
print(response.url)
# 查看响应码
print(response.status_code)
#如果网页返回的是 json,那么可以通过 response.json()转换为 dict 或者 list
print(response.json())

发送 POST 请求

最基本的 POST 请求可以使用 post 方法,传入 data 数据(这时候就不要再使用 urlencode 进行编码了,直接传入一个字典进去就可以了)。返回的也是response对象,可以进行的操作同上。比如请求拉勾网的数据的代码:

import requests

params = {'px': 'default',
          'city': '北京',
          'needAddtionalResult': 'false'}
data = {'first': 'true',
        'pn': 1,
        'kd': 'python'}
headers = {'Referer': "https://www.lagou.com/jobs/list_python",
           'Cookie': 'JSEIONID=ABAAABA9B2BCC46',
           'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
url = 'https://www.lagou.com/jobs/list_python#filterBox'
response = requests.post(url,
                         params=params,
                         headers=headers,
                         data=data,
                         timeout=5)
response.encoding = 'UTF-8'
print(response.text)

使用代理

使用 requests 添加代理也非常简单,只要在请求的方法中(比如 get 或者 post)传递 proxies参数即可(挂了科学上网软件的最好先关一下,我就因为没关被坑惨了):

import requests

url = 'http://www.httpbin.org/ip'
proxy = {
    'http': '161.35.110.112:3128'
}
resp_1 = requests.get(url, timeout=5)
print(resp_1.text)
resp_2 = requests.get(url, proxies=proxy, timeout=5)
print(resp_2.text)

输出如下:

使用requests.session保存cookie

之前使用 urllib 库,是可以使用 opener 发送多个请求,多个请求之间是可以共享 cookie 的。那么如果使用 requests,也要达到共享 cookie 的目的,那么可以使用 requests 库给我们提供的 session 对象。注意,这里的 session 不是 web 开发中的那个 session,这个地方只是一个会话的对象而已。还是以登录人人网为例,使用 requests 来实现。示例代码如下:

import requests

url = "http://www.renren.com/PLogin.do"
data = {"email": "970138074@qq.com", 'password': "pythonspider"}
headers = {
    'UserAgent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36"
}
# 登录
session = requests.session()
session.post(url, data=data, headers=headers)
# 访问大鹏个人中心
resp = session.get('http://www.renren.com/880151247/profile')
print(resp.status_code)
#输出:
200

总结一下

个人感觉使用方面确实requests库比起urllib的API接口要舒适许多,所以以后能用requests俺就不用urllib🤣🤣🤣


文章作者: Reset Ran
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Reset Ran !
  目录