爬虫(二):requests模块 ---get和post方法,cookie和session,代理

一、requests模块的使用步骤

# 1、导包
import requests
# 2、确定基础url
base_url = 'https://www.baidu.com/'
# 3、发送请求,获取响应
response = requests.get(base_url)
# 4、处理响应内容

二、requests中的get方法

requests.get(
    url = '请求url',
    headers = {}, # 请求头
    params = {}, # 请求参数,get方法中的请求参数拼接在url中
    timeout = 超时时长,
)

requests模块的get方法,返回一个response对象


1、response对象

服务器响应包含:状态行(协议,状态码)、响应头、空行、响应正文。

(1)响应正文
字符串格式:response.text
bytes类型:response.content
(2)状态码
response.status_code
(3)响应头
response.headers  --字典
# 获取响应头中的cookie
response.headers['cookie']
(4)响应正文的编码
response.encoding

# response.text获取到的字符串类型的响应正文,其实是通过下面的步骤获取的
response.encoding = response.content.decode()
(5)乱码问题的解决办法

产生的原因:编码和解码的编码格式不一致造成的。

str.encode()  # 将字符串解码成bytes类型
bytes.decode()  # 将bytes类型编码成字符串

第一种方法:

response.content.decode('页面正确的编码格式')

第二种方法:找到正确的编码,设置到 response.encoding

response.encoding = '正确的编码'
response.text ---> 正确的页面内容

2、get 方法举例

案例一:爬取百度首页

https://www.baidu.com/

# 1、导包
import requests
# 2、确定基础url
base_url = 'https://www.baidu.com/'
# 封装请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
# 3、发送请求,获取响应
response = requests.get(base_url,headers=headers)
# 解决乱码问题的第一种方法
# response.encoding = 'utf-8'
# 4、处理响应
with open('baidu.html','w',encoding='utf-8') as fp:
    # fp.write(response.text)
    # 解决乱码问题的第二种方法
    fp.write(response.content.decode('utf-8'))

案例二:爬取新浪新闻

输入 国产航母 ,分析检查返回的页面,如下图所示:

在这里插入图片描述


在这里插入图片描述

图 2-1 返回的页面

请求的是:https://search.sina.com.cn/?q=%E5%9B%BD%E4%BA%A7%E8%88%AA%E6%AF%8D&c=news&from=channel&ie=utf-8

请求方法是:get请求。

请求参数:有四个,其中一个参数是中文,请求的时候需要编码。

爬取代码示例:

# get请求,携带请求参数

# 1、导包
import requests
# 2、确定基础url
# 带请求参数的基础url,就是?以前包括问号
base_url = 'https://search.sina.com.cn/?'
# 封装请求头
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
# 请求参数
kw = '国产航母'
params = {
    'q': kw,
    'c': 'news',
    'from': 'channel',
    'ie': 'utf-8'
}
# 3、发送请求,获取响应
response = requests.get(base_url,headers=headers,params=params)
# 4、处理响应
# 右击-->检查  查看页面源代码
# <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
with open('sina_new.html','w',encoding='gbk') as fp:
    fp.write(response.content.decode('gbk'))
案例三:爬取百度贴吧

百度贴吧,搜索 python,利用get方法做分页

第一页:https://tieba.baidu.com/f?kw=%E7%8E%8B%E8%80%85&ie=utf-8&pn=0

第二页:https://tieba.baidu.com/f?kw=%E7%8E%8B%E8%80%85&ie=utf-8&pn=50

第三页:https://tieba.baidu.com/f?kw=%E7%8E%8B%E8%80%85&ie=utf-8&pn=100

寻找每个页面url中不同的地方,就是url最后的pn值不同

爬取代码示例:

# get方法 如何做分页
# 1、导包
import requests
import os

# 2、确定基础url
base_url = 'http://tieba.baidu.com/f?'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
kw = '王者吧'
filename = './tieba/' + kw
dirname = os.path.dirname(filename)
# print(dirname)
# 不存在就创建文件夹
if not os.path.exists(dirname):
    os.mkdir(dirname)
    if not os.path.exists(filename):
        os.mkdir(filename)
# 分页
for i in range(10):
    params = {
        'kw': kw,
        'ie': 'utf-8',
        'pn': str(i * 50),
    }
    # 3、发送请求,获取响应
    response = requests.get(base_url,headers=headers,params=params)
    # 4、处理响应
    with open(filename + '/{}.html'.format(i + 1),'w',encoding='utf-8') as fp:
        fp.write(response.text)
案例四:爬取百度搜索

百度首页,输入 python爬虫,爬取返回的页面

爬取代码示例:

# 1、导包
import requests

