(二)Requests
Requests概述:让 HTTP 服务人类
Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用。Requests库的优势 Requests 允许你发送纯天然,植物饲养的 HTTP/1.1 请求,无需手工劳动。你不需要手动为 URL 添加查询字串,也不需要对 POST 数据进行表单编码。Keep-alive 和 HTTP 连接池的功能是 100% 自动化的,一切动力都来自于根植在 Requests 内部的 urllib3。
为什么使用Requests库
- requests在python2 和python3中通用,方法完全一样,urllib2在python2和python3中的名称不同
- 工作中爬虫基本都使用requests
- 虽然Python的标准库中 urllib 模块已经包含了平常我们使用的大多数功能,但是它的 API 使用起来让人感觉不太好,而 Requests 自称 "HTTP for Humans",说明使用更简洁方便。requests 继承了urllib的所有特性,requests的底层实现就是urllib2。
- requests能够自动帮助我们解压(gzip压缩的等)网页内容,简单易用
- Requests支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的 URL 和 POST 数据自动编码。
- Requests库使用非常广泛,Twitter、Spotify、Microsoft、Amazon、Lyft、BuzzFeed、Reddit、NSA、女王殿下的政府、Amazon、Google、Twilio、Mozilla、Heroku、PayPal、NPR、Obama for America、Transifex、Native Instruments、Washington Post、Twitter、SoundCloud、Kippt、Readability、以及若干不愿公开身份的联邦政府机构都在内部使用。
文章图片
功能特性 Requests 完全满足今日 web 的需求:
- Keep-Alive & 连接池
- 国际化域名和 URL
- 带持久 Cookie 的会话
- 浏览器式的 SSL 认证
- 自动内容解码
- 基本/摘要式的身份认证
- 优雅的 key/value Cookie
- 自动解压
- Unicode 响应体
- HTTP(S) 代理支持
- 文件分块上传
- 流下载
- 连接超时
- 分块请求
- 支持 .netrc
- Requests 支持 Python 2.6—2.7以及3.3—3.7,而且能在 PyPy 下完美运行。
中文文档 API: http://docs.python-requests.org/zh_CN/latest/index.html
安装requests
$ pip install requests
基本GET请求(headers参数 和 parmas参数)
文章图片
最基本的GET请求可以直接用get方法
import requests
resp = requests.get('http://www.neuedu.com')
print(resp)
#
# 也可以这么写
response = requests.request("get", "http://www.neuedu.com")
print(response)
#
response.text 和response.content的区别
文章图片
import requests
url = 'http://www.baidu.com/'
r = requests.get(url)
# 查看响应内容 str类型
#r.text
r.encoding
'ISO-8859-1'
# 手动修改相应编码格式
r.encoding = 'utf-8'
r.encoding
'utf-8'
# 直接把相应数据改成utf-8
# r.content.decode()
# 获取响应头
r.headers
{'Accept-Ranges': 'bytes', 'Cache-Control': 'private, no-cache, no-store, proxy-revalidate, no-transform', 'Content-Length': '2381', 'Content-Type': 'text/html', 'Date': 'Mon, 17 Jun 2019 15:13:04 GMT', 'Etag': '"588604c4-94d"', 'Last-Modified': 'Mon, 23 Jan 2017 13:27:32 GMT', 'Pragma': 'no-cache', 'Server': 'ATS/8.0.3', 'Set-Cookie': 'BDORZ=27315;
max-age=86400;
domain=.baidu.com;
path=/', 'Age': '0', 'Connection': 'keep-alive'}
添加 headers 和 查询参数
为什么请求需要带上header?
模拟浏览器,欺骗服务器,获取和浏览器一致的内容
headers的形式:字典
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0;
Win64;
x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
# 用法:
requests.get(url,headers=headers)
发送带参数的请求 什么叫做请求参数:
列1: http://www.webkaka.com/tutorial/server/2015/021013/ 不是
例2: https://www.baidu.com/s?wd=python&c=b 是
import requestskw = {'wd':'东软'}headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0;
Win64;
x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}# params 接收一个字典或者字符串的查询参数,字典类型自动转换为url编码,不需要urlencode()
response = requests.get("http://www.baidu.com/s?", params=kw, headers = headers)# 查看响应内容,response.text 返回的是Unicode格式的数据
print(response.text)
# 查看响应内容,response.content返回的字节流数据
print(response.content)# 查看完整url地址
print(response.url)# 查看响应头部字符编码
print(response.encoding)# 查看响应码
print(response.status_code)
没有添加请求头的知乎网站
import requests
url = 'https://www.zhihu.com'
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0;
Win64;
x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
r = requests.get(url)
r.status_code
400
r = requests.get(url,headers= headers)
r.status_code
200
案例:百度贴吧的爬取
- 获取指定页数
- 将贴吧保存成文件
参考代码:
import requests"""
目标:
爬取百度贴吧页面:
1、构造url
2、构造请求头
3、发送请求
4、保存数据"""
class Baidu(object):def __init__(self,name,pn):
# 保存传入的贴吧名称
self.name = name
self.url = 'https://tieba.baidu.com/f?kw={}&ie=utf-8&pn='.format(name)
self.headers = {
"User-Agent": "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
}
# 构造url列表,拼接的页数
self.url_list = [self.url + str(pn*50) for pn in range(pn)]
print(self.url_list)# 发送请求获取数据,需要修改传入的url
def get_data(self,url):
response = requests.get(url,headers=self.headers)
return response.content# 保存数据
def save_data(self,data,num):
# 构造保存数据的文件名称
file_name = self.name + '_' + str(num) + '.html'
with open(file_name,'wb') as f:
f.write(data)# 执行方法
def run(self):
# 遍历url列表
for url in self.url_list:
# print (url)
# 调用发送请求的方法,获取数据
data = https://www.it610.com/article/self.get_data(url)
# 获取self.url_list索引值
num = self.url_list.index(url)
# 调用保存数据的方法
self.save_data(data,num)
import sysif __name__ =='__main__':
# 传入参数,贴吧名称,页数
name = sys.argv[1]
pn = int(sys.argv[2])
# print(type(name))
# print(type(pn))
# print(name,pn)
baidu = Baidu(name,pn)
baidu.run()
在终端运行如下命令:
python3 spider_tieba.py 李毅 3
本地会生成3个html文件哦
文章图片
Requests高阶(POST) 发送POST请求
哪些地方我们会用到POST请求:
- 登录注册( POST 比 GET 更安全)绝大多数的登录会使用post请求,极少数网站仍然在使用get请求进行登录
- 向服务器传输的数据量比较多的时候,或者向服务器传输大文件
- 所以同样的,我们的爬虫也需要在这两个地方回去模拟浏览器发送post请求
response = requests.post(url, data = https://www.it610.com/article/data, headers=headers)
# data 的形式:字典
案例:访问金山词霸在线翻译,获取翻译结果
网址:http://fy.iciba.com/
需求
1、构造url
2、请求头
3、构造请求体
4、发送请求,输出数据
如下如是浏览器的演示效果,接下来我们要用python代买去实现这一功能
文章图片
注释:
- 1.XHR:筛选使用Ajax请求的network(ajax技术的核心是XMLHttpRequest对象(简称XHR),这是由微软首先引入的一个特性,其他浏览器提供商后来都提供了相同的实现。XHR为向服务器发送请求和解析服务器响应提供了流畅的接口,能够以异步方式从服务器取得更多信息,意味着用户单击后,可以不必刷新页面也能取得新数据)
- 2.当左侧输入框发生 变化就会触发Ajax请求事件
-
- Form Data就是post请求的表单数据
参考代码:
- Form Data就是post请求的表单数据
import requests
import jsonclass JinShan(object):def __init__(self,word):
self.url = 'http://fy.iciba.com/ajax.php?a=fy'
self.headers = {
"User-Agent": "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
}
# 构造请求的参数
self.post_data = https://www.it610.com/article/{"f": "auto",
"t": "auto",
"w": word
}
# 发送请求
def request_post(self):
response = requests.post(url=self.url,headers=self.headers,data=https://www.it610.com/article/self.post_data)
# print(response.content.decode())
return response.content.decode()# 解析数据
def parse_data(self,data):
# 把响应数据转成字典
dict_data = json.loads(data)
# 判断out键是否存在,不能判断一个字符串是否在字典的索引
# if'out' in data:
#content = (dict_data['content']['out'])
# else:
#content = (dict_data['content']['word_mean'][0])
# 进行异常处理
try:
content = (dict_data['content']['out'])
except:
content = (dict_data['content']['word_mean'][0])
print (content)def run(self):
# 调用发送请求,并获取数据
data = https://www.it610.com/article/self.request_post()
# 调用解析数据方法
self.parse_data(data)if __name__ =='__main__':
import sys
word = sys.argv[1]
jinshan = JinShan(word)
jinshan.run()
在终端运行命令之后会有下面的效果
文章图片
使用IP代理爬虫 IP代理既代理服务器,其功能主要就是代理网络用户去获取网络信息,形象的说就是网络信息的中转站
为什么爬虫需要使用代理?
- 让目标服务器以为不是同一个客户端在请求,放置因为ip发送请求过多而被反爬
- 防止我们的真实地址被泄露,防止被追究
文章图片
文章图片
使用免费代理网站,比如快代理 https://www.kuaidaili.com/free/找到免费的ip
文章图片
下面是使用代理的示例代码:
import requests# 使用代理
url = 'http://www.baidu.com/'# 免费代理
proxies = {
'http':'http://115.210.24.183:9000',
'https':'https://183.129.207.86:14002'
}
# # 付费代理,用户名:密码@ip和port
# proxies = {
#'http':'http://user:pwd@115.223.200.85:9000'
# }response = requests.get(url,proxies=proxies)
print(response.text)
cookie和session 本质上都是基于键值对的字符串
两者区别:
- cookie数据存放在客户的浏览器上,session数据放在服务器上
- cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗(使用用户的cookies获取相关信息
- session会在一定时间内保存在服务器上。当访问增多,会比较占用服务器的性能
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
- 带上cookie、session的好处:很多网站必须登录之后(或者获取某种权限之后)才能能够请求到相关数据
- 带上cookie、session的弊端:一套cookie和session往往和一个用户对应.请求太快,请求次数太多,容易被服务器识别为爬虫。从而是账号收到损害
- 使用建议
1.不需要cookie的时候尽量不去使用cookie
2.为了获取登录之后的页面,我们必须发送带有cookies的请求,此时为了确保账号安全应该尽量降低数据采集速度
首先浏览器登录人人网,然后打开调试模式,复制url和cookie
文章图片
参考代码如下:
import requests
import re
"""
使用cookie进行模拟登录
1、首先使用浏览器登录网站
2、获取cookie信息
3、保存cookie信息放到请求头中"""
# 登录后用户信息页
url = 'http://www.renren.com/971209342'# 保存cookie信息
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Cookie": "anonymid=jx19bd0l-4r5q5y;
JSESSIONID=abcsD77Gb0el7fJktQOTw;
depovince=GW;
_r01_=1;
ick_login=19787144-5838-490f-b599-34a22b58aa7c;
t=06700184d453813c5b594f40b29cd9412;
societyguester=06700184d453813c5b594f40b29cd9412;
id=971209342;
xnsid=974c659d;
jebecookies=7b441396-b2be-4c75-ac03-4466a9fc763f|||||;
ver=7.0;
loginfrom=null"
}# 发送请
response = requests.get(url, headers=headers)# 获取响应,并且解码成str,使用正则获取响应中的字符串
print(re.findall('关注内容', response.content.decode()))
print(response.status_code)
输出结果如下:
['关注内容']
200
Cookies 和 session
如果一个响应中包含了cookie,那么我们可以利用 cookies参数拿到
import requestsurl = 'http://www.baidu.com'
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
}# 设置请求的超时时间,单位是s
# response = requests.get(url,timeout=3)response = requests.get(url, headers=headers)
# 获取cookie信息
print(response.cookies)# 把cookie转成字典
content = requests.utils.dict_from_cookiejar(response.cookies)
print(content)
# 将cookie字典转成对象
c = requests.utils.cookiejar_from_dict(content)
print(c)
运行结果:
, , , ]>
{'H_PS_PSSID': '1443_21123_29135_29237_29098_29369_28832_29220_26350', 'delPer': '0', 'BDSVRTM': '0', 'BD_HOME': '0'}
, , , ]>
使用session实现人人网登录 在 requests 里,session对象是一个非常常用的对象,这个对象代表一次用户会话:从客户端浏览器连接服务器开始,到客户端浏览器与服务器断开。
【(二)Requests】会话能让我们在跨请求时候保持某些参数,比如在同一个 Session 实例发出的所有请求之间保持 cookie
import requests
import reurl = 'http://www.renren.com/PLogin.do'# 保存cookie信息
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
}# 构造session回话对象
session = requests.session()# 构造post请求data数据
data = https://www.it610.com/article/{'email':'1900000000',
'password':'neuedu'
}
# 发送post请求
session.post(url,headers=headers,data=https://www.it610.com/article/data)# 验证登录是否成功
response = session.get('http://www.renren.com/963112933')##打印响应内容
print(response.text)
推荐阅读
- EffectiveObjective-C2.0|EffectiveObjective-C2.0 笔记 - 第二部分
- 遇到一哭二闹三打滚的孩子,怎么办┃山伯教育
- 赢在人生六项精进二阶Day3复盘
- 2019年12月24日
- 陇上秋二|陇上秋二 罗敷媚
- 一百二十三夜,请嫁给我
- 迷失的世界(二十七)
- 我要我们在一起(二)
- 基于|基于 antd 风格的 element-table + pagination 的二次封装
- (二)ES6第一节变量(let|(二)ES6第一节变量(let,const)