一、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请求总结
- 没有请求参数的情况下,只需要确定url和headers请求头。
- 有请求参数的情况下,右击–检查,找
query_string_params
,将里面的参数封装在params中。 - 分页主要是查看每页中,请求参数页码字段的变化,找到变化规律,用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方法举例
案例一:重写百度翻译
- 浏览器打开:fanyi.baidu.com
- F12—Network
- 输入job(在输入过程中会不断请求服务器),例如输入"j"时请求,输入"jo"时请求,输入"job"时也在请求。
- 同时获取请求。
图 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 请求数据获取的途径。
寻找的办法有以下几种:
- 写死在页面。
- 写在 js 中。
- 请求参数是在之前的一条 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的缺陷:
- 不安全 — 保存在客户端
- cookie本身最大支持4096(4kb)— 存储大小受限
5、session的工作原理
正是因为cookie的缺陷,所以产生了另外一种保持状态的机制。—session
服务器存储session,基于http协议的无状态特征,所以服务器就不知道这个访问者是谁。为了解决这个问题,cookie就起到了桥的作用。cookie在使用的过程中,将一个叫作sessionid
的字段放到cookie中,将来服务器就可以通过这个字段来查找到底是哪个用户的session。
session的生命周期:当用户第一次登录时创建(生命开始),到session有效期结束。
6、当我们浏览器关闭,session是否就失效了?
不失效。原因:session失效是由生命周期决定的。
7、cookie的组成
name | cookie名称,一旦创建,不可修改 |
---|---|
value | cookie的值 |
domain | 可以访问的网站域名 |
maxage | 过期时间。负数是永不失效。 |
path | cookie的使用路径 |
httponly | 若此属性为true,则只有http头中会携带此cookie |
size | cookie的大小 |
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、代理的分类
代理分类时,既可以根据协议区分,也可以根据其匿名程度区分。
- 根据协议区分
- FTP代理服务器:一般有上传、下载以及缓存功能,端口一般为 21、2121。
- HTTP代理服务器:主要用于访问网页,一般有内容过滤和缓存功能,端口一般为 80,8080。
- SSL/TLS代理:主要用于访问加密网站,一般有SSL或TLS加密功能(最高支持 128 位加密强度),端口一般为 443。
- Telnet代理:主要用于 telnet远程控制(黑客入侵计算机时常用于隐藏身份),端口一般为 23。
- 根据匿名程度区分
- 高度匿名代理:数据包会原封不动转化,在服务端看来,就好像一个普通用户在访问,做到完全隐藏 IP。
- 普通匿名代理:数据包会做一些改动,服务器有可能找到原 IP。
- 透明代理:不但改动数据,还会告诉服务器,是哪个用户访问的。
- 间谍代理:指组织或者个人用于记录用户传输的数据,然后进行研究、监控等目的的代理。
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/