# 2、确定基础url
base_url = 'https://www.baidu.com/s?'
# 请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
kw = 'python爬虫'
# 请求参数
params = {
    'wd': kw,
    'rsv_spt': '1',
    'rsv_iqid': '0xe2c14bcf0009669a',
    'issp': '1',
    'f': '8',
    'rsv_bp': '1',
    'rsv_idx': '2',
    'ie': 'utf-8',
    'tn': 'baiduhome_pg',
    'rsv_enter': '1',
    'rsv_dl': 'tb',
    'rsv_sug3': '15',
    'rsv_sug1': '9',
    'rsv_sug7': '100',
    'rsv_sug2': '0',
    'inputT': '4062',
    'rsv_sug4': '4672',
}

# 3、发送请求,获取响应
response = requests.get(base_url,headers=headers,params=params)
# 4、处理响应
with open('{}.html'.format(kw),'w',encoding='utf-8') as fp:
    fp.write(response.content.decode('utf-8'))

3、get请求总结

  1. 没有请求参数的情况下,只需要确定url和headers请求头。
  2. 有请求参数的情况下,右击–检查,找 query_string_params ,将里面的参数封装在params中。
  3. 分页主要是查看每页中,请求参数页码字段的变化,找到变化规律,用for循环就可以做到分页。

三、requests中的post方法

response = requests.post(
    url = '基础url',
    headers = {}, # 请求头
    data = {}, # 请求数据,post请求的请求数据放在请求实体中
    timeout = 超时时长,
)

requests模块的post方法,返回一个response对象.。

post请求一般返回数据都是json数据。

1、如何解析json数据

第一种方法:

  用response对象的json()方法,返回的是json字符串所对应的python的list或者dict

response.json() # 返回python的list或者dict

第二种方法:用json模块。

json.loads(json字符串) # 返回python的list或者dict
json.dumps(python的list或者dict) # 返回json字符串

2、post方法举例

案例一:重写百度翻译
  1. 浏览器打开:fanyi.baidu.com
  2. F12—Network
  3. 输入job(在输入过程中会不断请求服务器),例如输入"j"时请求,输入"jo"时请求,输入"job"时也在请求。
  4. 同时获取请求。

在这里插入图片描述

图 2-2 服务器请求

url:https://fanyi.baidu.com/sug

请求方式:POST

请求数据:job

代码示例:

# 1、导包
import requests,json
# 2、基础url
base_url = 'https://fanyi.baidu.com/sug'
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest'
}
kw = 'job'
data = {
    'kw': kw
}
# 3、发送请求,获取响应
response = requests.post(base_url,headers=headers,data=data)
# print(response.text)  # json字符串
# print(response.json(),type(response.json()))
# 解析json的第一种方法
# json_data = response.json()
# 解析json的第二种方法 ---用json模块
json_data = json.loads(response.text)
result = ''
for data in json_data['data']:
    result += data['v'] + '\n'
print(result)
案例二:浅尝有道词典翻译

有道翻译网址:http://fanyi.youdao.com/

在翻译中输入python

在这里插入图片描述

图 2-3 分析接口与请求方式

找到接口和请求的方式,如图 2-3 :

在这里插入图片描述

图 2-4 参数类型为Form Data

代码实现:

import requests

base_url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
    'Content-Length': '239',
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'Cookie': 'OUTFOX_SEARCH_USER_ID_NCOO=515894077.54851353; OUTFOX_SEARCH_USER_ID="1063309913@10.108.160.17"; _ga=GA1.2.948183379.1577080175; JSESSIONID=aaadp5J-1dw47eLlC60-w; ___rl__test__cookies=1580365311867',
    'Referer': 'http://fanyi.youdao.com/'
}
kw = 'work'
data = {
    'i': kw,
    'from': 'AUTO',
    'to': 'AUTO',
    'smartresult': 'dict',
    'client': 'fanyideskweb',
    'salt': '15803653118740',
    'sign': '8ec9fd2c8fe99a4f6969753839f60e5a',
    'ts': '1580365311874',
    'bv': '42160534cfa82a6884077598362bbc9d',
    'doctype': 'json',
    'version': '2.1',
    'keyfrom': 'fanyi.web',
    'action': 'FY_BY_REALTlME'
}
response = requests.post(base_url,headers=headers,data=data)
print(response.text)
运行结果:
{"errorCode":50}

Process finished with exit code 0

我们发现,当 kw='python' 时,能够获取到翻译的结果;当我们改变 kw的值时,上述代码并不能获取到翻译的结果。

案例三:深入有道词典

那么怎么解决上个案例中的问题呢?

Form Data 中的参数中,我们看到 salt,sign,ts,这是添加数字签名的标记。也就是这三个参数的值是生成出来的,也就是说随着翻译内容的不同,这三个值可能是会变化的。像这种动态生成的值一般会写在js脚本文件中。

(1)查找对应的js文件,如图 2-5 :

在这里插入图片描述

图 2-5 对应的js文件

(2)查看这个文件

复制Response中的内容,打开在线格式化代码,复制格式化之后的js代码,如图 2-6:
在这里插入图片描述

图 2-6 查看js文件内容

为了方便查看,我们在新建一个js文件,并且搜索与salt等变化的参数相关的字符,如图 2-7 所示:
在这里插入图片描述

图 2-7 找到相关内容

(3)生成 salt 内容

其中 (new Date).getTime() 这行语句我们可以在浏览器中的控制台上输出看一下,如图 2-8 :
在这里插入图片描述

图 2-8 验证内容

可见是精确到毫秒的时间戳,(用同样的方式验证:parseInt(10 * Math.random(), 10)),我们可以在 python输出一个时间,两者做个对比
在这里插入图片描述

图 2-9 验证对比值

js中时间戳是以毫秒计算的,而python中的时间戳是以秒计算的。

所以在这个JS中生成的 salt 值
在这里插入图片描述
在python中可以这样生成:

import time
import random

salt = str(time.time()*1000 + random.randint(0,10))

(4)生成 ts 内容

JS 中生成的 ts:

ts = "" + (new Date).getTime()

python 中生成的 ts :

ts = str(time.time()*1000)

(5)生成 sign 内容
在这里插入图片描述
JS 中生成的 sign 值:

sign = n.md5("fanyideskweb" + kw + salt + "n%A-rKaT5fb[Gy?;N5@Tj")

python 中生成的 sign 值:

def get_md5(value):
    md5 = hashlib.md5()
    md5.update(value.encode('utf-8'))
    result = md5.hexdigest()
    return result
value = "fanyideskweb" + kw + salt + "n%A-rKaT5fb[Gy?;N5@Tj"
sign = get_md5(value)

代码实现:

# 有道翻译

import hashlib
import json
import random
import time

import requests

base_url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
    'Content-Length': '239',
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'Cookie': 'OUTFOX_SEARCH_USER_ID_NCOO=515894077.54851353; OUTFOX_SEARCH_USER_ID="1063309913@10.108.160.17"; _ga=GA1.2.948183379.1577080175; JSESSIONID=aaadp5J-1dw47eLlC60-w; ___rl__test__cookies=1580365311867',
    'Referer': 'http://fanyi.youdao.com/'
}

kw = 'work'
salt = str(time.time()*1000 + random.randint(0,10))
ts = str(time.time()*1000)
def get_md5(value):
    md5 = hashlib.md5()
    md5.update(value.encode('utf-8'))
    result = md5.hexdigest()
    return result
value = "fanyideskweb" + kw + salt + "n%A-rKaT5fb[Gy?;N5@Tj"
sign = get_md5(value)
data = {
    'i': kw,
    'from': 'AUTO',
    'to': 'AUTO',
    'smartresult': 'dict',
    'client': 'fanyideskweb',
    'salt': salt,
    'sign': sign,
    'ts': ts,
    'bv': '42160534cfa82a6884077598362bbc9d',
    'doctype': 'json',
    'version': '2.1',
    'keyfrom': 'fanyi.web',
    'action': 'FY_BY_REALTlME'
}
response = requests.post(base_url,headers=headers,data=data)
# print(response.text)
# 解析json数据
json_data = json.loads(response.text) # 字典类型
result = ''
# 提取翻译后的结果
for data in json_data['smartResult']['entries']:
    result += data
print(result)

运行结果:
n. 工作;功;产品;操作;职业;行为;事业;工厂;著作;文学、音乐或艺术作品
vt. 使工作;操作;经营;使缓慢前进
vi. 工作;运作;起作用

Process finished with exit code 0

3、post 方法总结

post 请求能否成功,关键看请求参数。

如何查找是那个请求参数在影响数据获取?

通过对比,找到变化的参数。

找到参数的生成方式,就是解决这个 ajax 请求数据获取的途径。

寻找的办法有以下几种:

  1. 写死在页面。
  2. 写在 js 中
  3. 请求参数是在之前的一条 ajax 请求的数据里面提前获取好的。

四、cookie和session

1、什么是cookie

  cookie 是指网站为了鉴别用户身份,进行会话跟踪而存储在客户端本地的数据。

2、什么是session

  本来的含义是指有始有终的一系列动作,而在web中,session对象用来在服务器存储特定用户会话所需要的属性及信息。

3、cookie和session产生的原因

  cookie 和 session 它们不属于 http 协议范围,由于 http 协议是无法保持状态的,但实际情况,我们又需要保持一些信息,作为下次请求的条件,所以就产生了 cookie 和 session。

4、cookie的原理

  cookie是由服务器产生的,当浏览器第一次登录,发送请求给服务器,服务器返回数据,同时生成一个cookie返回给客户端,客户端将这个cookie保存下来。

  当浏览器再次访问时,会自动携带cookie信息,这样服务器就能通过cookie判断是哪个用户在操作。

cookie的缺陷:

  1. 不安全 — 保存在客户端
  2. cookie本身最大支持4096(4kb)— 存储大小受限

5、session的工作原理

正是因为cookie的缺陷,所以产生了另外一种保持状态的机制。—session

  服务器存储session,基于http协议的无状态特征,所以服务器就不知道这个访问者是谁。为了解决这个问题,cookie就起到了桥的作用。cookie在使用的过程中,将一个叫作sessionid 的字段放到cookie中,将来服务器就可以通过这个字段来查找到底是哪个用户的session。

session的生命周期:当用户第一次登录时创建(生命开始),到session有效期结束。

6、当我们浏览器关闭,session是否就失效了?

不失效。原因:session失效是由生命周期决定的。

7、cookie的组成

namecookie名称,一旦创建,不可修改
valuecookie的值
domain可以访问的网站域名
maxage过期时间。负数是永不失效。
pathcookie的使用路径
httponly若此属性为true,则只有http头中会携带此cookie
sizecookie的大小
secure是否仅被使用安全传输协议。

8、会话cookie和持久cookie

持久化:将内存中的数据存储到硬盘上的过程。
序列化:将对象保存到硬盘上。

  • 会话cookie:保存在内存中的cookie,浏览器关闭,cookie失效。
  • 持久cookie:保存在硬盘上的cookie。

9、用requests模块实现登录

(1)只需要将【登录后的】cookie字段封装在请求头中。
(2)使用 requests 的 session 对象登录。
  session对象可以记录登录状态。

案例:实现人人网登录

第一种:在请求头中封装用户的cookie信息

# 实现人人网登录

import requests

base_url = 'http://www.renren.com/908944115/profile'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
    'Cookie': '用户登录后的cookie信息'
}
response = requests.get(base_url,headers=headers)
if '用户头像旁边的用户昵称' in response.text:
    print('登录成功!')
else:
    print('登录失败!')

第二种:使用requests的session对象

import requests
base_url = 'http://www.renren.com/PLogin.do'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
    'Referer': 'http://www.renren.com/908944115/newsfeed/photo'
}
# session 记录登录状态
# 实例化一个session对象
se = requests.Session()
data = {
    'email':'用户名',
    'password':'密码'
}
# 此时se对象就保存了登录信息
# form表单提交用户名和密码
se.post(base_url,headers=headers,data=data)
index_url = 'http://www.renren.com/908944115/profile'
# 发送请求,获取响应
response = se.get(index_url,headers=headers)
if '用户头像旁边的用户昵称' in response.text:
    print('登录成功!')
else:
    print('登录失败!')

五、代理

1、代理的基本原理

代理形象的说,他是网络信息的中转站。实际上就是在本机和服务器之间架了一座桥。

2、代理的作用

  • 突破自身 ip访问限制,访问一些平时不能访问的站点。
  • 访问一些单位或团体内部资源。
  • 提高访问速度。代理服务器的主要作用就是中转,所以一般代理服务器里面都是用内存来进行数据存储的。
  • 隐藏 ip。对于爬虫来说,我们用代理就是为了隐藏自身 IP,防止自身的 IP被封锁。

3、代理的分类

代理分类时,既可以根据协议区分,也可以根据其匿名程度区分。

  1. 根据协议区分
    1. FTP代理服务器:一般有上传、下载以及缓存功能,端口一般为 21、2121。
    2. HTTP代理服务器:主要用于访问网页,一般有内容过滤和缓存功能,端口一般为 80,8080。
    3. SSL/TLS代理:主要用于访问加密网站,一般有SSL或TLS加密功能(最高支持 128 位加密强度),端口一般为 443。
    4. Telnet代理:主要用于 telnet远程控制(黑客入侵计算机时常用于隐藏身份),端口一般为 23。
  2. 根据匿名程度区分
    1. 高度匿名代理:数据包会原封不动转化,在服务端看来,就好像一个普通用户在访问,做到完全隐藏 IP。
    2. 普通匿名代理:数据包会做一些改动,服务器有可能找到原 IP。
    3. 透明代理:不但改动数据,还会告诉服务器,是哪个用户访问的。
    4. 间谍代理:指组织或者个人用于记录用户传输的数据,然后进行研究、监控等目的的代理。

4、在requests模块中设置代理

proxies = {
    '代理服务器的类型':'代理ip'
}
response = requests.get(proxies = proxies)

代理服务器的类型:http,https,ftp

代理 ip:http://ip:port


作业:

1、股吧信息爬取

url:http://guba.eastmoney.com/

要求:爬取10页内容,保存到 guba文件夹下

2、金山词霸

url:http://www.iciba.com/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值